hackedteam/shshget

View on GitHub
shshget.rb

Summary

Maintainability
A
3 hrs
Test Coverage
#!/usr/bin/env ruby

#
# Jan 3 2012
#
# Pretty hackish
# Will make at least 3 requests every 8 hours
# Needs a bit of cleaning and some heavy testing on all
# the different kind of idevices
#
# Whenever there's a new device, add it to devices.yaml
#
# rev
#

require 'net/http'
require 'objspace'
require 'plist'
require 'psych'
require 'cgi'
require 'logger'

def log(level, msg)
  log_file = "shsh.log"
  log = Logger.new(File.open(log_file, "a+"))
  log.level = Logger::DEBUG
  log.send(level, msg)
  log.close
end

def build_plist_for_manifest(manifest, ecid)
  obj = {}
  obj['@APTicket'] = true
  obj['@BBTicket'] = true
  obj['ApNonce'] = 'MTAwMQ==' # 1001 base64
  obj['@HostIpAddress'] = '192.168.0.1'
  obj['@HostPlatformInfo'] = 'mac'
  obj['@Locality'] = 'en_US'
  obj['@VersionInfo'] = 'libauthinstall-68.1'
  obj['ApBoardID'] = manifest["BuildIdentities"][0]["ApBoardID"]
  obj['ApChipID'] = manifest["BuildIdentities"][0]["ApChipID"]
  obj['ApECID'] = ecid
  obj['ApProductionMode'] = true
  obj['ApSecurityDomain'] = 1
  obj['UniqueBuildID'] = manifest["BuildIdentities"][0]["UniqueBuildID"]
  #obj['UniqueBuildID'] = 'bZ/+6gi44GhO84bgFlIkxw0V+d8='

  t = manifest["BuildIdentities"][0]["Manifest"]["AppleLogo"]
  t.delete("Info")
  obj['AppleLogo'] = t

  #t = manifest["BuildIdentities"][0]["Manifest"]["BasebandFirmware"]
  #t.delete("Info")
  #obj['BasebandFirmware'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryCharging"]
  t.delete("Info")
  obj['BatteryCharging'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryCharging0"]
  t.delete("Info")
  obj['BatteryCharging0'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryCharging1"]
  t.delete("Info")
  obj['BatteryCharging1'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryFull"]
  t.delete("Info")
  obj['BatteryFull'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryLow0"]
  t.delete("Info")
  obj['BatteryLow0'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryLow1"]
  t.delete("Info")
  obj['BatteryLow1'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["BatteryPlugin"]
  t.delete("Info")
  obj['BatteryPlugin'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["DeviceTree"]
  t.delete("Info")
  obj['DeviceTree'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["KernelCache"]
  t.delete("Info")
  obj['KernelCache'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["LLB"]
  t.delete("Info")
  obj['LLB'] = t

  #t = manifest["BuildIdentities"][0]["Manifest"]["NeedService"]
  #t.delete("Info")
  #obj['NeedService'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["RecoveryMode"]
  t.delete("Info")
  obj['RecoveryMode'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["RestoreDeviceTree"]
  t.delete("Info")
  obj['RestoreDeviceTree'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["RestoreKernelCache"]
  t.delete("Info")
  obj['RestoreKernelCache'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["RestoreLogo"]
  t.delete("Info")
  obj['RestoreLogo'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["RestoreRamDisk"]
  t.delete("Info")
  obj['RestoreRamDisk'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["iBEC"]
  t.delete("Info")
  obj['iBEC'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["iBSS"]
  t.delete("Info")
  obj['iBSS'] = t

  t = manifest["BuildIdentities"][0]["Manifest"]["iBoot"]
  t.delete("Info")
  obj['iBoot'] = t

  # serialize
  plist = obj.to_plist
  plist_data = plist.dump.gsub("\"<", "<").gsub("\\n\"", "").gsub("\\n", "\n").gsub("\\t", "\t").gsub("\\", "")

  return plist_data
end

def request_shsh(plist_data)
  uri = URI('http://gs.apple.com.akadns.net/TSS/controller?action=2')

  req = Net::HTTP::Post.new(uri.request_uri)
  req["Accept"] = "*/*"
  req["Cache-Control"] = "no-cache"
  req["Content-type"] = "text/xml; charset=\"utf-8\""
  req["User-Agent"] = "InetURL/1.0"
  req["Host"] = "gs.apple.com.akadns.net"
  req["Content-Length"] = plist_data.bytesize
  req.body = plist_data

  res = Net::HTTP.start('gs.apple.com.akadns.net', '80') { |http|
    http.request(req)
  }

  return res.response
end

def check_latest_ios(phone_ver, build_ver)
  uri = URI('http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStore.woa/wa/com.apple.jingle.appserver.client.MZITunesClientCheck/version')
  res = Net::HTTP.get(uri)
  versions = Plist::parse_xml(res)

  ver = ""

  v = versions['MobileDeviceSoftwareVersionsByVersion']['9']['MobileDeviceSoftwareVersions'][phone_ver][build_ver]
  if v.has_key?("SameAs")
    bid = v["SameAs"]
    ver = versions['MobileDeviceSoftwareVersionsByVersion']['9']['MobileDeviceSoftwareVersions'][phone_ver][bid]['Restore']['ProductVersion']
  else
    ver = versions['MobileDeviceSoftwareVersionsByVersion']['9']['MobileDeviceSoftwareVersions'][phone_ver][build_ver]['Restore']['ProductVersion']
  end

  entry = (phone_ver + "(" + build_ver + ") last ver: " + ver)
  log(:info, entry)
  return ver
end

manifest_dir = "manifests/"
ecid_dir = "ecids/"

while true do
  File.open("devices.yaml", "r+") { |f|
    devices = Psych.load(f.read)
    index = 0

    devices.each_pair do |k, v|
      ecid      = v['ecid']
      phone_ver = v['phone_ver']
      build     = v['build']
      last_shsh = v['last_shsh']

      last_ios_ver_avail = check_latest_ios(phone_ver, build)
      entry = "Last ios version for " + phone_ver + "(" + build + ") is " + last_ios_ver_avail
      log(:info, entry)

      if last_shsh < last_ios_ver_avail
        # Update devices.yaml for latest ios shsh
        dev = "Device " + index.to_s
        devices[dev]['last_shsh'] = last_ios_ver_avail

        manifest_path = manifest_dir + "BuildManifest-" + phone_ver.downcase + "-" + last_ios_ver_avail + ".plist.gz"
        entry = "Manifest Path: " + manifest_path
        log(:info, entry)

        manifest_content = ''
        Zlib::GzipReader.open(manifest_path) { |gz|
          manifest_content = gz.read
        }

        manifest = Plist::parse_xml(manifest_content)
        plist_data = build_plist_for_manifest(manifest, ecid)

        res = request_shsh(plist_data)
        # Response will be in the form STATUS=0&MESSAGE=SUCCESS&REQUEST_STRING=
        d = CGI::parse(res.body)

        if d['MESSAGE'][0] == "SUCCESS"
          entry = "Correctly retrieved shsh for " + phone_ver + "(" + build + ")"
          log(:info, entry)

          ecid_path = ecid_dir + ecid.to_s + "-" + phone_ver + "-" + last_ios_ver_avail + ".shsh"
          File.open(ecid_path, "w") { |f|
            f.write(d['REQUEST_STRING'][0])
          }
        else
          entry = "Error while retrieving shsh for " + phone_ver + "(" + build + ")"
          log(:fatal, entry)
          entry = "Response: " + res.body
          log(:debug, entry)
        end
      end

      index += 1
    end

    # update yaml for latest ios shsh
    f.truncate(0)
    f.seek(0)
    f.write(devices.to_yaml)
    f.close()
  }

  # sleep 8h
  sleep(28800)
end