def file_read_v2(self, handle, sz, local_file): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: with open(local_file, "ab") as local_file_handle: 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() local_file_handle.write(d) 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
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 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 file_read(self, handle, sz): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: print(str( (len(data) / full_size ) * 100 ) + "\r") 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 download_file(self, remote_file, local_file): max_blocks = 102400 if not os.path.isfile(local_file): info = self.get_file_info(remote_file) if info['st_ifmt'] == 'S_IFLNK': remote_file = info['LinkTarget'] block_count = int(info['st_blocks']) if block_count > max_blocks: counter = max_blocks remaining_blocks = block_count while remaining_blocks > 0: num_blocks_to_read = min(max_blocks, remaining_blocks) handle = self.file_open(remote_file, num_blocks_to_read) try: self.dispatch_packet(AFC_OP_READ, struct.pack("<QQ", handle, 65536)) s, d = self.receive_data() except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService( "com.apple.afc2")
def startAcquisition(self): sn = get_serial(self.logging) lockdown = LockdownClient(sn) device_found_mes = f"""\n Device Found! Device Name: {lockdown.allValues['DeviceName']} Device Model: {lockdown.allValues['ProductType']} iOS Version: {lockdown.allValues['ProductVersion']} Device Build: {lockdown.allValues['BuildVersion']} WiFi Address: {lockdown.allValues['WiFiAddress']} Hardware Model: {lockdown.allValues['HardwareModel']} """ self.logging.info(device_found_mes) afc_service = lockdown.startService("com.apple.afc") afc = AFCClient(lockdown=lockdown) afc.pull_directory('/', self.output) if self.md5 or self.sha1: with open(self.csv_path, "w", newline='') as csvfile: csvfile_obj = csv.writer(csvfile) if self.md5 and self.sha1: csvfile_obj.writerow( ["File Name", "Full Path", "MD5", "SHA-1"]) elif self.md5: csvfile_obj.writerow(["File Name", "Full Path", "MD5"]) elif self.sha1: csvfile_obj.writerow(["File Name", "Full Path", "SHA-1"]) hasher(self.output, self.md5, self.sha1, csvfile_obj, self.logging)
def startAcquisition(self): sn = get_serial(self.logging) lockdown = LockdownClient(sn) device_found_mes = f""" Device Found! Device Name: {lockdown.allValues['DeviceName']} Device Model: {lockdown.allValues['ProductType']} iOS Version: {lockdown.allValues['ProductVersion']} Device Build: {lockdown.allValues['BuildVersion']} WiFi Address: {lockdown.allValues['WiFiAddress']} Hardware Model: {lockdown.allValues['HardwareModel']} """ print(device_found_mes) afc2_service = lockdown.startService("com.apple.afc2") afc = AFC2Client(lockdown=lockdown) afc.pull_directory(self.remoteFolder, self.output) if self.md5 or self.sha1: with open(self.csv_path, "ab") as csvfile: csvfile_obj = csv.writer(csvfile) hasher(self.output, self.md5, self.sha1, csvfile_obj, self.logging)
def do_operation(self, opcode, data=""): try: self.dispatch_packet(opcode, data) data = self.receive_data() return 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 f**k(self): sn = self.get_serial() lockdown = LockdownClient(sn) #afc2_service = lockdown.startService("com.apple.afc2") lockdown.startService("com.apple.afc2") afc = AFC2Client(lockdown) #content = afc.get_file_contents('/jb/offsets.plist') afc.pull_directory('/', self.output) x = 0
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()
def file_read_v2(self, handle, sz, local_file, infos): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: with open(local_file, "ab") as local_file_handle: 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() if len(d) == 0: print(local_file + " appears to be an empty file") local_file_handle.write(b"") else: local_file_handle.write(d) except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.afc2") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead #data += d # Change modify times modify_time = datetime.fromtimestamp( int(infos['st_mtime']) // 1000000000) modTime = time.mktime(modify_time.timetuple()) os.utime(local_file, (modTime, modTime)) birth_time = int(infos['st_birthtime']) // 1000000000 # Change creation time on windows if os.name == 'nt': setctime(local_file, birth_time) return
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 __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 startAcquisition(self): sn = get_serial() lockdown_object = LockdownClient(sn) backup_object = MobileBackup2(udid=sn, logger=self.logging, backupPath=self.output) backup_object.backup() x = 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, lockdown=None, serviceName="com.apple.mobile.house_arrest", service=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) lockdownClient = LockdownClient(udid) serviceName = "com.apple.mobile.house_arrest" super(HouseArrestClient, self).__init__(lockdownClient, serviceName)
def __init__(self, lockdown=None, serviceName="com.apple.afc", service=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.service = service if service else self.lockdown.startService( self.serviceName) self.packet_num = 0
def __init__(self, lockdown=None, serviceName='com.apple.mobile.screenshotr', 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) DLMessageVersionExchange = self.service.recvPlist() version_major = DLMessageVersionExchange[1] self.service.sendPlist( ["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recvPlist()
def __init__(self, lockdown=None, serviceName="com.apple.mobile.file_relay", 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] >= "8": raise DeviceVersionNotSupported self.service = self.lockdown.startService(serviceName) self.packet_num = 0
def __init__(self, lockdown=None, backupPath=None, password="", udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.backupPath = backupPath if backupPath else "backups" self.password = password self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) if not self.lockdown: raise Exception("Unable to start lockdown") ProductVersion = self.lockdown.allValues['ProductVersion'] #ProductVersion = self.lockdown.getValue("", "ProductVersion") if ProductVersion and int( ProductVersion[:ProductVersion.find('.')]) < 5: raise DeviceVersionNotSupported self.start()
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))
class AFC2Client(object): def __init__(self, filesystem_obj, lockdown=None, serviceName="com.apple.afc2", service=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.filesystem_obj = filesystem_obj self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.service = service if service else self.lockdown.startService( self.serviceName) self.packet_num = 0 def stop_session(self): self.logger.info("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 if PY3 and isinstance(data, str): data = data.encode('utf-8') self.service.send(header + data) def receive_data(self): res = self.service.recv_exact(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: self.logger.error("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) data = self.receive_data() return data except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) return self.do_operation(opcode, data) def list_to_dict(self, d): if PY3: if type(d) != str: d = d.decode('utf-8') else: x = 0 t = d.split("\x00") t = t[:-1] assert len(t) % 2 == 0 res = {} for i in xrange(int(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: if PY3: if type(data) != str: data = data.decode('utf-8') else: print("Directory: " + dirname + " is a string, this shouldnt happen") return [x for x in data.split("\x00") if x != ""] return [] def get_file_info(self, filename): status, data = self.do_operation(AFC_OP_GET_FILE_INFO, filename) status2, data2 = self.do_operation(AFC_OP_READ, filename) if status == AFC_E_SUCCESS: return self.list_to_dict(data) if status == AFC_E_PERM_DENIED: self.logger.warning( "AFC Permission Denied for: " + filename + " Timestamps, file size, and other data cannot be obtained") return None def file_open(self, filename, mode=AFC_FOPEN_RDONLY): if PY3: filename = filename.encode('utf-8') separator = b"\x00" else: separator = "\x00" status, data = self.do_operation( AFC_OP_FILE_OPEN, struct.pack("<Q", mode) + filename + separator) 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_read(self, handle, sz): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: print(str((len(data) / full_size) * 100) + "\r") 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.afc2") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead data += d return data def file_read_v2(self, handle, sz, local_file, infos): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: with open(local_file, "ab") as local_file_handle: 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() if len(d) == 0: print(local_file + " appears to be an empty file") local_file_handle.write(b"") else: local_file_handle.write(d) except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.afc2") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead #data += d # Change modify times modify_time = datetime.fromtimestamp( int(infos['st_mtime']) // 1000000000) modTime = time.mktime(modify_time.timetuple()) os.utime(local_file, (modTime, modTime)) birth_time = int(infos['st_birthtime']) // 1000000000 # Change creation time on windows if os.name == 'nt': setctime(local_file, birth_time) return 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 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 get_file_contents_v2(self, filename, local_file): info = self.get_file_info(filename) if info: if info['st_ifmt'] == 'S_IFLNK': filename = info['LinkTarget'] if info['st_ifmt'] == 'S_IFDIR': self.logger.info("%s is directory...", filename) return self.logger.info("Reading: %s", filename) h = self.file_open(filename) if not h: return self.file_read_v2(h, int(info["st_size"]), local_file, info) self.file_close(h) 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 PY3 and isinstance(fd, bytes): fd = fd.decode('utf-8') 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 def pull_file(self, remote_file, local_file): local_file = local_file.replace("/", os.sep) if not os.path.exists(local_file): self.get_file_contents_v2(remote_file, local_file) else: x = 0 def read_buffer(self, remote_file, size, local_file): x = 0 def download_file(self, remote_file, local_file): max_blocks = 102400 if not os.path.isfile(local_file): info = self.get_file_info(remote_file) if info['st_ifmt'] == 'S_IFLNK': remote_file = info['LinkTarget'] block_count = int(info['st_blocks']) if block_count > max_blocks: counter = max_blocks remaining_blocks = block_count while remaining_blocks > 0: num_blocks_to_read = min(max_blocks, remaining_blocks) handle = self.file_open(remote_file, num_blocks_to_read) try: self.dispatch_packet(AFC_OP_READ, struct.pack("<QQ", handle, 65536)) s, d = self.receive_data() except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService( "com.apple.afc2") def handle_dir_pull(self, parent_dir, fd, output): if parent_dir == "/": new_folder = parent_dir + fd else: new_folder = parent_dir + '/' + fd new_folder = re.sub('[<>:"|?*]', '_', new_folder) local_folder = output + new_folder.strip() if not os.path.exists(local_folder): self.logger.info("Creating Folder: " + new_folder) os.makedirs(local_folder) infos = self.get_file_info(posixpath.join(parent_dir, fd)) # Change modify times modify_time = datetime.fromtimestamp( int(infos['st_mtime']) // 1000000000) modTime = time.mktime(modify_time.timetuple()) os.utime(local_folder, (modTime, modTime)) if new_folder is not '': self.pull_directory(new_folder, output) def handle_file_pull(self, parent_dir, fd, infos, output): if parent_dir == "/": new_file = parent_dir + fd else: new_file = parent_dir + '/' + fd new_file = re.sub('[<>:"|?*]', '_', new_file) local_file = output + os.sep + new_file.strip() parent_local_folder = (local_file[::-1].split("/")) local_single_file = parent_local_folder[0][::-1] del parent_local_folder[0] parent_local_folder = (os.sep.join(parent_local_folder))[::-1] if parent_local_folder.endswith(' '): parent_local_folder = parent_local_folder[:-1] local_file = os.path.join(parent_local_folder, local_single_file) if not os.path.exists(parent_local_folder): os.makedirs(parent_local_folder) if infos is not None: if infos['st_size'] == '0': open(local_file, 'a').close() self.pull_file(new_file, local_file) def pull_directory(self, parent_dir, output): windows_reserved_names = [ 'CON', 'PRN', 'AUX', 'CLOCK$', 'NUL', 'COM1', 'LPT1', 'LPT2', 'LPT3', 'COM2', 'COM3', 'COM4' ] for fd in self.read_directory(parent_dir): if PY3 and isinstance(fd, bytes): fd = fd.decode('utf-8') if fd in ('.', '..', ''): continue infos = self.get_file_info(posixpath.join(parent_dir, fd)) if infos and infos.get('st_ifmt') == 'S_IFDIR': '''Handle folder creating / pulling''' if fd.upper() in windows_reserved_names: fd = fd + "_MEAT_RENAMED" self.handle_dir_pull(parent_dir, fd, output) else: '''Handle file creating / pulling''' if fd.upper() in windows_reserved_names: fd = fd + "_MEAT_RENAMED" self.handle_file_pull(parent_dir, fd, infos, output) add_db_entry(self.filesystem_obj, fd, parent_dir, infos)
def __init__(self, lockdown, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.service = lockdown.startService("com.apple.mobile.MCInstall")
"--logfile", dest="logFile", default=False, help="Write Logs into specified file", type="string") parser.add_option("-w", "--watch-time", default=False, action="store", dest="watchtime", metavar="WATCH_TIME", help="watchtime") (options, args) = parser.parse_args() try: try: logging.basicConfig(level=logging.INFO) lckdn = LockdownClient(options.device_udid) syslog = Syslog(lockdown=lckdn) syslog.watch(watchtime=int(options.watchtime), procName=options.procName, logFile=options.logFile) except KeyboardInterrupt: print("KeyboardInterrupt caught") raise else: pass except (KeyboardInterrupt, SystemExit): exit()
(options, args) = parser.parse_args() if sys.platform == "win32": import win32pipe, 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) logging.basicConfig(level=logging.INFO) lockdown = LockdownClient(options.device_udid) pcap = lockdown.startService("com.apple.pcapd") while True: d = pcap.recvPlist() if not d: break if not PY3: d = d.data hdrsize, xxx, packet_size = struct.unpack(">LBL", d[:9]) flags1, flags2, offset_to_ip_data, zero = struct.unpack( ">LLLL", d[9:0x19]) assert hdrsize >= 0x19 if PY3: interfacetype = d[0x19:hdrsize].strip(b"\x00")
action="store_true", default=False, help="List installed applications (non system apps)") parser.add_option("-a", "--app", dest="app", action="store", default=None, metavar="APPID", help="Access application files with AFC") parser.add_option("-i", "--install", dest="installapp", action="store", default=None, metavar="FILE", help="Install an application package") (options, args) = parser.parse_args() if options.list: lockdown = LockdownClient() list_apps(lockdown) elif options.app: lockdown = LockdownClient() house_arrest_shell(lockdown, options.app) elif options.installapp: lockdown = LockdownClient() mobile_install(lockdown, options.installapp) else: parser.print_help()
def get_lockdown_and_service(udid): from pymobiledevice2.lockdown import LockdownClient lockdown = LockdownClient(udid) service = lockdown.startService("com.apple.mobile.installation_proxy") return lockdown, service
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
class AFCClient(object): def __init__(self, lockdown=None, serviceName="com.apple.afc", service=None, udid=None, logger=None): self.logger = logger or logging.getLogger(__name__) self.serviceName = serviceName self.lockdown = lockdown if lockdown else LockdownClient(udid=udid) self.service = service if service else self.lockdown.startService(self.serviceName) self.packet_num = 0 def stop_session(self): self.logger.info("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 if PY3 and isinstance(data, str): data = data.encode('utf-8') self.service.send(header + data) def receive_data(self): res = self.service.recv_exact(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: self.logger.error("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) data = self.receive_data() return data except: self.lockdown = LockdownClient() self.service = self.lockdown.startService(self.serviceName) return self.do_operation(opcode, data) def list_to_dict(self, d): if PY3: if type(d) != str: d = d.decode('utf-8') else: x =0 t = d.split("\x00") t = t[:-1] assert len(t) % 2 == 0 res = {} for i in xrange(int(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: if PY3: data = data.decode('utf-8') return [x for x in data.split("\x00") if x != ""] 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": self.logger.info("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: self.logger.info("%s/%s", 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): if PY3: linkname = linkname.encode('utf-8') separator = b"\x00" else: separator = "\x00" status, data = self.do_operation(AFC_OP_MAKE_LINK, struct.pack("<Q", type) + target + separator + linkname + separator) self.logger.info("make_link: %s", status) return status def file_open(self, filename, mode=AFC_FOPEN_RDONLY): if PY3: filename = filename.encode('utf-8') separator = b"\x00" else: separator = "\x00" status, data = self.do_operation(AFC_OP_FILE_OPEN, struct.pack("<Q", mode) + filename + separator) 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): if PY3: filename = filename.encode('utf-8') separator = b"\x00" else: separator = "\x00" status, data = self.do_operation(AFC_OP_REMOVE_PATH, filename + separator) return status def file_rename(self, old, new): if PY3: old = old.encode('utf-8') new = new.encode('utf-8') separator = b"\x00" else: separator = "\x00" status, data = self.do_operation(AFC_OP_RENAME_PATH, old + separator + new + separator) return status def file_read(self, handle, sz): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: print(str( (len(data) / full_size ) * 100 ) + "\r") 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 file_read_v2(self, handle, sz, local_file): MAXIMUM_READ_SIZE = 1 << 16 full_size = sz data = "" if PY3: data = b"" while sz > 0: with open(local_file, "ab") as local_file_handle: 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() local_file_handle.write(d) 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 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 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 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': self.logger.info("%s is directory...", filename) return self.logger.info("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 get_file_contents_v2(self, filename, local_file): info = self.get_file_info(filename) if info: if info['st_ifmt'] == 'S_IFLNK': filename = info['LinkTarget'] if info['st_ifmt'] == 'S_IFDIR': self.logger.info("%s is directory...", filename) return self.logger.info("Reading: %s", filename) h = self.file_open(filename) if not h: return self.file_read_v2(h, int(info["st_size"]), local_file) self.file_close(h) 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 PY3 and isinstance(fd, bytes): fd = fd.decode('utf-8') 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 def pull_file(self, remote_file, local_file): if not os.path.isfile(local_file): self.get_file_contents_v2(remote_file, local_file) def read_buffer(self, remote_file, size, local_file): x = 0 def download_file(self, remote_file, local_file): max_blocks = 102400 if not os.path.isfile(local_file): info = self.get_file_info(remote_file) if info['st_ifmt'] == 'S_IFLNK': remote_file = info['LinkTarget'] block_count = int(info['st_blocks']) if block_count > max_blocks: counter = max_blocks remaining_blocks = block_count while remaining_blocks > 0: num_blocks_to_read = min(max_blocks, remaining_blocks) handle = self.file_open(remote_file, num_blocks_to_read) try: self.dispatch_packet(AFC_OP_READ, struct.pack("<QQ", handle, 65536)) s, d = self.receive_data() except: import traceback traceback.print_exc() self.lockdown = LockdownClient() self.service = self.lockdown.startService("com.apple.afc2") def pull_directory(self, parent_dir, output): windows_reserved_names = ['CON', 'PRN', 'AUX', 'CLOCK$', 'NUL', 'COM1', 'LPT1', 'LPT2', 'LPT3', 'COM2', 'COM3', 'COM4'] for fd in self.read_directory(parent_dir): if PY3 and isinstance(fd, bytes): fd = fd.decode('utf-8') if fd in ('.', '..', ''): continue infos = self.get_file_info(posixpath.join(parent_dir, fd)) if infos and infos.get('st_ifmt') == 'S_IFDIR': if parent_dir == "/": if fd in windows_reserved_names: fd = fd + "_MEAT_RENAMED" new_folder = parent_dir + fd else: if fd in windows_reserved_names: fd = fd + "_MEAT_RENAMED" new_folder = parent_dir + '/' + fd new_folder = re.sub('[<>:"|?*]', '_', new_folder) local_folder = output + "\\" + new_folder.strip() if not os.path.exists(local_folder): self.logger.info("Creating Folder: " + new_folder) os.makedirs(local_folder) if new_folder is not '': self.pull_directory(new_folder, output) else: if parent_dir == "/": new_file = parent_dir + fd else: new_file = parent_dir + '/' + fd new_file = re.sub('[<>:"|?*]', '_', new_file) local_file = output + "\\" + new_file.strip() #self.download_file(new_file, local_file) parent_local_folder = (local_file[::-1].split("/")) local_single_file = parent_local_folder[0][::-1] del parent_local_folder[0] parent_local_folder = ("\\".join(parent_local_folder))[::-1] if parent_local_folder.endswith(' '): parent_local_folder = parent_local_folder[:-1] local_file = parent_local_folder + "\\" + local_single_file if not os.path.exists(parent_local_folder): os.makedirs(parent_local_folder) if infos is not None: if infos['st_size'] == '0': open(local_file, 'a').close() self.pull_file(new_file, local_file)
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) if not self.lockdown: raise Exception("Unable to start lockdown") self.start()