diff --git a/objection/__init__.py b/objection/__init__.py index 5924159f..4ae4a189 100644 --- a/objection/__init__.py +++ b/objection/__init__.py @@ -1,6 +1,6 @@ import sys -__version__ = '1.11.0' +__version__ = '1.11.1' # helper containing a python 3 related warning # if this is run with python 2 diff --git a/objection/commands/device.py b/objection/commands/device.py index 31c3a8c1..8b8a8363 100644 --- a/objection/commands/device.py +++ b/objection/commands/device.py @@ -2,7 +2,7 @@ from tabulate import tabulate from ..state.connection import state_connection -from ..state.device import device_state, Android, Ios +from ..state.device import device_state, Android, Ios, Macos def get_environment(args: list = None) -> None: @@ -22,6 +22,9 @@ def get_environment(args: list = None) -> None: if device_state.platform == Android: _get_android_environment() + if device_state.platform == Macos: + _get_macos_environment() + def _get_ios_environment() -> None: """ @@ -51,3 +54,20 @@ def _get_android_environment() -> None: click.secho('') click.secho(tabulate(paths.items(), headers=['Name', 'Path'])) + + +def _get_macos_environment() -> None: + """ + Prints information about the macOS environment. + + This includes the current OS version as well as directories + of interest for the current applications Documents, Library and + main application bundle. + + :return: + """ + + paths = state_connection.get_api().env_ios_paths() + + click.secho('') + click.secho(tabulate(paths.items(), headers=['Name', 'Path'])) diff --git a/objection/console/cli.py b/objection/console/cli.py index 8b0c9ed2..9f6efc20 100644 --- a/objection/console/cli.py +++ b/objection/console/cli.py @@ -39,6 +39,8 @@ def get_agent() -> Agent: @click.group() @click.option('--network', '-N', is_flag=True, help='Connect using a network connection instead of USB.', show_default=True) +@click.option('--desktop', '-D', is_flag=True, help='Connect using a local connection for desktop.', + show_default=True) @click.option('--host', '-h', default='127.0.0.1', show_default=True) @click.option('--port', '-p', required=False, default=27042, show_default=True) @click.option('--api-host', '-ah', default='127.0.0.1', show_default=True) @@ -53,7 +55,7 @@ def get_agent() -> Agent: @click.option('--foremost', '-f', required=False, is_flag=True, help='Use the current foremost application.') @click.option('--debugger', required=False, default=False, is_flag=True, help='Enable the Chrome debug port.') @click.option('--uid', required=False, default=None, help='Specify the uid to run as (Android only).') -def cli(network: bool, host: str, port: int, api_host: str, api_port: int, +def cli(network: bool, desktop: bool, host: str, port: int, api_host: str, api_port: int, name: str, serial: str, debug: bool, spawn: bool, no_pause: bool, foremost: bool, debugger: bool, uid: int) -> None: """ @@ -79,6 +81,9 @@ def cli(network: bool, host: str, port: int, api_host: str, api_port: int, if serial: state_connection.device_id = serial + if desktop: + state_connection.use_desktop() + # set api parameters app_state.api_host = api_host app_state.api_port = api_port diff --git a/objection/console/commands.py b/objection/console/commands.py index 1326bd85..60930dac 100644 --- a/objection/console/commands.py +++ b/objection/console/commands.py @@ -499,7 +499,7 @@ }, }, # ios commands - 'ios': { + 'ios': { 'meta': 'Commands specific to iOS', 'commands': { 'info': { @@ -742,7 +742,215 @@ }, } }, - + # macos commands + 'macos': { + 'meta': 'Commands specific to iOS', + 'commands': { + 'info': { + 'meta': 'Get macOS and application related information', + 'commands': { + 'binary': { + 'meta': 'Get information about application binaries and dylibs', + 'exec': binary.info + } + } + }, + 'keychain': { + 'meta': 'Work with the macOS keychain', + 'commands': { + 'dump': { + 'meta': 'Dump the keychain for the current app\'s entitlement group', + 'flags': ['--json', '--smart'], + 'exec': keychain.dump + }, + 'dump_raw': { + 'meta': 'Dump raw, unprocessed keychain entries (advanced)', + 'exec': keychain.dump_raw + }, + 'clear': { + 'meta': 'Delete all keychain entries for the current app\'s entitlement group', + 'exec': keychain.clear + }, + 'add': { + 'meta': 'Add an entry to the iOS keychain', + 'flags': ['--account', '--service', '--data'], + 'exec': keychain.add + } + } + }, + 'plist': { + 'meta': 'Work with macOS Plists', + 'commands': { + 'cat': { + 'meta': 'Cat a plist', + 'dynamic': filemanager.list_files_in_current_fm_directory, + 'exec': plist.cat + } + } + }, + 'bundles': { + 'meta': 'Work with macOS Bundles', + 'commands': { + 'list_frameworks': { + 'meta': 'Lists all of the application\'s bundles that represent frameworks', + 'flags': ['--include-apple-frameworks', '--full-path'], + 'exec': bundles.show_frameworks + }, + 'list_bundles': { + 'meta': 'Lists all of the application\'s non framework bundles', + 'flags': ['--full-path'], + 'exec': bundles.show_bundles + } + } + }, + 'nsuserdefaults': { + 'meta': 'Work with NSUserDefaults', + 'commands': { + 'get': { + 'meta': 'Get all of the entries', + 'exec': nsuserdefaults.get + } + } + }, + 'nsurlcredentialstorage': { + 'meta': 'Work with the shared NSURLCredentialStorage', + 'commands': { + 'dump': { + 'meta': 'Dump all of the credentials in the shared NSURLCredentialStorage', + 'exec': nsurlcredentialstorage.dump + } + } + }, + 'cookies': { + 'meta': 'Work with shared cookies', + 'commands': { + 'get': { + 'meta': 'Get the current apps shared cookies', + 'flags': ['--json'], + 'exec': cookies.get + } + } + }, + 'heap': { + 'meta': 'Commands to work with the macOS heap', + 'commands': { + 'print': { + 'meta': 'Print information about objects on the iOS heap', + 'commands': { + 'ivars': { + 'meta': 'Print instance variables for an Objective-C object', + 'flags': ['--to-utf8'], + 'exec': ios_heap.ivars + }, + 'methods': { + 'meta': 'Print instance methods for an Objective-C object', + 'flags': ['--without-arguments'], + 'exec': ios_heap.methods + } + } + }, + 'search': { + 'meta': 'Search for information about the current macOS heap', + 'commands': { + 'instances': { + 'meta': 'Search for live instances of a particular class', + 'exec': ios_heap.instances + } + } + }, + 'execute': { + 'meta': 'Execute methods on objects on the macOS heap', + 'flags': ['--return-string'], + 'exec': ios_heap.execute + }, + 'evaluate': { + 'meta': 'Evaluate JavaScript on objects on the macOS heap', + 'flags': ['--inline'], + 'exec': ios_heap.evaluate + } + } + }, + 'hooking': { + 'meta': 'Commands used for hooking methods in iOS', + 'commands': { + 'list': { + 'meta': 'Lists various bits of information', + 'commands': { + 'classes': { + 'meta': 'List classes available in the current application', + 'exec': ios_hooking.show_ios_classes + }, + 'class_methods': { + 'meta': 'List the methods in a class', + 'flags': ['--include-parents'], + 'exec': ios_hooking.show_ios_class_methods + } + } + }, + 'watch': { + 'meta': 'Watch invocations of classes and methods', + 'exec': ios_hooking.watch, + 'flags': ['--dump-args', '--dump-backtrace', '--dump-return'], + }, + 'set': { + 'meta': 'Set various values', + 'commands': { + 'return_value': { + 'meta': 'Set a methods return value. Supports only boolean returns', + 'exec': ios_hooking.set_method_return_value + } + } + }, + 'search': { + 'meta': 'Search for various classes and or methods', + 'exec': ios_hooking.search, + 'flags': ['--json', '--only-classes'] + }, + 'generate': { + 'meta': 'Generate Frida hooks for macOS', + 'commands': { + 'class': { + 'meta': 'A generic hook manager for Classes', + 'exec': ios_generate.clazz + }, + 'simple': { + 'meta': 'Simple hooks for each Class method', + 'exec': ios_generate.simple + } + }, + } + } + }, + 'pasteboard': { + 'meta': 'Work with the macOS pasteboard', + 'commands': { + 'monitor': { + 'meta': 'Monitor the macOS pasteboard', + 'exec': pasteboard.monitor + } + } + }, + 'sslpinning': { + 'meta': 'Work with macOS SSL pinning', + 'commands': { + 'disable': { + 'meta': 'Attempt to disable SSL pinning in various iOS libraries/classes', + 'flags': ['--quiet'], + 'exec': ios_pinning.ios_disable + } + } + }, + 'monitor': { + 'meta': 'Commands to work with macOS function monitoring', + 'commands': { + 'crypto': { + 'meta': 'Monitor CommonCrypto operations', + 'exec': ios_crypto.crypto_enable + } + }, + }, + } + }, 'exit': { 'meta': 'Exit', }, diff --git a/objection/state/connection.py b/objection/state/connection.py index 93929ac6..2dacc192 100644 --- a/objection/state/connection.py +++ b/objection/state/connection.py @@ -8,6 +8,7 @@ def __init__(self) -> None: """ self.network = False + self.desktop = False self.host = None self.port = None self.device_type = 'usb' @@ -43,6 +44,16 @@ def use_network(self) -> None: self.network = True self.device_type = 'remote' + def use_desktop(self) -> None: + """ + Sets the values required to have a Network connection. + + :return: + """ + + self.desktop = True + self.device_type = 'local' + def get_comms_type(self) -> int: """ Returns the currently configured connection type. diff --git a/objection/state/device.py b/objection/state/device.py index 46ee51af..5319414d 100644 --- a/objection/state/device.py +++ b/objection/state/device.py @@ -17,6 +17,13 @@ class Ios(Device): path_separator = '/' +class Macos(Device): + """ Represents macOS specific configurations. """ + + name = 'macos' + path_separator = '/' + + class DeviceState(object): """ A class representing the state of a device and its runtime. """ diff --git a/objection/utils/agent.py b/objection/utils/agent.py index 679df1e6..0b411fae 100644 --- a/objection/utils/agent.py +++ b/objection/utils/agent.py @@ -11,7 +11,7 @@ from objection.state.app import app_state from objection.state.connection import state_connection -from objection.state.device import device_state, Ios, Android +from objection.state.device import device_state, Ios, Android, Macos from objection.state.jobs import job_manager_state from objection.utils.helpers import debug_print @@ -288,7 +288,8 @@ def update_device_state(self): device_state.set_platform(Ios) elif params['os']['id'] == 'android': device_state.set_platform(Android) - + elif params['os']['id'] == 'macos': + device_state.set_platform(Macos) # set os version device_state.set_version(params['os']['version'])