コード例 #1
0
 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
コード例 #2
0
    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
コード例 #3
0
 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)
コード例 #4
0
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))
コード例 #5
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.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()
コード例 #6
0
 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
コード例 #7
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
コード例 #8
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)
     if not self.lockdown:
         raise Exception("Unable to start lockdown")
     self.start()
コード例 #9
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)
     self.service = self.lockdown.start_service(
         "com.apple.springboardservices")
コード例 #10
0
                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)
コード例 #11
0
    (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:
コード例 #12
0
    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()
コード例 #13
0
 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")
コード例 #14
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)
     self.c = self.lockdown.start_service("com.apple.syslog_relay")
コード例 #15
0
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
コード例 #16
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)
     self.crash_server = AFCCrashLog(lockdown=self.lockdown)