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: 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.start_service(self.serviceName) self.file_write(handle, data) return s
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.start_service("com.apple.afc") return self.file_read(handle, sz) if s != AFC_E_SUCCESS: break sz -= toRead data += d return data
def do_operation(self, opcode, data=""): try: self.dispatch_packet(opcode, data) return self.receive_data() except Exception as E: print(E) self.lockdown = LockdownClient() self.service = self.lockdown.start_service(self.serviceName) return self.do_operation(opcode, data)
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.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.start_service(serviceName) DLMessageVersionExchange = self.service.recv_plist() version_major = DLMessageVersionExchange[1] self.service.send_plist(["DLMessageVersionExchange", "DLVersionsOk", version_major]) DLMessageDeviceReady = self.service.recv_plist()
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.start_service( 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, 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()
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.service = self.lockdown.start_service( "com.apple.springboardservices")
screen_data = res[1]['ScreenShotData'] else: screen_data = res[1]['ScreenShotData'].data return screen_data return None if __name__ == '__main__': parser = OptionParser(usage='%prog') parser.add_option("-u", "--udid", default=False, action="store", dest="device_udid", metavar="DEVICE_UDID", help="Device udid") parser.add_option('-p', '--path', dest='outDir', default=False, help='Output Directory (default: . )', type='string') (options, args) = parser.parse_args() outPath = '.' if options.outDir: outPath = options.outDir logging.basicConfig(level=logging.INFO) lckdn = LockdownClient(options.device_udid) screenshotr = screenshotr(lockdown=lckdn) data = screenshotr.take_screenshot() if data: filename = strftime('screenshot-%Y-%m-%d-%H-%M-%S.png', gmtime()) outPath = os.path.join(outPath, filename) print('Saving Screenshot at %s' % outPath) o = open(outPath, 'wb') o.write(data)
(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.start_service("com.apple.pcapd") while True: d = pcap.recv_plist() 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") else:
def run(self) -> None: def _callback(res): self.callback(get_auxiliary_text(res.raw)) lock_down = LockdownClient(udid=self.device_id) installation = InstallationProxy(lockdown=lock_down) app_info = installation.find_bundle_id(self.bundle_id) if not app_info: raise Exception("No app matches", self.bundle_id) logging.info("BundleID: %s", self.bundle_id) logging.info("DeviceIdentifier: %s", lock_down.device_info.get('UniqueDeviceID')) sign_identity = app_info.get("SignerIdentity", "") logging.info("SignIdentity: %r", sign_identity) xcode_version = 29 session_identifier = NSUUID('96508379-4d3b-4010-87d1-6483300a7b76') manager_lock_down_1 = TestManagerdLockdown(lock_down).init() manager_lock_down_1._make_channel( "dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface" ) if lock_down.ios_version > LooseVersion('11.0'): result = manager_lock_down_1.call( "dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface", "_IDE_initiateControlSessionWithProtocolVersion:", DTXServerRPCRawObj(xcode_version)).parsed logging.info("result: %s", result) manager_lock_down_1.register_callback(DTXEnum.FINISHED, lambda _: self.quit_event.set()) manager_lock_down_1.register_unhandled_callback(_callback) manager_lock_down_2 = TestManagerdLockdown(lock_down).init() manager_lock_down_2._make_channel( "dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface" ) manager_lock_down_2.register_callback(DTXEnum.FINISHED, lambda _: self.quit_event.set()) manager_lock_down_2.register_unhandled_callback(_callback) _start_flag = threading.Event() def _start_executing(res=None): if _start_flag.is_set(): return _start_flag.set() logging.info( " _start_executing Start execute test plan with IDE version: %d", xcode_version) manager_lock_down_2._call( False, 0xFFFFFFFF, '_IDE_startExecutingTestPlanWithProtocolVersion:', DTXServerRPCRawObj(xcode_version)) def _show_log_message(res): logging.info(f"{res.parsed} : {get_auxiliary_text(res.raw)}") if 'Received test runner ready reply with error: (null' in ''.join( get_auxiliary_text(res.raw)): logging.info("_start_executing Test runner ready detected") _start_executing() manager_lock_down_2.register_callback( '_XCT_testBundleReadyWithProtocolVersion:minimumVersion:', _start_executing) manager_lock_down_2.register_callback('_XCT_logDebugMessage:', _show_log_message) manager_lock_down_2.register_callback( '_XCT_didFinishExecutingTestPlan', lambda _: self.quit_event.set()) result = manager_lock_down_2.call( 'dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface', '_IDE_initiateSessionWithIdentifier:forClient:atPath:protocolVersion:', DTXServerRPCRawObj( session_identifier, str(session_identifier) + '-6722-000247F15966B083', '/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild', xcode_version)).parsed logging.info("_start_executing result: %s", result) # launch_wda xctest_path = "/tmp/WebDriverAgentRunner-" + str( session_identifier).upper() + ".xctestconfiguration" xctest_content = archive( XCTestConfiguration({ "testBundleURL": NSURL( None, "file://" + app_info['Path'] + "/PlugIns/WebDriverAgentRunner.xctest"), "sessionIdentifier": session_identifier, })) fsync = HouseArrestClient(udid=self.device_id) fsync.send_command(self.bundle_id) for fname in fsync.read_directory("/tmp"): if fname.endswith(".xctestconfiguration"): logging.debug("remove /tmp/%s", fname) fsync.file_remove("/tmp/" + fname) fsync.set_file_contents(xctest_path, xctest_content) conn = InstrumentServer(lock_down).init() conn.call('com.apple.instruments.server.services.processcontrol', 'processIdentifierForBundleIdentifier:', self.bundle_id) conn.register_unhandled_callback(_callback) app_path = app_info['Path'] app_container = app_info['Container'] xctestconfiguration_path = app_container + xctest_path logging.info("AppPath: %s", app_path) logging.info("AppContainer: %s", app_container) app_env = { 'CA_ASSERT_MAIN_THREAD_TRANSACTIONS': '0', 'CA_DEBUG_TRANSACTIONS': '0', 'DYLD_FRAMEWORK_PATH': app_path + '/Frameworks:', 'DYLD_LIBRARY_PATH': app_path + '/Frameworks', 'NSUnbufferedIO': 'YES', 'SQLITE_ENABLE_THREAD_ASSERTIONS': '1', 'WDA_PRODUCT_BUNDLE_IDENTIFIER': '', 'XCTestConfigurationFilePath': xctestconfiguration_path, 'XCODE_DBG_XPC_EXCLUSIONS': 'com.apple.dt.xctestSymbolicator', 'MJPEG_SERVER_PORT': '', 'USE_PORT': '', } if self.app_env: app_env.update(self.app_env) if lock_down.ios_version > LooseVersion('11.0'): app_env[ 'DYLD_INSERT_LIBRARIES'] = '/Developer/usr/lib/libMainThreadChecker.dylib' app_env['OS_ACTIVITY_DT_MODE'] = 'YES' app_options = {'StartSuspendedKey': False} if lock_down.ios_version > LooseVersion('12.0'): app_options['ActivateSuspended'] = True app_args = [ '-NSTreatUnknownArgumentsAsOpen', 'NO', '-ApplePersistenceIgnoreState', 'YES' ] identifier = "launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:" pid = conn.call('com.apple.instruments.server.services.processcontrol', identifier, app_path, self.bundle_id, app_env, app_args, app_options).parsed if not isinstance(pid, int): logging.error(f"Launch failed: {pid}") raise Exception("Launch failed") logging.info(f" Launch {self.bundle_id} pid: {pid}") conn.call('com.apple.instruments.server.services.processcontrol', "startObservingPid:", DTXServerRPCRawObj(pid)) if self.quit_event: conn.register_callback(DTXEnum.FINISHED, lambda _: self.quit_event.set()) if lock_down.ios_version > LooseVersion('12.0'): identifier = '_IDE_authorizeTestSessionWithProcessID:' result = manager_lock_down_1.call( 'dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface', identifier, DTXServerRPCRawObj(pid)).parsed logging.info("_IDE_authorizeTestSessionWithProcessID: %s", result) else: identifier = '_IDE_initiateControlSessionForTestProcessID:protocolVersion:' result = manager_lock_down_1.call( 'dtxproxy:XCTestManager_IDEInterface:XCTestManager_DaemonConnectionInterface', identifier, DTXServerRPCRawObj(pid, xcode_version)).parsed logging.info("_IDE_authorizeTestSessionWithProcessID: %s", result) while not self.quit_event.wait(.1): pass logging.warning("xctrunner quited") conn.stop() manager_lock_down_2.stop() manager_lock_down_1.stop()
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.start_service("com.apple.mobile.MCInstall")
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.start_service("com.apple.syslog_relay")
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.start_service( 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.sock.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) return self.receive_data() except Exception as E: print(E) self.lockdown = LockdownClient() self.service = self.lockdown.start_service(self.serviceName) return self.do_operation(opcode, data) def list_to_dict(self, d): if PY3: d = d.decode('utf-8') t = d.split("\x00") t = t[:-1] assert len(t) % 2 == 0 res = {} for i in range(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 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.start_service("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 = 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: 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.start_service(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 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 __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.crash_server = AFCCrashLog(lockdown=self.lockdown)