def test_get_crash_log(self): mux = USBMux() if not mux.devices: mux.process(0.1) if len(mux.devices) == 0: print("no real device found") self.no_device = True return udid = mux.devices[0].serial procname = "QQ" lockdown = LockdownClient(udid) self.service = lockdown.startService("com.apple.crashreportcopymobile") client = AFCClient(lockdown,service=self.service) afc_shell = AFCShell(client=client) remote_crash_path = '/' dest_path = '/tmp' local_crashes =[] print('udid:', udid) for _dirname, _dirs, files in afc_shell.afc.dir_walk(remote_crash_path): for filename in files: if procname in filename: remote_crash_file = os.path.join(remote_crash_path, filename) data = afc_shell.afc.get_file_contents(remote_crash_file) local_crash_file = os.path.join(dest_path, filename) local_crashes.append(local_crash_file) with open(local_crash_file, 'wb') as fp: fp.write(data) print(local_crashes)
def file_read(self, handle, sz): MAXIMUM_READ_SIZE = 1 << 16 data = "" if PY3: data = b"" while sz > 0: if sz > MAXIMUM_READ_SIZE: toRead = MAXIMUM_READ_SIZE else: toRead = sz try: self.dispatch_packet(AFC_OP_READ, struct.pack("<QQ", handle, toRead)) s, d = self.receive_data() except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.afc") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead data += d return data
def test_get_crash_log(self): mux = USBMux() if not mux.devices: mux.process(0.1) if len(mux.devices) == 0: print("no real device found") self.no_device = True return udid = mux.devices[0].serial procname = "QQ" lockdown = LockdownClient(udid) self.service = lockdown.startService("com.apple.crashreportcopymobile") client = AFCClient(lockdown, service=self.service) afc_shell = AFCShell(client=client) remote_crash_path = '/' dest_path = '/tmp' local_crashes = [] print('udid:', udid) for _dirname, _dirs, files in afc_shell.afc.dir_walk( remote_crash_path): for filename in files: if procname in filename: remote_crash_file = os.path.join(remote_crash_path, filename) data = afc_shell.afc.get_file_contents(remote_crash_file) local_crash_file = os.path.join(dest_path, filename) local_crashes.append(local_crash_file) with open(local_crash_file, 'wb') as fp: fp.write(data) print(local_crashes)
def install(self, ipa_path, options=None, handler=None, *args): '''安装应用程序 :param ipa_path: 安装包的路径 :type ipa_path: str :return: boolean - 安装是否成功 ''' print "上传安装包..." afc_client = AFCClient(self.lockdown) tmp_ipa = "t%d.ipa" % time.time() with open(ipa_path, "rb") as f: ipa_content = f.read() afc_client.set_file_contents("/" + tmp_ipa, ipa_content) print "上传完毕" print "开始安装" cmd = {"Command": "Install", "PackagePath": tmp_ipa} if options: cmd.update(options) self.lockdown = LockdownClient(self.udid) self.service = self.lockdown.startService( "com.apple.mobile.installation_proxy") self.service.sendPlist(cmd) ret = self.wait_completion(handler, args) if ret[0]: print "安装成功" else: print "安装失败:%s" % ret[1] return ret
def file_write(self, handle, data): MAXIMUM_WRITE_SIZE = 1 << 15 hh = struct.pack("<Q", handle) segments = len(data) / MAXIMUM_WRITE_SIZE try: for i in xrange(segments): self.dispatch_packet( AFC_OP_WRITE, hh + data[i * MAXIMUM_WRITE_SIZE:(i + 1) * MAXIMUM_WRITE_SIZE], this_length=48) s, d = self.receive_data() if s != AFC_E_SUCCESS: self.logger.error("file_write error: %d", s) break if len(data) % MAXIMUM_WRITE_SIZE: self.dispatch_packet(AFC_OP_WRITE, hh + data[segments * MAXIMUM_WRITE_SIZE:], this_length=48) s, d = self.receive_data() except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) self.file_write(handle, data) return s
def do_operation(self, opcode, data=""): try: self.dispatch_packet(opcode, data) return self.receive_data() except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) return self.do_operation(opcode, data)
def __init__(self, lockdown=None, serviceName="com.apple.mobile.diagnostics_relay"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService(serviceName) self.packet_num = 0
def __init__(self, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService( "com.apple.mobile.installation_proxy")
def __init__(self, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.c = self.lockdown.startService("com.apple.syslog_relay") if self.c: self.c.send("watch") else: sys.exit(1)
def start(self): lockdown = LockdownClient(self.udid) ios_version = lockdown.allValues['ProductVersion'] if DT.compare_version(ios_version, '11.0') >= 0: # iOS11真机以上不支持数据分割 self._partial_supported = False self.web_inspector = lockdown.startService("com.apple.webinspector") self._sock = self.web_inspector.s self._sock.setblocking(False) self._sock.settimeout(5) self.init_inspector()
def test_get_device_info(self): udid = self._get_device() print('udid:%s' % udid) if udid is None: print("no real device found") return lockdown = LockdownClient(udid) lockdown.startService("com.apple.afc") info = lockdown.allValues print(info) self.assertIsInstance(info, dict, 'Query device information error')
def __init__(self, bundle_id, udid): super(RealDeviceProtocol, self).__init__(bundle_id, udid) self._partial_supported = True lockdown = LockdownClient(self.udid) ios_version = lockdown.allValues['ProductVersion'] if DT.compare_version(ios_version, '11.0') >= 0: # iOS11真机以上不支持数据分割 self._partial_supported = False self.web_inspector = lockdown.startService("com.apple.webinspector") self._sock = self.web_inspector.s self._sock.setblocking(False) self._sock.settimeout(5)
def setUp(self): mux = USBMux() if not mux.devices: mux.process(0.1) if len(mux.devices) == 0: print("no real device found") self.no_device = True return self.udid = mux.devices[0].serial self.lockdownclient = LockdownClient(self.udid) self.service = self.lockdownclient.startService("com.apple.mobile.installation_proxy")
def __init__(self, lockdown=None, serviceName="com.apple.mobile.file_relay"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] >= "8": raise DeviceVersionNotSupported self.service = self.lockdown.startService(serviceName) self.packet_num = 0
def __init__(self, filename, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.pcapd") self.f = open(filename, "wb") self.f.write( struct.pack("<LHHLLLL", 0xa1b2c3d4, 2, 4, 0, 0, 65535, LINKTYPE_ETHERNET)) self._stop = False
def __init__(self, lockdown=None, serviceName='com.apple.mobile.screenshotr'): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() # Starting Screenshot service self.service = self.lockdown.startService(serviceName) # hand check DLMessageVersionExchange = self.service.recvPlist() #assert len(DLMessageVersionExchange) == 2 version_major = DLMessageVersionExchange[1] self.service.sendPlist( ["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist()
def get_device_info(udid=None, keyname=None): '''获取iOS设备的相关属性信息 :param udid: iOS设备的udid :type udid: str :param keyname: iOS设备的特定信息字段的名称 :type keyname: str :returns: str - iOS设备的信息 ''' lockdown = LockdownClient(udid) lockdown.startService("com.apple.afc") if keyname: return lockdown.allValues.get(keyname) else: return lockdown.allValues
def house_arrest(lockdown, applicationId): try: mis = lockdown.startService("com.apple.mobile.house_arrest") except: lockdown = LockdownClient() mis = lockdown.startService("com.apple.mobile.house_arrest") if mis == None: return mis.sendPlist({"Command": "VendDocuments", "Identifier": applicationId}) res = mis.recvPlist() if res.get("Error"): print "Unable to Lookup the selected application: You probably trying to access to a system app..." return None return AFCClient(lockdown, service=mis)
def house_arrest(lockdown, applicationId): try: mis = lockdown.startService("com.apple.mobile.house_arrest") except: lockdown = LockdownClient() mis = lockdown.startService("com.apple.mobile.house_arrest") if mis == None: return mis.sendPlist({"Command": "VendDocuments", "Identifier": applicationId}) res = mis.recvPlist() if res.get("Error"): print("Unable to Lookup the selected application: You probably trying to access to a system app...") return None return AFCClient(lockdown, service=mis)
def file_write(self, handle, data): MAXIMUM_WRITE_SIZE = 1 << 15 hh = struct.pack("<Q", handle) segments = int(len(data) / MAXIMUM_WRITE_SIZE) try: for i in range(segments): self.dispatch_packet(AFC_OP_WRITE, hh + data[ i * MAXIMUM_WRITE_SIZE:(i + 1) * MAXIMUM_WRITE_SIZE], this_length=48) s, d = self.receive_data() if s != AFC_E_SUCCESS: print("file_write error %d" % s) break if len(data) % MAXIMUM_WRITE_SIZE: self.dispatch_packet(AFC_OP_WRITE, hh + data[segments * MAXIMUM_WRITE_SIZE:], this_length=48) s, d = self.receive_data() except ImportError: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) self.file_write(handle, data) return s
def get_screenshot(udid=None, filepath="/tmp/screenshot.png"): '''获取iOS设备的屏幕快照 :param udid: iOS设备的udid :type udid: str :param filepath: 屏幕快照的存储路径 :type filepath: str :returns: boolean - 截图是否成功 ''' result = False tiff_file = tempfile.NamedTemporaryFile(suffix='.tiff') tiff_file_path = tiff_file.name lockdown = LockdownClient(udid) screenshot = screenshotr(lockdown) data = screenshot.take_screenshot() with open(tiff_file_path, "wb") as fd: fd.write(data) screenshot.stop_session() try: args = [ "/usr/bin/sips", "-s format png", tiff_file_path, "--out", filepath ] check_call(" ".join(args), shell=True, stderr=STDOUT) result = True except CalledProcessError, e: print e.output
class screenshotr(object): def __init__(self, lockdown=None, serviceName='com.apple.mobile.screenshotr'): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() # Starting Screenshot service self.service = self.lockdown.startService(serviceName) # hand check DLMessageVersionExchange = self.service.recvPlist() #assert len(DLMessageVersionExchange) == 2 version_major = DLMessageVersionExchange[1] self.service.sendPlist( ["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist() def stop_session(self): self.service.close() def take_screenshot(self): self.service.sendPlist( ['DLMessageProcessMessage', {'MessageType': 'ScreenShotRequest'}]) res = self.service.recvPlist() assert len(res) == 2 assert res[0] == "DLMessageProcessMessage" if res[1].get('MessageType') == 'ScreenShotReply': data = res[1]['ScreenShotData'].data return data return None
def __init__(self, lockdown=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] >= "5": raise DeviceVersionNotSupported self.start()
class Syslog(object): def __init__(self, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.c = self.lockdown.startService("com.apple.syslog_relay") if self.c: self.c.send("watch") else: sys.exit(1) def watch(self, procName=None, logFile=None): while True: d = self.c.recv(4096) if not d: break if procName: procFilter = re.compile(procName, re.IGNORECASE) if len(d.split(" ")) > 4 and not procFilter.search(d): continue print(d.strip(b"\n\x00\x00")) if logFile: with open(logFile, 'a') as f: f.write(d.replace("\x00", ""))
def __init__(self, udid=None, bid='com.tencent.sng.test.gn', sandbox="VendContainer", lockdown=None): self.lockdown = lockdown if lockdown else LockdownClient(udid) self.bid = bid self.service = None retry = 5 while retry > 0: try: self.service = self.lockdown.startService( "com.apple.mobile.house_arrest") break except: import traceback traceback.print_exc() retry -= 1 time.sleep(5) if self.service is None: raise RuntimeError('Connect to house_arrest failed') self.service.sendPlist({"Command": sandbox, "Identifier": bid}) self.afc_shell = AFCShell(client=self) status = self.service.recvPlist() if status.has_key( 'Error') and status['Error'] == "ApplicationLookupFailed": raise RuntimeWarning('ApplicationLookupFailed') if status.has_key('Status') and status['Status'] != 'Complete': raise RuntimeWarning('House arrest service launch failed') super(SandboxClient, self).__init__(self.lockdown, service=self.service)
def main(): parser = OptionParser(usage="%prog") parser.add_option("-l", "--list", dest="list", action="store_true", default=False, help="List installed profiles") parser.add_option("-i", "--install", dest="install", action="store", metavar="FILE", help="Install profile") parser.add_option("-r", "--remove", dest="remove", action="store", metavar="IDENTIFIER", help="Remove profile") (options, args) = parser.parse_args() if not options.list and not options.install and not options.remove: parser.print_help() return lockdown = LockdownClient() mc = MobileConfigService(lockdown) if options.list: pprint(mc.GetProfileList()) elif options.install: mc.InstallProfile(read_file(options.install)) elif options.remove: pprint(mc.RemoveProfile(options.remove))
def __init__(self, lockdown=None, serviceName="com.apple.mobile.house_arrest", service=None): self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient() self.service = service if service else self.lockdown.startService( self.serviceName)
def __init__(self, lockdown=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.c = self.lockdown.startService("com.apple.syslog_relay") if self.c: self.c.send("watch") else: exit(1)
def test_install_app(self): if self.no_device: return ipa_path = os.path.join(os.path.expanduser("~"), "Downloads/app/DemoApp.ipa") tmp_ipa = "/t%d.ipa" % time.time() with open(ipa_path, "rb") as f: ipa_content = f.read() afc = AFCClient(self.lockdownclient) afc.set_file_contents(tmp_ipa, ipa_content) print("Upload completed") print("Starting installation") cmd = {"Command":"Install", "PackagePath": tmp_ipa} self.lockdownclient = LockdownClient(self.udid) self.service = self.lockdownclient.startService("com.apple.mobile.installation_proxy") self.service.sendPlist(cmd) result, err = self.wait_completion() self.assertTrue(result, 'install_app failed: %s' % err)
def __init__(self, lockdown=None, serviceName="com.apple.mobile.notification_proxy", udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.service = self.lockdown.startService(serviceName)
def __init__(self,lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.mobile.installation_proxy")
def __init__(self, lockdown=None, backupPath=None, password=""): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] < "5": raise DeviceVersionNotSupported self.udid = lockdown.getValue("", "UniqueDeviceID") self.willEncrypt = lockdown.getValue("com.apple.mobile.backup", "WillEncrypt") self.escrowBag = lockdown.getValue('', 'EscrowBag') self.service = self.lockdown.startServiceWithEscrowBag( "com.apple.mobilebackup2", self.escrowBag) if not self.service: raise Exception( "MobileBackup2 init error : Could not start com.apple.mobilebackup2" ) if backupPath: self.backupPath = backupPath else: self.backupPath = "backups" if not os.path.isdir(self.backupPath): os.makedirs(self.backupPath, 0o0755) print( "Starting new com.apple.mobilebackup2 service with working dir: %s" % self.backupPath) self.password = password DLMessageVersionExchange = self.service.recvPlist() version_major = DLMessageVersionExchange[1] self.service.sendPlist( ["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist() if DLMessageDeviceReady and DLMessageDeviceReady[ 0] == "DLMessageDeviceReady": self.version_exchange() else: raise Exception("MobileBackup2 init error %s" % DLMessageDeviceReady)
def __init__(self, lockdown=None, serviceName="com.apple.afc", service=None): self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient() self.service = service if service else self.lockdown.startService( self.serviceName) self.packet_num = 0
def __init__(self, afcname='com.apple.afc', completekey='tab', stdin=None, stdout=None, client=None, udid=None, logger=None): Cmd.__init__(self, completekey=completekey, stdin=stdin, stdout=stdout) self.logger = logger or logging.getLogger(__name__) self.lockdown = LockdownClient() self.afc = client if client else AFCClient(self.lockdown, serviceName=afcname, udid=udid) self.curdir = '/' self.prompt = 'AFC$ ' + self.curdir + ' ' self.complete_cat = self._complete self.complete_ls = self._complete
def __init__(self, filename, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.pcapd") self.f = open(filename, "wb") self.f.write(struct.pack("<LHHLLLL", 0xa1b2c3d4, 2, 4, 0, 0, 65535, LINKTYPE_ETHERNET)) self._stop = False
class FileRelay(object): def __init__(self, lockdown=None, serviceName="com.apple.mobile.file_relay"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] >= "8": raise DeviceVersionNotSupported self.service = self.lockdown.startService(serviceName) self.packet_num = 0 def stop_session(self): print("Disconecting...") self.service.close() def request_sources(self, sources=["UserDatabases"]): self.service.sendPlist({"Sources": sources}) while 1: res = self.service.recvPlist() if res: s = res.get("Status") if s == "Acknowledged": z = "" while True: x = self.service.recv() if not x: break z += x return z else: print(res.get("Error")) break return None
class PcapClient(object): def __init__(self, filename, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.pcapd") self.f = open(filename, "wb") self.f.write(struct.pack("<LHHLLLL", 0xa1b2c3d4, 2, 4, 0, 0, 65535, LINKTYPE_ETHERNET)) self._stop = False def __del__(self): self.stop() def writePacket(self, packet): t = time.time() #TODO check milisecond conversion pkthdr = struct.pack("<LLLL", int(t), int(t*1000000 % 1000000), len(packet), len(packet)) data = pkthdr + packet self.f.write(data) self.f.flush() return True def capturePackets(self): while not self._stop: d = self.service.recvPlist() if not d: break data = d.data hdrsize, xxx, packet_size = struct.unpack(">LBL", data[:9]) flags1, flags2, offset_to_ip_data, zero = struct.unpack(">LLLL", data[9:0x19]) assert hdrsize >= 0x19 interfacetype = data[0x19:hdrsize].strip("\x00") t = time.time() print interfacetype, packet_size, t packet = data[hdrsize:] assert packet_size == len(packet) if offset_to_ip_data == 0: #add fake ethernet header for pdp packets packet = "\xBE\xEF" * 6 + "\x08\x00" + packet if not self.writePacket(packet): break def stop(self): self._stop = True self.f.close()
def __init__(self, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] >= "5": raise DeviceVersionNotSupported self.service = self.lockdown.startService("com.apple.mobilebackup") self.udid = self.lockdown.udid DLMessageVersionExchange = self.service.recvPlist() version_major = DLMessageVersionExchange[1] self.service.sendPlist(["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist() if DLMessageDeviceReady and DLMessageDeviceReady[0] == "DLMessageDeviceReady": print "Got DLMessageDeviceReady"
def __init__(self, lockdown=None, serviceName="com.apple.mobile.notification_proxy"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService(serviceName)
(options, args) = parser.parse_args() if sys.platform == "win32": import win32pipe import win32file output = Win32Pipe() else: if options.output: path = options.output else: _, path = mkstemp(prefix="device_dump_", suffix=".pcap", dir=".") print("Recording data to: %s" % path) output = PcapOut(path) lockdown = LockdownClient() pcap = lockdown.startService("com.apple.pcapd") while True: d = pcap.recvPlist() if not d: break data = d.data hdrsize, xxx, packet_size = struct.unpack(">LBL", data[:9]) flags1, flags2, offset_to_ip_data, zero = struct.unpack(">LLLL", data[ 9:0x19]) assert hdrsize >= 0x19 interfacetype = data[0x19:hdrsize].strip("\x00") t = time.time() print(interfacetype, packet_size, t)
class MobileBackup(object): def __init__(self, lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion[0] >= "5": raise DeviceVersionNotSupported self.service = self.lockdown.startService("com.apple.mobilebackup") self.udid = self.lockdown.udid DLMessageVersionExchange = self.service.recvPlist() version_major = DLMessageVersionExchange[1] self.service.sendPlist( ["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist() if DLMessageDeviceReady and DLMessageDeviceReady[0] == "DLMessageDeviceReady": print("Got DLMessageDeviceReady") def check_filename(self, name): if name.find("../") != -1: raise Exception("HAX, sneaky dots in path %s" % name) if not name.startswith(self.backupPath): if name.startswith(self.udid): name = os.path.join(self.backupPath, name) return name name = os.path.join(self.backupPath, self.udid, name) return name return name def read_file(self, filename): filename = self.check_filename(filename) if os.path.isfile(filename): with open(filename, 'rb') as f: data = f.read() f.close() return data return None def write_file(self, filename, data): filename = self.check_filename(filename) with open(filename, 'wb') as f: f.write(data) f.close() def create_info_plist(self): root_node = self.lockdown.allValues # print pprint(root_node) info = {"BuildVersion": root_node.get("BuildVersion") or "", "DeviceName": root_node.get("DeviceName") or "", "Display Name": root_node.get("DeviceName") or "", "GUID": "---", "ProductType": root_node.get("ProductType") or "", "ProductVersion": root_node.get("ProductVersion") or "", "Serial Number": root_node.get("SerialNumber") or "", "Unique Identifier": self.udid.upper(), "Target Identifier": self.udid, "Target Type": "Device", "iTunes Version": "10.0.1" } info["ICCID"] = root_node.get("IntegratedCircuitCardIdentity") or "" info["IMEI"] = root_node.get( "InternationalMobileEquipmentIdentity") or "" info["Last Backup Date"] = datetime.datetime.now() afc = AFCClient(self.lockdown) iTunesFilesDict = {} iTunesFiles = afc.read_directory("/iTunes_Control/iTunes/") for i in iTunesFiles: data = afc.get_file_contents("/iTunes_Control/iTunes/" + i) if data: iTunesFilesDict[i] = plistlib.Data(data) info["iTunesFiles"] = iTunesFilesDict iBooksData2 = afc.get_file_contents("/Books/iBooksData2.plist") if iBooksData2: info["iBooks Data 2"] = plistlib.Data(iBooksData2) info["iTunes Settings"] = self.lockdown.getValue("com.apple.iTunes") print("Creating %s" % os.path.join(self.udid, "Info.plist")) self.write_file(os.path.join(self.udid, "Info.plist"), plistlib.dumps(info)) def ping(self, message): self.service.sendPlist(["DLMessagePing", message]) print("ping response", self.service.recvPlist()) def device_link_service_send_process_message(self, msg): return self.service.sendPlist(["DLMessageProcessMessage", msg]) def device_link_service_receive_process_message(self): req = self.service.recvPlist() if req: assert req[0] == "DLMessageProcessMessage" return req[1] def send_file_received(self): return self.device_link_service_send_process_message({"BackupMessageTypeKey": "kBackupMessageBackupFileReceived"}) def request_backup(self): req = {"BackupComputerBasePathKey": "/", "BackupMessageTypeKey": "BackupMessageBackupRequest", "BackupProtocolVersion": "1.6" } self.create_info_plist() self.device_link_service_send_process_message(req) res = self.device_link_service_receive_process_message() if not res: return if res["BackupMessageTypeKey"] != "BackupMessageBackupReplyOK": print(res) return self.device_link_service_send_process_message(res) filedata = "" f = None outpath = None while True: res = self.service.recvPlist() if not res or res[0] != "DLSendFile": if res[0] == "DLMessageProcessMessage": if res[1].get("BackupMessageTypeKey") == "BackupMessageBackupFinished": print("Backup finished OK !") # TODO BackupFilesToDeleteKey plistlib.writePlist( res[1]["BackupManifestKey"], self.check_filename("Manifest.plist")) break data = res[1].data info = res[2] if not f: outpath = self.check_filename(info.get("DLFileDest")) print(info["DLFileAttributesKey"][ "Filename"], info.get("DLFileDest")) f = open(outpath + ".mddata", "wb") f.write(data) if info.get("DLFileStatusKey") == DEVICE_LINK_FILE_STATUS_LAST_HUNK: self.send_file_received() f.close() if not info.get("BackupManifestKey", False): plistlib.writePlist( info.get("BackupFileInfo"), outpath + ".mdinfo") f = None
class AFCClient(object): def __init__(self, lockdown=None, serviceName="com.apple.afc", service=None): self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient() self.service = service if service else self.lockdown.startService(self.serviceName) self.packet_num = 0 def stop_session(self): print "Disconecting..." self.service.close() def dispatch_packet(self, operation, data, this_length=0): afcpack = Container(magic=AFCMAGIC, entire_length=40 + len(data), this_length=40 + len(data), packet_num=self.packet_num, operation=operation) if this_length: afcpack.this_length = this_length header = AFCPacket.build(afcpack) self.packet_num += 1 self.service.send(header + data) def receive_data(self): res = self.service.recv(40) status = AFC_E_SUCCESS data = "" if res: res = AFCPacket.parse(res) assert res["entire_length"] >= 40 length = res["entire_length"] - 40 data = self.service.recv_exact(length) if res.operation == AFC_OP_STATUS: if length != 8: print "Status length != 8" status = struct.unpack("<Q", data[:8])[0] elif res.operation != AFC_OP_DATA: pass#print "error ?", res return status, data def do_operation(self, opcode, data=""): try: self.dispatch_packet(opcode, data) return self.receive_data() except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) return self.do_operation(opcode, data) def list_to_dict(self, d): t = d.split("\x00") t = t[:-1] assert len(t) % 2 == 0 res = {} for i in xrange(len(t)/2): res[t[i*2]] = t[i*2 + 1] return res def get_device_infos(self): status, infos = self.do_operation(AFC_OP_GET_DEVINFO) if status == AFC_E_SUCCESS: return self.list_to_dict(infos) def read_directory(self, dirname): status, data = self.do_operation(AFC_OP_READ_DIR, dirname) if status == AFC_E_SUCCESS: return filter(lambda x:x!="", data.split("\x00")) return [] def make_directory(self, dirname): status, data = self.do_operation(AFC_OP_MAKE_DIR, dirname) return status def remove_directory(self, dirname): info = self.get_file_info(dirname) if not info or info.get("st_ifmt") != "S_IFDIR": print "remove_directory: %s not S_IFDIR" % dirname return for d in self.read_directory(dirname): if d == "." or d == ".." or d == "": continue info = self.get_file_info(dirname + "/" + d) if info.get("st_ifmt") == "S_IFDIR": self.remove_directory(dirname + "/" + d) else: print dirname + "/" + d self.file_remove(dirname + "/" + d) assert len(self.read_directory(dirname)) == 2 #.. et . return self.file_remove(dirname) def get_file_info(self, filename): status, data = self.do_operation(AFC_OP_GET_FILE_INFO, filename) if status == AFC_E_SUCCESS: return self.list_to_dict(data) def make_link(self, target, linkname, type=AFC_SYMLINK): status, data = self.do_operation(AFC_OP_MAKE_LINK, struct.pack("<Q", type) + target + "\x00" + linkname + "\x00") print "make_link", status return status def file_open(self, filename, mode=AFC_FOPEN_RDONLY): status, data = self.do_operation(AFC_OP_FILE_OPEN, struct.pack("<Q", mode) + filename + "\x00") return struct.unpack("<Q", data)[0] if data else None def file_close(self, handle): status, data = self.do_operation(AFC_OP_FILE_CLOSE, struct.pack("<Q", handle)) return status def file_remove(self, filename): status, data = self.do_operation(AFC_OP_REMOVE_PATH, filename + "\x00") return status def file_rename(self, old, new): status, data = self.do_operation(AFC_OP_RENAME_PATH, old + "\x00" + new + "\x00") return status def file_read(self, handle, sz): MAXIMUM_READ_SIZE = 1 << 16 data = "" while sz > 0: if sz > MAXIMUM_READ_SIZE: toRead = MAXIMUM_READ_SIZE else: toRead = sz try: self.dispatch_packet(AFC_OP_READ, struct.pack("<QQ", handle, toRead)) s, d = self.receive_data() except: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.afc") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead data += d return data def file_write(self, handle, data): MAXIMUM_WRITE_SIZE = 1 << 15 hh = struct.pack("<Q", handle) segments = len(data) / MAXIMUM_WRITE_SIZE try: for i in xrange(segments): self.dispatch_packet(AFC_OP_WRITE, hh + data[i*MAXIMUM_WRITE_SIZE:(i+1)*MAXIMUM_WRITE_SIZE], this_length=48) s, d = self.receive_data() if s != AFC_E_SUCCESS: print "file_write error %d" % s break if len(data) % MAXIMUM_WRITE_SIZE: self.dispatch_packet(AFC_OP_WRITE, hh + data[segments*MAXIMUM_WRITE_SIZE:], this_length=48) s, d = self.receive_data() except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) self.file_write(handle,data) return s def get_file_contents(self, filename): info = self.get_file_info(filename) if info: if info['st_ifmt'] == 'S_IFLNK': filename = info['LinkTarget'] if info['st_ifmt'] == 'S_IFDIR': print "%s is directory..." % filename return print "Reading %s" % filename h = self.file_open(filename) if not h: return d = self.file_read(h, int(info["st_size"])) self.file_close(h) return d return def set_file_contents(self, filename, data): h = self.file_open(filename, AFC_FOPEN_WR) if not h: return d = self.file_write(h, data) self.file_close(h) def dir_walk(self, dirname): dirs = [] files = [] for fd in self.read_directory(dirname): if fd in ('.', '..', ''): continue infos = self.get_file_info(posixpath.join(dirname, fd)) if infos and infos.get('st_ifmt') == 'S_IFDIR': dirs.append(fd) else: files.append(fd) yield dirname, dirs, files if dirs: for d in dirs: for walk_result in self.dir_walk(posixpath.join(dirname, d)): yield walk_result
class NPClient(object): def __init__(self, lockdown=None, serviceName="com.apple.mobile.notification_proxy"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService(serviceName) def stop_session(self): print("Disconecting...") self.service.close() def post_notification(self, notification): # Sends a notification to the device's notification_proxy. self.service.sendPlist({"Command": "PostNotification", "Name": notification}) self.service.sendPlist({"Command": "Shutdown"}) res = self.service.recvPlist() pprint(res) if res: if res.get("Command") == "ProxyDeath": return res.get("Command") else: print("Got unknown NotificationProxy command %s" % res.get("Command")) pprint(res) return None def observe_notification(self, notification): # Tells the device to send a notification on the specified event print("Observing %s" % notification) self.service.sendPlist({"Command": "ObserveNotification", "Name": notification}) def get_notification(self, notification): # Checks if a notification has been sent by the device res = self.service.recvPlist() if res: if res.get("Command") == "RelayNotification": if res.get("Name"): return res.get("Name") elif res.get("Command") == "ProxyDeath": print("NotificationProxy died!") else: print("Got unknown NotificationProxy command %s" % res.get("Command")) pprint(res) return None def notifier(self, name, args=None): if args == None: return None self.observe_notification(args.get("notification")) while args.get("running") == True: np_name = self.get_notification(args.get("notification")) if np_name: userdata = args.get("userdata") try: _thread.start_new_thread( args.get("callback"), (np_name, userdata, )) except: print("Error: unable to start thread") def subscribe(self, notification, cb, data=None): np_data = { "running": True, "notification": notification, "callback": cb, "userdata": data, } try: _thread.start_new_thread( self.notifier, ("NotificationProxyNotifier_" + notification, np_data, )) except: print("Error: unable to start thread") while(1): time.sleep(1)
class installation_proxy(object): def __init__(self,lockdown=None): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.mobile.installation_proxy") def watch_completion(self,handler=None,*args): while True: z = self.service.recvPlist() if not z: break completion = z.get("PercentComplete") if completion: if handler: print "calling handler" handler(completion,*args) print "%s %% Complete" % z.get("PercentComplete") if z.get("Status") == "Complete": return z.get("Status") return "Error" def send_cmd_for_bid(self,bundleID, cmd="Archive", options=None, handler=None, *args): cmd = {"Command": cmd, "ApplicationIdentifier": bundleID } if options: cmd.update(options) self.service.sendPlist(cmd) #print "%s : " % (cmd, bundleID) print "%s : %s\n" % (cmd, self.watch_completion(handler, *args)) def uninstall(self,bundleID, options=None, handler=None, *args): self.send_cmd_for_bid(bundleID, "Uninstall", options, handler, args) def install_or_upgrade(self, ipaPath, cmd="Install", options=None, handler=None, *args): afc = AFCClient(self.lockdown) afc.set_file_contents("/" + os.path.basename(ipaPath), open(ipaPath,"rb").read()) cmd = {"Command":cmd, "PackagePath": os.path.basename(ipaPath)} if options: cmd.update(options) self.service.sendPlist(cmd) # print "%s : " % (cmd, bundleID) print "%s : %s\n" % (cmd, self.watch_completion(handler, args)) def install(self,ipaPath, options=None, handler=None, *args): return self.install_or_upgrade(ipaPath, "Install", client_options, handler, args) def upgrade(self,ipaPath, options=None, handler=None, *args): return self.install_or_upgrade(ipaPath, "Upgrade", client_options, handler, args) def apps_info(self): self.service.sendPlist({"Command": "Lookup"}) return self.service.recvPlist().get('LookupResult') def archive(self,bundleID, options=None, handler=None, *args): self.send_cmd_for_bid(bundleID, "Archive", options, handler, args) def restore_archive(self,bundleID, options=None, handler=None, *args): self.send_cmd_for_bid(bundleID, "Restore", client_options, handler, args) def remove_archive(self,bundleID, options={}, handler=None, *args): self.send_cmd_for_bid(bundleID, "RemoveArchive", options, handler, args) def archives_info(self): return self.service.sendRequest({"Command": "LookupArchive"}).get("LookupResult") def search_path_for_bid(self, bid): path = None for a in self.get_apps(appTypes=["User","System"]): if a.get("CFBundleIdentifier") == bid: path = a.get("Path")+"/"+a.get("CFBundleExecutable") return path def get_apps(self,appTypes=["User"]): return [app for app in self.apps_info().values() if app.get("ApplicationType") in appTypes] def print_apps(self, appType=["User"]): for app in self.get_apps(appType): print ("%s : %s => %s" % (app.get("CFBundleDisplayName"), app.get("CFBundleIdentifier"), app.get("Path") if app.get("Path") else app.get("Container"))).encode('utf-8') def get_apps_bid(self,appTypes=["User"]): return [app["CFBundleIdentifier"] for app in self.get_apps() if app.get("ApplicationType") in appTypes] def close(self): self.service.close() def __del__(self): self.close()
class InstallationProxyTest(unittest.TestCase): def setUp(self): mux = USBMux() if not mux.devices: mux.process(0.1) if len(mux.devices) == 0: print("no real device found") self.no_device = True return self.udid = mux.devices[0].serial self.lockdownclient = LockdownClient(self.udid) self.service = self.lockdownclient.startService("com.apple.mobile.installation_proxy") def wait_completion(self, handler=None, *args): while True: z = self.service.recvPlist() print(type(z), z) if not z: break completion = z.get("PercentComplete") if completion: if handler: handler(completion, *args) print("%s: %s%% Complete" % (z.get("Status"), completion)) else: if z.get("Status") == "Complete" or ("Status" not in z and "CFBundleIdentifier" in z): return (True, "") else: return (False, z.get("ErrorDescription")) def test_install_app(self): if self.no_device: return ipa_path = os.path.join(os.path.expanduser("~"), "Downloads/app/DemoApp.ipa") tmp_ipa = "/t%d.ipa" % time.time() with open(ipa_path, "rb") as f: ipa_content = f.read() afc = AFCClient(self.lockdownclient) afc.set_file_contents(tmp_ipa, ipa_content) print("Upload completed") print("Starting installation") cmd = {"Command":"Install", "PackagePath": tmp_ipa} self.lockdownclient = LockdownClient(self.udid) self.service = self.lockdownclient.startService("com.apple.mobile.installation_proxy") self.service.sendPlist(cmd) result, err = self.wait_completion() self.assertTrue(result, 'install_app failed: %s' % err) def test_uninstall_app(self): if self.no_device: return bundle_id = "com.gotohack.test.demo" cmd = {"Command": "Uninstall", "ApplicationIdentifier": bundle_id} self.service.sendPlist(cmd) result, err = self.wait_completion() self.assertTrue(result, 'uninstall_app failed: %s' % err) def test_apps_info(self): if self.no_device: return self.service.sendPlist({"Command": "Lookup"}) print(self.service.recvPlist()) def test_list_apps(self, app_type='user'): if self.no_device: return options = {} if app_type == 'system': options["ApplicationType"] = "System" elif app_type == 'user': options["ApplicationType"] = "User" options["ReturnAttributes"] = ["CFBundleIdentifier", "CFBundleName", ] self.service.sendPlist({"Command": "Browse", "ClientOptions": options}) apps = [] while True: z = self.service.recvPlist() if z.get("Status") == "BrowsingApplications": apps.extend(z["CurrentList"]) elif z.get("Status") == "Complete": break else: raise Exception(z.get("ErrorDescription")) print(apps) def tearDown(self): if not self.no_device and self.service: self.service.close()
class DIAGClient(object): def __init__(self, lockdown=None, serviceName="com.apple.mobile.diagnostics_relay"): if lockdown: self.lockdown = lockdown else: self.lockdown = LockdownClient() self.service = self.lockdown.startService(serviceName) self.packet_num = 0 def stop_session(self): print "Disconecting..." self.service.close() def query_mobilegestalt(self, MobileGestalt=MobileGestaltKeys.split("\n")): self.service.sendPlist({"Request": "MobileGestalt", "MobileGestaltKeys": MobileGestalt}) res = self.service.recvPlist() d = res.get("Diagnostics") if d: return d.get("MobileGestalt") return None def action(self, action="Shutdown", flags=None): self.service.sendPlist({"Request": action }) res = self.service.recvPlist() return res.get("Diagnostics") def restart(self): return self.action("Restart") def shutdown(self): return self.action("Shutdown") def diagnostics(self, diagType="All"): self.service.sendPlist({"Request": diagType}) res = self.service.recvPlist() if res: return res.get("Diagnostics") return None def ioregistry_entry(self, name=None, ioclass=None): d = {} if name: d["EntryName"] = name if ioclass: d["EntryClass"] = ioclass d["Request"] = "IORegistry" self.service.sendPlist(d) res = self.service.recvPlist() pprint(res) if res: return res.get("Diagnostics") return None def ioregistry_plane(self, plane=""): d = {} if plane: d["CurrentPlane"] = plane else: d["CurrentPlane"] = "" d["Request"] = "IORegistry" self.service.sendPlist(d) res = self.service.recvPlist() dd = res.get("Diagnostics") if dd: return dd.get("IORegistry") return None