def set_device(self): """ Set's the target device to work with. :return: """ if self.config.device_id is not None: self.device = frida.get_device(self.config.device_id) elif (self.config.host is not None) or (self.config.device_type == 'remote'): if self.config.host is None: self.device = frida.get_remote_device() else: host = self.config.host port = self.config.port self.device = frida.get_device_manager() \ .add_remote_device(f'{host}:{port}' if host is not None else f'127.0.0.1:{port}') elif self.config.device_type is not None: for dev in frida.enumerate_devices(): if dev.type == self.config.device_type: self.device = dev else: self.device = frida.get_local_device() # surely we have a device by now? if self.device is None: raise Exception('Unable to find a device') self.device.on('output', self.handlers.device_output) self.device.on('lost', self.handlers.device_lost) debug_print(f'device determined as: {self.device}')
def _prepare_source(self): """ Prepares the self.script_src attribute based on a few rules. If the script source is already set, simply return as there is nothing for us to do. If the script path is set, read that and populate the script_src attribute. If neither script_src not script_path is set, attempt to read the index.js that lives next to the plugin file. If all of the above fail, simply return, writing a debug warning no script source could be found. :return: """ if self.script_src: return if self.script_path: self.script_path = os.path.abspath(self.script_path) with open(self.script_path, 'r', encoding='utf-8') as f: self.script_src = '\n'.join(f.readlines()) return possible_src = os.path.abspath(os.path.join( os.path.abspath(os.path.dirname(self.plugin_file)), 'index.js')) if os.path.exists(possible_src): self.script_path = possible_src with open(self.script_path, 'r', encoding='utf-8') as f: self.script_src = '\n'.join(f.readlines()) return debug_print('[warning] No Fridascript could be found for plugin {0}'.format(self.namespace))
def __init__(self, config: AgentConfig): """ initialises the agent class """ self.agent_path = Path(__file__).parent.parent / 'agent.js' if not self.agent_path.exists(): raise Exception( f'Unable to locate Objection agent sources at: {self.agent_path}. ' 'If this is a development install, check the wiki for more ' 'information on building the agent.') debug_print('Agent path is: {path}'.format(path=self.agent_path)) self.config = config debug_print(f'agent config: {self.config}') self.handlers = OutputHandlers() atexit.register(self.teardown)
def set_target_pid(self): """ Set's the PID we should attach to. This method will spawn the target if needed. The resumed value is also toggled here. Defaults: resumed: bool = True :return: """ if (self.config.name is None) and (not self.config.foremost): raise Exception('Need a target name to spawn/attach to') if self.config.foremost: try: app = self.device.get_frontmost_application() except Exception as e: raise Exception( f'Could not get foremost application on {self.device.name}: {e}' ) if app is None: raise Exception( f'No foremost application on {self.device.name}') self.pid = app.pid # update the global state for the prompt etc. state_connection.name = app.identifier elif self.config.spawn: self.pid = self.device.spawn(self.config.name) self.resumed = False else: # check if the name is actually an integer. this way we can # assume we got the target PID already try: self.pid = int(self.config.name) except ValueError: pass if self.pid is None: # last resort, maybe we have a process name self.pid = self.device.get_process(self.config.name).pid debug_print(f'process PID determined as {self.pid}')
def run(self): """ Run the Agent by getting a device, setting the target pid and attaching. If we should skip pausing, also resume the process. :return: """ self.set_device() self.set_target_pid() self.attach() # internal state self.update_device_state() if not self.config.pause: debug_print('asked to run without pausing, so resuming in run()') self.resume()
def start(plugin_folder: str, quiet: bool, startup_command: str, file_commands, startup_script: click.File, enable_api: bool) -> None: """ Start a new session """ agent = get_agent() state_connection.set_agent(agent) # load plugins if plugin_folder: folder = Path(plugin_folder).resolve() debug_print(f'[plugin] Plugins path is: {folder}') for p in folder.iterdir(): if p.is_file() or p.name.startswith('.'): debug_print(f'[plugin] Skipping {p.name}') continue debug_print(f'[plugin] Attempting to load plugin at {p}') load_plugin([p]) repl = Repl() if startup_script: click.secho( f'Importing and running startup script at: {startup_script}', dim=True) agent.attach_script(startup_script.read()) if startup_command: for command in startup_command: click.secho(f'Running a startup command... {command}', dim=True) repl.run_command(command) if file_commands: click.secho('Running commands from file...', bold=True) for command in file_commands.readlines(): command = command.strip() if command == '': continue # run the command using the instantiated repl click.secho(f'Running: \'{command}\':\n', dim=True) repl.run_command(command) warn_about_older_operating_systems() # start the api server if enable_api: def api_thread(): """ Small method to run Flask non-blocking """ api_state.start(app_state.api_host, app_state.api_port) click.secho( f'Starting API server on {app_state.api_host}:{app_state.api_port}', fg='yellow', bold=True) thread = threading.Thread(target=api_thread) thread.daemon = True thread.start() time.sleep(2) # drop into the repl repl.run(quiet=quiet)