def cat(args: list = None) -> None: """ Parses a plist on an iOS device and echoes it in a more human readable way. :param args: :return: """ if len(args) <= 0: click.secho('Usage: ios plist cat <remote_plist>', bold=True) return plist = args[0] if not os.path.isabs(plist): pwd = filemanager.pwd() plist = os.path.join(pwd, plist) runner = FridaRunner() runner.set_hook_with_data(ios_hook('plist/get'), plist=plist) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to get plist with error: {0}'.format( response.error_reason), fg='red') return click.secho(response.data, bold=True)
def show_ios_class_methods(args: list) -> None: """ Displays the methods available in a class. :param args: :return: """ if len(args) <= 0: click.secho('Usage: ios hooking list class_methods <class name> (--include-parents)', bold=True) return classname = args[0] runner = FridaRunner() runner.set_hook_with_data( ios_hook('hooking/list-class-methods'), classname=classname, include_parents=_should_include_parent_methods(args)) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list classes with error: {0}'.format(response.error_reason), fg='red') return None # dump the methods to screen for method in response.data: click.secho(method)
def entries(args: list = None) -> None: """ Lists entries in the Android KeyStore :param args: :return: """ runner = FridaRunner() runner.set_hook_with_data(android_hook('keystore/list')) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list KeyStore items with error: {0}'.format( response.error_reason), fg='red') return None if not response.data: click.secho('No keystore items were found', fg='yellow') return None output = [[x['alias'], x['is_key'], x['is_certificate']] for x in response.data] click.secho(tabulate(output, headers=['Alias', 'Is Key', 'Is Certificate']))
def execute(args: list) -> None: """ Runs a shell command on an Android device. :param args: :return: """ command = ' '.join(args) click.secho('Running command: {0}\n'.format(command), dim=True) runner = FridaRunner() runner.set_hook_with_data(android_hook('command/exec'), command=command) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to run command with error: {0}'.format( response.error_reason), fg='red') return if response.stdout: click.secho(response.stdout, bold=True) if response.stderr: click.secho(response.stderr, bold=True, fg='red')
def search_class(args: list) -> None: """ Searching for Objective-C classes in the current application by name. :param args: :return: """ if len(clean_argument_flags(args)) < 1: click.secho('Usage: ios hooking search classes <name>', bold=True) return search = args[0] runner = FridaRunner() runner.set_hook_with_data(ios_hook('hooking/search-class'), search=search) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to search for classes with error: {0}'.format(response.error_reason), fg='red') return None if response.data: # dump the classes to screen for classname in response.data: click.secho(classname) click.secho('\nFound {0} classes'.format(len(response.data)), bold=True) else: click.secho('No classes found')
def search_method(args: list) -> None: """ Search for Objective-C methods by name. :param args: :return: """ if len(clean_argument_flags(args)) < 1: click.secho('Usage: ios hooking search methods <name>', bold=True) return search = args[0] runner = FridaRunner() runner.set_hook_with_data(ios_hook('hooking/search-method'), search=search) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to search for methods with error: {0}'.format(response.error_reason), fg='red') return None if response.data: # dump the methods to screen for method in response.data: click.secho(method) click.secho('\nFound {0} methods'.format(len(response.data)), bold=True) else: click.secho('No methods found')
def search_class(args: list) -> None: """ Searches the current Android application for instances of a class. :param args: :return: """ if len(args) < 1: click.secho('Usage: android hooking search classes <name>', bold=True) return search = args[0] runner = FridaRunner() runner.set_hook_with_data(android_hook('hooking/search-class'), search=search) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to search for classes with error: {0}'.format(response.error_reason), fg='red') return None if response.data: # dump the classes to screen for classname in response.data: click.secho(classname) click.secho('\nFound {0} classes'.format(len(response.data)), bold=True) else: click.secho('No classes found')
def show_android_classes(args: list = None) -> None: """ Show the currently loaded classes. :param args: :return: """ hook = android_hook('hooking/list-classes') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list classes with error: {0}'.format( response.error_reason), fg='red') return None # print the enumerated classes for class_name in sorted(response.data): click.secho(class_name) click.secho('\nFound {0} classes'.format(len(response.data)), bold=True)
def var_class(args: list) -> None: search = str(search) if len(search) == 0: click.secho('Usage: android hooking search classes <name>', bold=True) return runner = FridaRunner() runner.set_hook_with_data(android_hook('hooking/search-class'), search=search) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to search for classes with error: {0}'.format( response.error_reason), fg='red') return None if response.data: # dump the classes to screen for classname in response.data: click.secho(classname) click.secho('\nFound {0} classes'.format(len(response.data)), bold=True) else: click.secho('No classes found')
def show_registered_activities(args: list = None) -> None: """ Enumerate all registered Activities :param args: :return: """ hook = android_hook('hooking/list-activities') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list activities with error: {0}'.format( response.error_reason), fg='red') return None if not response.data: click.secho('No activities were found', fg='yellow') return None for class_name in sorted(response.data): click.secho(class_name) click.secho('\nFound {0} classes'.format(len(response.data)), bold=True)
def show_android_class_methods(args: list = None) -> None: """ Shows the methods available on an Android class. :param args: :return: """ if len(clean_argument_flags(args)) <= 0: click.secho('Usage: android hooking list class_methods <class name>', bold=True) return class_name = args[0] runner = FridaRunner() runner.set_hook_with_data(android_hook('hooking/list-class-methods'), class_name=class_name) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list class methods with error: {0}'.format( response.error_reason), fg='red') return None # print the enumerated classes for class_name in sorted(response.data): click.secho(class_name) click.secho('\nFound {0} method(s)'.format(len(response.data)), bold=True)
def dump(args: list = None) -> None: """ Dump the iOS keychain :param args: :return: """ if _should_output_json(args) and len(args) < 2: click.secho('Usage: ios keychain dump (--json <local destination>)', bold=True) return click.secho('Note: You may be asked to authenticate using the devices passcode or TouchID') if not _should_output_json(args): click.secho('Get all of the attributes by adding `--json keychain.json` to this command', dim=True) click.secho('Reading the iOS keychain...', dim=True) hook = ios_hook('keychain/dump') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to get keychain items with error: {0}'.format(response.error_message), fg='red') return if _should_output_json(args): destination = args[1] click.secho('Writing full keychain as json to {0}...'.format(destination), dim=True) with open(destination, 'w') as f: f.write(json.dumps(response.data, indent=2)) click.secho('Dumped full keychain to: {0}'.format(destination), fg='green') return # refer to hooks/ios/keychain/dump.js for a key,value reference data = [] if response.data: for entry in response.data: data.append([entry['item_class'], entry['account'], entry['service'], entry['generic'], entry['data'], ]) click.secho('') click.secho(tabulate(data, headers=['Class', 'Account', 'Service', 'Generic', 'Data'])) else: click.secho('No keychain data could be found', fg='yellow')
def get(args: list) -> None: """ Gets cookies using the iOS NSHTTPCookieStorage sharedHTTPCookieStorage and prints them to the screen. :param args: :return: """ hook = ios_hook('binarycookie/get') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to get cookies with error: {0}'.format( response.error_reason), fg='red') return if not response.data: click.secho('No cookies found') return if _should_dump_json(args): print(json.dumps(response.data, indent=4)) return data = [] for cookie in response.data: data.append([ cookie['name'], cookie['value'], cookie['expiresDate'], cookie['domain'], cookie['path'], cookie['isSecure'], cookie['isHTTPOnly'] ]) click.secho(tabulate(data, headers=[ 'Name', 'Value', 'Expires', 'Domain', 'Path', 'Secure', 'HTTPOnly' ]), bold=True)
def _get_ios_classes() -> list: """ Gets a list of all of the classes available in the current Objective-C runtime. :return: """ hook = ios_hook('hooking/list-classes') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to list classes with error: {0}'.format(response.error_reason), fg='red') return None return response.data
def launch_service(args: list) -> None: """ Launches an exported service using an Android Intent :param args: :return: """ if len(args) < 1: click.secho('Usage: android intent launch_service <service_class>', bold=True) return intent_class = args[0] click.secho('Launching Service: {0}...'.format(intent_class), dim=True) runner = FridaRunner() runner.set_hook_with_data(android_hook('intent/start-service'), intent_class=intent_class) runner.run()
def launch_activity(args: list) -> None: """ Launces an activity class using an Android Intent :param args: :return: """ if len(args) < 1: click.secho('Usage: android intent launch_activity <activity_class>', bold=True) return intent_class = args[0] click.secho('Launching Activity: {0}...'.format(intent_class), dim=True) runner = FridaRunner() runner.set_hook_with_data(android_hook('intent/start-activity'), intent_class=intent_class) runner.run()
def clear(args: list = None) -> None: """ Clear the iOS keychain. :param args: :return: """ click.secho('Clearing the keychain...', dim=True) hook = ios_hook('keychain/clear') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to clear keychain items with error: {0}'.format(response.error_message), fg='red') return click.secho('Keychain cleared', fg='green')
def clear(args: list = None) -> None: """ Clears out an Android KeyStore :param args: :return: """ runner = FridaRunner() runner.set_hook_with_data(android_hook('keystore/clear')) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to clear the KeyStore error: {0}'.format( response.error_reason), fg='red') return None click.secho('Cleared the KeyStore', fg='green')
def get(args: list = None) -> None: """ Gets all of the values stored in NSUserDefaults and prints them to screen. :param args: :return: """ hook = ios_hook('nsuserdefaults/get') runner = FridaRunner(hook=hook) runner.run() response = runner.get_last_message() if not response.is_successful(): click.secho('Failed to get nsuserdefaults with error: {0}'.format( response.error_reason), fg='red') return click.secho(response.data, bold=True)