예제 #1
0
def watch_class_method(args: list) -> None:
    """
        Starts an objection jon that hooks into a specific class method
        and reports on invocations.

        :param args:
        :return:
    """

    if len(clean_argument_flags(args)) <= 0:
        click.secho(('Usage: ios hooking watch method <selector> (eg: -[ClassName methodName:]) '
                     '(optional: --dump-backtrace) '
                     '(optional: --dump-args) '
                     '(optional: --dump-return)'), bold=True)
        return

    selector = args[0]
    argument_count = selector.count(':')

    runner = FridaRunner()
    runner.set_hook_with_data(ios_hook('hooking/watch-method'), selector=selector,
                              argument_count=argument_count,
                              dump_backtrace=_should_dump_backtrace(args),
                              dump_args=_should_dump_args(args),
                              dump_return=_should_dump_return_value(args))

    runner.run_as_job(name='watch-method', args=args)
예제 #2
0
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)
예제 #3
0
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')
예제 #4
0
def add(args: list) -> None:
    """
        Adds a new keychain entry to the keychain

        :param args:
        :return:
    """

    if not _has_minimum_flags_to_add_item(args):
        click.secho(
            'Usage: ios keychain add --key <key name> --data <entry data>',
            bold=True)
        return

    key = _get_flag_value(args, '--key')
    value = _get_flag_value(args, '--data')

    click.secho('Adding a new entry to the iOS keychain...', dim=True)
    click.secho('Key:       {0}'.format(key), dim=True)
    click.secho('Value:     {0}'.format(value), dim=True)

    runner = FridaRunner()
    runner.set_hook_with_data(ios_hook('keychain/add'))

    api = runner.rpc_exports()

    if api.add(key, value):
        click.secho('Successfully added the keychain item', fg='green')
        return

    click.secho('Failed to add the keychain item', fg='red')
예제 #5
0
def watch_class_method(args: list) -> None:
    """
        Starts an objection jon that hooks into a specific class method
        and reports on invocations.

        :param args:
        :return:
    """

    if len(args) <= 0:
        click.secho((
            'Usage: ios hooking watch method <selector>'
            ' (eg: -[ClassName methodName:]) (optional: --include-backtrace)'),
                    bold=True)
        return

    selector = args[0]

    runner = FridaRunner()
    runner.set_hook_with_data(
        ios_hook('hooking/watch-method'),
        selector=selector,
        include_backtrace=_should_include_backtrace(args))

    runner.run_as_job(name='watch-method')
예제 #6
0
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')
예제 #7
0
파일: hooking.py 프로젝트: zenzue/objection
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)
예제 #8
0
    def test_finds_and_compiles_ios_hooks_without_an_exception_handler(self):
        hook = ios_hook('filesystem/pwd', skip_trycatch=True)

        expected_output = """// Determines the current working directory, based
// on the main bundles path on the iOS device.

var NSBundle = ObjC.classes.NSBundle;
var BundleURL = NSBundle.mainBundle().bundlePath();

var response = {
    status: 'success',
    error_reason: NaN,
    type: 'current-working-directory',
    data: {
        cwd: BundleURL.toString()
    }
};

send(response);

// -- Sample Objective-C
//
// NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
"""

        self.assertEqual(hook, expected_output)
예제 #9
0
def watch_class_methods_var_returns(args: list) -> None:
    """
        Starts an objection jon that hooks into a specific all classes
        and methods and reports on invocations when specifi
        args and return values reached.

        :param args:
        :return:
    """

    if len(clean_argument_flags(args)) <= 0:
        click.secho(('Usage: ios hooking watch var_and_returns <classPattern> <methodPattern> <argsPattern> <returnPattern> (eg: Controller login [email protected] false) '
                     '(optional: --dump-backtrace) '
                     '(optional: --dump-args) '
                     '(optional: --dump-return)'), bold=True)
        return

    classes_Pattern = args[0]
    methods_Pattern = args[1]
    args_Pattern = args[2]
    returns_Pattern = args[3]

    runner = FridaRunner()
    runner.set_hook_with_data(ios_hook('hooking/watch-class-methods-var-returns'),
                              classes_Pattern=classes_Pattern,
                              methods_Pattern=methods_Pattern,
                              args_Pattern=args_Pattern,
                              returns_Pattern=returns_Pattern,
                              dump_backtrace=_should_dump_backtrace(args),
                              dump_args=_should_dump_args(args),
                              dump_return=_should_dump_return_value(args))

    runner.run_as_job(name='watch-class-methods-var-returns', args=args)
예제 #10
0
    def test_finds_and_compiles_ios_hooks_with_an_exception_handler(self):
        hook = ios_hook('filesystem/pwd')

        expected_output = """if (ObjC.available) {

    try {

        // Determines the current working directory, based
// on the main bundles path on the iOS device.

var NSBundle = ObjC.classes.NSBundle;
var BundleURL = NSBundle.mainBundle().bundlePath();

var response = {
    status: 'success',
    error_reason: NaN,
    type: 'current-working-directory',
    data: {
        cwd: BundleURL.toString()
    }
};

send(response);

// -- Sample Objective-C
//
// NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];


    } catch (err) {

        var response = {
            status: 'error',
            error_reason: err.message,
            type: 'global-exception',
            data: {}
        };

        send(response);
    }

} else {

    var response = {
        status: 'error',
        error_reason: 'Objective-C runtime is not available.',
        type: 'global-exception',
        data: {}
    };

    send(response);
}
"""

        self.assertEqual(hook, expected_output)
예제 #11
0
def disable(args: list = None) -> None:
    """
        Attempts to disable jailbreak detection.

        :param args:
        :return:
    """

    hook = ios_hook('jailbreak/disable')

    runner = FridaRunner(hook=hook)
    runner.run_as_job(name='disable-jailbreak-detection')
예제 #12
0
def simulate(args: list = None) -> None:
    """
        Attempts to simulate a Jailbroken environment

        :param args:
        :return:
    """

    hook = ios_hook('jailbreak/simulate')

    runner = FridaRunner(hook=hook)
    runner.run_as_job(name='simulate-jailbroken-environment')
예제 #13
0
파일: keychain.py 프로젝트: zbx91/objection
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')
예제 #14
0
def monitor(args: list = None) -> None:
    """
        Starts a new objection job that monitors the iOS pasteboard
        and reports on new strings found.

        :param args:
        :return:
    """

    hook = ios_hook('pasteboard/monitor')

    runner = FridaRunner(hook=hook)
    runner.run_as_job(name='pasteboard-monitor')
예제 #15
0
def ios_disable(args: list = None) -> None:
    """
        Starts a new objection job that hooks common classes and functions,
        applying new logic in an attempt to bypass SSL pinning.

        :param args:
        :return:
    """

    hook = ios_hook('pinning/disable')

    runner = FridaRunner(hook=hook)
    runner.run_as_job(name='pinning-disable')
예제 #16
0
def ios_disable(args: list = None) -> None:
    """
        Starts a new objection job that hooks common classes and functions,
        applying new logic in an attempt to bypass SSL pinning.

        :param args:
        :return:
    """

    hook = ios_hook('pinning/disable')

    runner = FridaRunner()
    runner.set_hook_with_data(
        hook=hook,
        ignore_ios10_tls_helper=_should_ignore_ios10_tls_helper_hook(args),
        quiet=_should_be_quiet(args))
    runner.run_as_job(name='pinning-disable')
예제 #17
0
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)
예제 #18
0
파일: hooking.py 프로젝트: zenzue/objection
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
예제 #19
0
def dump_ios_method_args(args: list) -> None:
    """
        Starts an objection job that hooks into a class method and
        dumps the argument values as the method is invoked.

        :param args:
        :return:
    """

    # small helper method to reduce copy/paste code for the usage info
    def usage():
        click.secho(
            'Usage: ios hooking dump method_args <+/-> <class_name> <method_name>',
            bold=True)

    if len(args) < 3:
        usage()
        return

    class_instance = args[0]
    class_name = args[1]
    method_name = args[2]

    if class_instance not in ['-', '+']:
        click.secho(
            'Specify a class method (+) or instance method (-) with either a "+" or a "-"',
            fg='red')
        usage()
        return

    full_method = '{0}[{1} {2}]'.format(class_instance, class_name,
                                        method_name)
    argument_count = full_method.count(':')
    click.secho('Full method: {0} ({1} arguments)'.format(
        full_method, argument_count))

    # prepare a runner for the arg dump hook
    runner = FridaRunner()
    runner.set_hook_with_data(ios_hook('hooking/dump-arguments'),
                              method=full_method,
                              argument_count=argument_count)

    runner.run_as_job(name='dump-arguments')
예제 #20
0
파일: keychain.py 프로젝트: zbx91/objection
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')
예제 #21
0
파일: hooking.py 프로젝트: zenzue/objection
def watch_class(args: list) -> None:
    """
        Starts an objection job that hooks into all of the methods
        available in a class and reports on invocations.

        :param args:
        :return:
    """

    if len(args) <= 0:
        click.secho('Usage: ios hooking watch class <class_name> (--include-parents)', bold=True)
        return

    class_name = args[0]

    runner = FridaRunner()
    runner.set_hook_with_data(
        ios_hook('hooking/watch-class-methods'),
        class_name=class_name, include_parents=_should_include_parent_methods(args))

    runner.run_as_job(name='watch-class-methods')
예제 #22
0
파일: hooking.py 프로젝트: zenzue/objection
def set_method_return_value(args: list) -> None:
    """
        Make an Objective-C method return a specific boolean
        value, always.

        :param args:
        :return:
    """

    if len(args) < 2:
        click.secho('Usage: ios hooking set_method_return "<selector>" (eg: "-[ClassName methodName:]") <true/false>',
                    bold=True)
        return

    selector = args[0]
    retval = args[1]

    runner = FridaRunner()
    runner.set_hook_with_data(
        ios_hook('hooking/set-return'), selector=selector, retval=_string_is_true(retval))

    runner.run_as_job(name='set-return-value')
예제 #23
0
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)
예제 #24
0
def dump(args: list = None) -> None:
    """
        Dumps credentials stored in NSURLCredentialStorage

        :param args:
        :return:
    """

    hook = ios_hook('nsurlcredentialstorage/dump')

    runner = FridaRunner(hook=hook)
    api = runner.rpc_exports()

    data = api.dump()

    runner.unload_script()

    if not data:
        click.secho('No credentials found using NSURLCredentialStorage')

    click.secho('')
    click.secho(tabulate(data, headers="keys"))
    click.secho('')
    click.secho('Found {count} credentials'.format(count=len(data)), bold=True)