def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) gateway_params = frida.EndpointParameters(port=8080) www = Path(__file__).parent.resolve() / "web_client" / "dist" self._service = frida.WebGatewayService(gateway_params, root=www)
def __init__(self): appdata_path = os.environ["appdata"] data_path = os.path.join(appdata_path,"winstrument") if not os.path.exists(data_path): os.mkdir(data_path) settings_path = os.path.join(data_path, "settings.toml") #unique temporary storage for each instance of the program self._db = DBConnection(os.path.join(data_path,f"db_{datetime.now().timestamp()}.sqlite3")) self.settings_controller = SettingsController(settings_path) default_settings = {'target': 'C:\\Windows\\System32\\Calc.exe' , "verbosity": 0} #settings won't exist on first run if self.settings_controller.get_module_settings(self.CORE_MODNAME) == {}: self.settings_controller.set_module_settings(self.CORE_MODNAME, default_settings) self.metadata = self.get_metadata() self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._base_module = importlib.import_module("winstrument.base_module",None) self._modules_to_load=[] self._available_modules = self._enumerate_modules() self._loaded_modules = [] self._instrumentations = []
def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) # self._device = frida.get_local_device() self._device = frida.get_usb_device() self._sessions = set() # self._device.on("delivered", lambda child: self._reactor.schedule(lambda: self._on_delivered(child))) self._device.on( "spawn-added", lambda child: self._reactor.schedule( lambda: self._on_delivered(child)))
def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) cluster_params = frida.EndpointParameters( address="unix:/Users/oleavr/src/cluster", certificate="/Users/oleavr/src/identity2.pem", authentication=('token', "wow-such-secret")) if ENABLE_CONTROL_INTERFACE: control_params = frida.EndpointParameters( address="::1", port=27042, certificate="/Users/oleavr/src/identity.pem", authentication=('callback', self._authenticate)) else: control_params = None service = frida.PortalService(cluster_params, control_params) self._service = service self._device = service.device self._peers = {} self._nicks = set() self._channels = {} service.on( 'node-connected', lambda *args: self._reactor.schedule( lambda: self._on_node_connected(*args))) service.on( 'node-joined', lambda *args: self._reactor.schedule( lambda: self._on_node_joined(*args))) service.on( 'node-left', lambda *args: self._reactor.schedule( lambda: self._on_node_left(*args))) service.on( 'node-disconnected', lambda *args: self._reactor.schedule( lambda: self._on_node_disconnected(*args))) service.on( 'controller-connected', lambda *args: self._reactor.schedule( lambda: self._on_controller_connected(*args))) service.on( 'controller-disconnected', lambda *args: self._reactor.schedule( lambda: self._on_controller_disconnected(*args))) service.on( 'authenticated', lambda *args: self._reactor.schedule( lambda: self._on_authenticated(*args))) service.on( 'subscribe', lambda *args: self._reactor.schedule( lambda: self._on_subscribe(*args))) service.on( 'message', lambda *args: self._reactor.schedule( lambda: self._on_message(*args)))
class Application(object): def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) gateway_params = frida.EndpointParameters(port=8080) www = Path(__file__).parent.resolve() / "web_client" / "dist" self._service = frida.WebGatewayService(gateway_params, root=www) def run(self): self._reactor.schedule(self._start) self._reactor.run() def _start(self): self._service.start() def _stop(self): self._service.stop() def _process_input(self, reactor): while True: try: command = input("Enter command: ").strip() except KeyboardInterrupt: self._reactor.cancel_io() return if command == "stop": self._reactor.schedule(self._stop) break
def __init__(self, nick): self._reactor = Reactor(run_until_return=self._process_input) token = { 'nick': nick, 'secret': "knock-knock" } self._device = frida.get_device_manager().add_remote_device("::1", certificate="/Users/oleavr/src/cert.pem", token=json.dumps(token)) self._bus = self._device.bus self._bus.on('message', lambda *args: self._reactor.schedule(lambda: self._on_bus_message(*args))) self._channel = None self._prompt = "> "
def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data)))
def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data)))
def __init__(self, argv, env): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_usb_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) self.argv = argv self.env = env self.output = [] # stdout will pushed into array
def __init__(self, config, logger_obj, api_watch_list): self.config = config self.logger = logger_obj self.api_watch_list = api_watch_list self.execution_timeout = self.config.get_execution_timeout() self.capture_basic_behavior = self.config.get_capture_behavior_report_basic_flag() self.capture_complete_behavior = self.config.get_capture_behavior_report_complete_flag() self.process_list = [] self.target_process_pid = None # Initialize Reporting Module self.report_generator = Reporting(config, logger_obj) # Initialize Queue for FriSpyGUI to receive the events self.event_queue_name = self.config.get_event_queue_name() self.msmqueue_event = MSMQCustom(self.event_queue_name) self.config_queue_name = self.config.get_config_queue_name() self.msmqueue_config = MSMQCustom(self.config_queue_name) # Initialize Controller self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() try: self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data))) self._device.on("process-crashed", lambda crash: self._reactor.schedule(lambda: self._on_process_crashed(crash))) self._device.on("lost", lambda crash: self._reactor.schedule(lambda: self._on_process_crashed(crash))) except Exception as e: self.logger.log("error", "Exception - FriSpyController : run : %s" %(str(e))) self.Controller_cleaup(None) sys.exit(1)
def __init__(self, path, filename, queue, num_skip_calls): import frida from frida_tools.application import Reactor self._logger = logging.getLogger(self.__class__.__name__) self.path = path self.filename = filename self.states = queue self.num_skip_calls = num_skip_calls self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._device.on("output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) # pylint: disable=undefined-variable self.output = io.StringIO() self._mallocs = 0 self._frees = 0 self._output_counter = 0
def test_basics(self): test_ui = TestUI() reactor = Reactor(lambda reactor: test_ui.on_result.wait()) def start(): d = Discoverer(reactor) d.start(self.session, test_ui) reactor.schedule(d.stop, 0.1) reactor.schedule(start) reactor.run() self.assertIsInstance(test_ui.module_functions, dict) self.assertIsInstance(test_ui.dynamic_functions, list)
def test_basics(self): done = threading.Event() reactor = Reactor(lambda reactor: done.wait()) def start(): tp = TracerProfileBuilder().include("open*") t = Tracer(reactor, MemoryRepository(), tp.build()) targets = t.start_trace(self.session, 'late', {}, 'qjs', UI()) t.stop() reactor.stop() done.set() reactor.schedule(start) reactor.run()
class Shell(object): def __init__(self, argv, env): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_usb_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) self.argv = argv self.env = env self.output = [] # stdout will pushed into array def exec(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): click.secho("✔ spawn(argv={})".format(self.argv), fg='green', dim=True) pid = self._device.spawn(self.argv, env=self.env, stdio='pipe') self._instrument(pid) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): click.secho("✔ attach(pid={})".format(pid), fg='green', dim=True) session = self._device.attach(pid) session.on( "detached", lambda reason: self._reactor.schedule(lambda: self._on_detached( pid, session, reason))) click.secho("✔ enable_child_gating()", fg='green', dim=True) session.enable_child_gating() # print("✔ resume(pid={})".format(pid)) self._device.resume(pid) self._sessions.add(session) def _on_child_added(self, child): click.secho("⚡ child_added: {}".format(child), fg='green', dim=True) self._instrument(child.pid) @staticmethod def _on_child_removed(child): click.secho("⚡ child_removed: {}".format(child), fg='green', dim=True) def _on_output(self, pid, fd, data): # print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) # fd=0 (input) fd=1(stdout) fd=2(stderr) if fd != 2: self.output.append(data) def _on_detached(self, pid, session, reason): click.secho("⚡ detached: pid={}, reason='{}'".format(pid, reason), fg='green', dim=True) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) @staticmethod def _on_message(pid, message): click.secho("⚡ message: pid={}, payload={}".format(pid, message), fg='green', dim=True)
class Application(object): def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): argv = ["/bin/sh", "-c", "cat /etc/hosts"] env = { "BADGER": "badger-badger-badger", "SNAKE": "mushroom-mushroom", } print("✔ spawn(argv={})".format(argv)) pid = self._device.spawn(argv, env=env, stdio='pipe') self._instrument(pid) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): print("✔ attach(pid={})".format(pid)) session = self._device.attach(pid) session.on( "detached", lambda reason: self._reactor.schedule(lambda: self._on_detached( pid, session, reason))) print("✔ enable_child_gating()") session.enable_child_gating() print("✔ create_script()") script = session.create_script("""\ Interceptor.attach(Module.getExportByName(null, 'open'), { onEnter: function (args) { send({ type: 'open', path: Memory.readUtf8String(args[0]) }); } }); """) script.on( "message", lambda message, data: self._reactor.schedule( lambda: self._on_message(pid, message))) print("✔ load()") script.load() print("✔ resume(pid={})".format(pid)) self._device.resume(pid) self._sessions.add(session) def _on_child_added(self, child): print("⚡ child_added: {}".format(child)) self._instrument(child.pid) def _on_child_removed(self, child): print("⚡ child_removed: {}".format(child)) def _on_output(self, pid, fd, data): print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) def _on_detached(self, pid, session, reason): print("⚡ detached: pid={}, reason='{}'".format(pid, reason)) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_message(self, pid, message): print("⚡ message: pid={}, payload={}".format(pid, message["payload"]))
class Winstrument(): #adapted from https://github.com/frida/frida-python/blob/master/examples/child_gating.py CORE_MODNAME = "core" def __init__(self): appdata_path = os.environ["appdata"] data_path = os.path.join(appdata_path,"winstrument") if not os.path.exists(data_path): os.mkdir(data_path) settings_path = os.path.join(data_path, "settings.toml") #unique temporary storage for each instance of the program self._db = DBConnection(os.path.join(data_path,f"db_{datetime.now().timestamp()}.sqlite3")) self.settings_controller = SettingsController(settings_path) default_settings = {'target': 'C:\\Windows\\System32\\Calc.exe' , "verbosity": 0} #settings won't exist on first run if self.settings_controller.get_module_settings(self.CORE_MODNAME) == {}: self.settings_controller.set_module_settings(self.CORE_MODNAME, default_settings) self.metadata = self.get_metadata() self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._base_module = importlib.import_module("winstrument.base_module",None) self._modules_to_load=[] self._available_modules = self._enumerate_modules() self._loaded_modules = [] self._instrumentations = [] def get_metadata(self, filename="metadata.toml"): """ Parse the metadata.toml file for module metadata like descriptions, if present. Returns dict of metadata, or None if the file is not present or invalid. """ metadata_filepath = os.path.join(os.path.dirname(__file__),"modules",filename) try: metadata = toml.load(metadata_filepath) return dict((k.lower(), v) for k,v in metadata.items()) #modulenames are lowercase except toml.TomlDecodeError: metadata = None return metadata def get_available_modules(self): """ Gets a list of all available modules (from modules/metadata.toml) returns a list with module names """ return self._available_modules.copy() def get_loaded_modules(self): """ Gets a list of all modules that have already been loaded returns a list of module names """ return [mod for mod in self._loaded_modules] def export_all(self, outfile, formatter=utils.format_table): """ Write the output for all modules to the given output stream in the desired format outfile - file stream object. This could be a normal file or sys.stdout formatter - callable which takes a list of ModuleMessage objects and returns a string to output. See utils.py No return, but writes the output stream """ for module in self.get_available_modules(): self.print_saved_output(module,formatter,outfile) def print_saved_output(self, modulename, formatter=utils.format_table, output=sys.stdout): """ Write the output for the given module to the given output stream in the desired format. modulename - str formatter - callable which takes a list of ModuleMessage objects and returns a string to output. See utils.py output - file stream object. This could be a normal file or sys.stdout No return, but writes the output stream """ messages = self._db.read_messages(modulename) if formatter is None: formatter = utils.format_table verbosity = self.settings_controller.get_setting_int(self.CORE_MODNAME,"verbosity") or 0 output.write(formatter(messages,verbosity)+"\n") def unload_module(self, module): """ Unloads the given module. It will not be injected with the target is run module - str """ try: self._modules_to_load.remove(module) self._loaded_modules.remove(module) except ValueError: print (f"Can't unload because {module} wasn't loaded") if module not in self._available_modules: self._available_modules.append(module) self._initialize_modules() def load_module(self, module): """ Loads the given module, if it hasn't already been loaded. modulename - str """ if module not in self._modules_to_load: self._modules_to_load.append(module) else: print(f"Error: {module} is already loaded") return self._initialize_modules() def _enumerate_modules(self,moudlepath="modules"): """ Returns a list of available modules. Uses metadata file if available, otherwise falls back to all modules in the modulepath """ if self.metadata: available_modules = [key.lower() for key in self.metadata.keys()] else: #metadata file missing or broken, fall back to module discovery based on path available_modules = [name for _, name, _, in pkgutil.iter_modules([os.path.join(os.path.dirname(__file__), moudlepath)])] return available_modules def _initialize_modules(self, modulepath = "winstrument.modules"): """ Import python modules that are set to be loaded. If the module is not found, print a warning to STDOUT and remove the module from the _modules_to_load list. modulepath: string - Python import path for modules. This is a Python path, not a Windows path. """ for modulename in self._modules_to_load: try: module = importlib.import_module(f"{modulepath}.{modulename}") if module not in self._loaded_modules: self._loaded_modules.append(modulename) except ImportError: print(f"Error: module '{modulename}' not found, skiping!") self._modules_to_load.remove(modulename) continue def run(self,target=None,arglist=None): """ Schedule frida to spawn the target process, then instrument it. target: str - path to target to spawn arglist: list - arguments to pass to target when spawned """ if target: process = target args = arglist else: process = self.settings_controller.get_setting(self.CORE_MODNAME,"target") args = self.settings_controller.get_setting(self.CORE_MODNAME,"args") self._reactor.schedule(lambda: self._start(process,args)) self._reactor.run() def _start(self,target,args=None): """ Spawn the target process and then instrument it with any available scripts. If not found, write a warning to STDERR. target: str - Path to the process to spawn args: list or None - list of command line arguments to use with the target """ if target is None: sys.stderr.write(f"{Fore.RED} No target set. Use 'set target <target> to specify a program to instrument.\n{Style.RESET_ALL}") self.stop() return cmd = [target] if args: cmd.append(args) try: pid = self._device.spawn(cmd) except frida.ExecutableNotFoundError: sys.stderr.write(f"{Fore.RED}Target {target} not found! Make sure the path is correct.\n{Style.RESET_ALL}") self.stop() return print("Spawned " + str(pid)) self._instrument(pid, target) def _stop_if_idle(self): """ Helper function used with Frida reactor. Stops the reactor if there are no queued child sessions. """ if len(self._sessions) == 0: self.stop() def stop(self): """ Signal that the Frida reactor has been requested to stop, then stop it. """ self._stop_requested.set() self._reactor.stop() def quit(self): """ Save settings to settings file. """ self.settings_controller.save_settings() self._db.close() def _instrument(self, pid, path): """ Iterates over currently loaded modules and performs instrumentation on the target process for each. pid: int - PID of the spawned process path: str - filesystem path to the spawned process executable. """ try: session = self._device.attach(pid) except frida.TransportError as e: sys.stderr.write(f"{Fore.RED} Got exception {repr(e)} when attaching to {pid}\n{Style.RESET_ALL}") return session.on('detached',lambda reason: self._reactor.schedule(lambda: self._on_detach(pid, session, reason))) session.enable_child_gating() #pause child processes until manually resumed for moduleclass in self._base_module.BaseInstrumentation.__subclasses__(): if moduleclass.modulename in self._loaded_modules: # module might have been unloaded by user instrumentation = moduleclass(session, path, self._db) self._instrumentations.append(instrumentation) instrumentation.load_script() print(f"instrumented process with pid: {pid} and path: {path}") self._device.resume(pid) self._sessions.add(session) def _on_detach(self, pid, session, reason): """ Callback called when the Frdia becomes detached froma process. Calls the on_finish method for any loaded instrumentations, removes the old session and prints output, if verbosity is high enough. pid: int - PID of detached process session: Frida Session object - session corresponded to the detached process reason: str - Reason provided by Frida for why the target terminated """ print (f"detached from {pid} for reason {reason}") for instrumentation in self._instrumentations: instrumentation.on_finish() self._instrumentations.clear() #reset for next session, if any self._sessions.remove(session) verbosity = self.settings_controller.get_setting_int(self.CORE_MODNAME,"verbosity") or 0 self.export_all(sys.stdout) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_child_added(self, child): """ Callback called by Frida reactor when a new child is spawned from the target process. child - object """ self._instrument(child.pid,child.path) def _on_child_removed(self,child): """ Callback called by Frida reactor when a child process ends. child - object """ print(f"Child removed: {child.pid}")
class BinAnalyser: def __init__(self, path, filename, queue, num_skip_calls): import frida from frida_tools.application import Reactor self._logger = logging.getLogger(self.__class__.__name__) self.path = path self.filename = filename self.states = queue self.num_skip_calls = num_skip_calls self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._device.on("output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) # pylint: disable=undefined-variable self.output = io.StringIO() self._mallocs = 0 self._frees = 0 self._output_counter = 0 def exec(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() self.analyse() self.states.put('STOP') def _stop(self): self._stop_requested.set() def _start(self): self.pid = self._device.spawn(self.path, stdio='pipe') self._logger.info("Spawned new process. PID: %d", self.pid) session = self._device.attach(self.pid) session.on("detached", lambda reason: self._reactor.schedule( lambda: self._on_detached(self.pid, session, reason))) # pylint: disable=undefined-variable self._logger.info("Session attached") session.enable_child_gating() script = session.create_script( INJECTED_SCRIPT.format(main_module_name=self.filename, num_skip_calls=self.num_skip_calls)) script.on("message", lambda message, data: self._reactor.schedule( lambda: self._on_message(message, data))) # pylint: disable=undefined-variable script.load() self._logger.info("Script loaded") self._print_progress(rewrite=False) self._device.resume(self.pid) # @profile def _on_output(self, pid, fd, data): if fd != 2 and pid == self.pid: self.output.write(data.decode()) self._output_counter += 1 if self._output_counter // 30 == 1: self._output_counter = 0 self.analyse() def _on_detached(self, pid, session, reason): if pid == self.pid: self._logger.info("Session detached") self._reactor.schedule(self._stop, delay=0.5) def _on_message(self, message, data): if message['type'] == 'send': if message['payload'] == 'MALLOC': self._mallocs += 1 self._print_progress() elif message['payload'] == 'FREE': self._frees += 1 self._print_progress() else: self._logger.getChild('frida_script').info(message['payload']) else: self._logger.getChild('frida_script').error(message) def _print_progress(self, rewrite=True): # string = '' # if rewrite: # string = '\r' # string += 'Mallocs: %d, Frees: %d' % (self._mallocs, self._frees) # sys.stdout.write(string) # sys.stdout.flush() pass # @profile def analyse(self): self.outputString = self.output.getvalue() self.output.close() self.output = io.StringIO() if not self.outputString: return split = self.outputString.split('LOG_START_1337\n') if len(split) == 1: return for string in split: split = string.split('LOG_END_1337', maxsplit=1) if len(split) == 2: state_string_raw = split[0].strip() state_string_raw_split = state_string_raw.split('\n', maxsplit=1) if "LOG_MALLOC" in state_string_raw_split[ 0] or "LOG_FREE" in state_string_raw_split[0]: self.states.put( AllocatorStateWrapper( prev_op=state_string_raw_split[0].replace( 'LOG_', ''), freelist_blocks=parse_freelist( state_string_raw_split[1]), tags=parse_tags(state_string_raw_split[1]))) else: self.states.put( AllocatorStateWrapper(prev_op=None, freelist_blocks=parse_freelist( state_string_raw_split[1]), tags=parse_tags( state_string_raw_split[1]))) else: if "Segmentation fault" in string: logger.error("Segmentation fault occurred") sys.exit() self.output.write('LOG_START_1337\n') self.output.write(string)
class Application: def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) cluster_params = frida.EndpointParameters( address="unix:/Users/oleavr/src/cluster", certificate="/Users/oleavr/src/identity2.pem", authentication=('token', "wow-such-secret")) if ENABLE_CONTROL_INTERFACE: control_params = frida.EndpointParameters( address="::1", port=27042, certificate="/Users/oleavr/src/identity.pem", authentication=('callback', self._authenticate)) else: control_params = None service = frida.PortalService(cluster_params, control_params) self._service = service self._device = service.device self._peers = {} self._nicks = set() self._channels = {} service.on( 'node-connected', lambda *args: self._reactor.schedule( lambda: self._on_node_connected(*args))) service.on( 'node-joined', lambda *args: self._reactor.schedule( lambda: self._on_node_joined(*args))) service.on( 'node-left', lambda *args: self._reactor.schedule( lambda: self._on_node_left(*args))) service.on( 'node-disconnected', lambda *args: self._reactor.schedule( lambda: self._on_node_disconnected(*args))) service.on( 'controller-connected', lambda *args: self._reactor.schedule( lambda: self._on_controller_connected(*args))) service.on( 'controller-disconnected', lambda *args: self._reactor.schedule( lambda: self._on_controller_disconnected(*args))) service.on( 'authenticated', lambda *args: self._reactor.schedule( lambda: self._on_authenticated(*args))) service.on( 'subscribe', lambda *args: self._reactor.schedule( lambda: self._on_subscribe(*args))) service.on( 'message', lambda *args: self._reactor.schedule( lambda: self._on_message(*args))) def run(self): self._reactor.schedule(self._start) self._reactor.run() def _start(self): self._service.start() self._device.enable_spawn_gating() def _stop(self): self._service.stop() def _process_input(self, reactor): while True: try: command = input("Enter command: ").strip() except KeyboardInterrupt: self._reactor.cancel_io() return if len(command) == 0: print("Processes:", self._device.enumerate_processes()) continue if command == "stop": self._reactor.schedule(self._stop) break def _authenticate(self, raw_token): try: token = json.loads(raw_token) nick = str(token['nick']) secret = token['secret'].encode('utf-8') except: raise ValueError("invalid request") provided = hashlib.sha1(secret).digest() expected = hashlib.sha1("knock-knock".encode('utf-8')).digest() if not hmac.compare_digest(provided, expected): raise ValueError("get outta here") return { 'nick': nick, } def _on_node_connected(self, connection_id, remote_address): print("on_node_connected()", connection_id, remote_address) def _on_node_joined(self, connection_id, application): print("on_node_joined()", connection_id, application) print("\ttags:", self._service.enumerate_tags(connection_id)) def _on_node_left(self, connection_id, application): print("on_node_left()", connection_id, application) def _on_node_disconnected(self, connection_id, remote_address): print("on_node_disconnected()", connection_id, remote_address) def _on_controller_connected(self, connection_id, remote_address): print("on_controller_connected()", connection_id, remote_address) self._peers[connection_id] = Peer(connection_id, remote_address) def _on_controller_disconnected(self, connection_id, remote_address): print("on_controller_disconnected()", connection_id, remote_address) peer = self._peers.pop(connection_id) for channel in list(peer.memberships): channel.remove_member(peer) if peer.nick is not None: self._release_nick(peer.nick) def _on_authenticated(self, connection_id, session_info): print("on_authenticated()", connection_id, session_info) peer = self._peers.get(connection_id, None) if peer is None: return peer.nick = self._acquire_nick(session_info['nick']) def _on_subscribe(self, connection_id): print("on_subscribe()", connection_id) self._service.post(connection_id, { 'type': 'welcome', 'channels': list(self._channels.keys()) }) def _on_message(self, connection_id, message, data): peer = self._peers[connection_id] mtype = message['type'] if mtype == 'join': self._get_channel(message['channel']).add_member(peer) elif mtype == 'part': channel = self._channels.get(message['channel'], None) if channel is None: return channel.remove_member(peer) elif mtype == 'say': channel = self._channels.get(message['channel'], None) if channel is None: return channel.post(message['text'], peer) elif mtype == 'announce': self._service.broadcast({ 'type': 'announce', 'sender': peer.nick, 'text': message['text'] }) else: print("Unhandled message:", message) def _acquire_nick(self, requested): candidate = requested serial = 2 while candidate in self._nicks: candidate = requested + str(serial) serial += 1 nick = candidate self._nicks.add(nick) return nick def _release_nick(self, nick): self._nicks.remove(nick) def _get_channel(self, name): channel = self._channels.get(name, None) if channel is None: channel = Channel(name, self._service) self._channels[name] = channel return channel
class Application(object): def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) # self._device = frida.get_local_device() self._device = frida.get_usb_device() self._sessions = set() # self._device.on("delivered", lambda child: self._reactor.schedule(lambda: self._on_delivered(child))) self._device.on( "spawn-added", lambda child: self._reactor.schedule( lambda: self._on_delivered(child))) def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): argv = [ "/data/local/tmp/dcow", "/data/local/tmp/run-as", "/system/bin/run-as" ] print("v spawn(argv={})".format(argv)) pid = self._device.spawn(argv) self._instrument(pid) #package_name = "com.yk26gzrdq" #activity_name = "com.yk26gzrdq.DesktopActivity" #pid = self._device.spawn(package_name, activity=activity_name) #pid = self._device.spawn(package_name) #self._instrument(pid) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): print("v attach(pid={})".format(pid)) session = self._device.attach(pid) session.on( "detached", lambda reason: self._reactor.schedule(lambda: self._on_detached( pid, session, reason))) print("v enable_child_gating()") session.enable_child_gating() print("v create_script()") script = session.create_script(""" /** * to demo how Frida can intercept dirtyCow vulnerability Apps * @author Vash Hsu * @date Octorber, 2019 */ /** * Log the involked methods. * @param {string} typeString reporting type, to group multiple send-messages * @param {array} infoList array of meta data, where each is ASCII string */ function reportCall(typeString, infoList) { const sendData = { 'c': 'report', 'type': typeString, 'cols': infoList, }; send(JSON.stringify(sendData)); } var libcIOmap = {}; var fileIOmap = {}; setImmediate(function() { var updateIOmap = function(myKey, myValue) { libcIOmap[myKey] = myValue; }; var lookupIOmap = function(myKey) { if (myKey in libcIOmap) { return libcIOmap[myKey]; } else { return ''; } }; var updateFileIOmap = function(myKey, myValue) { fileIOmap[myKey] = myValue; }; var lookupFileIOmap = function(myKey) { if (myKey in fileIOmap) { return fileIOmap[myKey]; } else { return ''; } }; const isInterestingPath = function(filePath) { if (filePath.startsWith('/system/') || filePath.startsWith('/data/') || filePath.startsWith('/proc/') || filePath.startsWith('/sdcard/')) { return true; } return true; }; // void *mmap(void *addr, size_t length, int prot, int flags, // int fd, off_t offset); // #define PROT_READ 0x1 /* page can be read */ // #define MAP_PRIVATE 0x0 /* changes are private */ Interceptor.attach(Module.findExportByName('libc.so', 'mmap'), { onEnter: function(args) { this.addr = args[0]; this.len = parseInt(args[1]); this.prot = parseInt(args[2]); if (this.prot === 1) { this.prot = 'PROT_READ'; } this.flags = parseInt(args[3]); if (this.flags === 0) { this.flags = 'MAP_PRIVATE'; } this.fd = parseInt(args[4]); this.offset = parseInt(args[5]); }, onLeave: function(retval) { var result = parseInt(retval); var targetFile = lookupIOmap(this.fd); reportCall('libc.so', ['mmap', this.addr, "len="+this.len, "prop="+this.prot, "flag="+this.flags, targetFile, "fd="+this.fd, this.offset, retval]); return retval; }, }); // int madvise(void *addr, size_t length, int advice); // #define MADV_DONTNEED 4 /* dont need these pages */ Interceptor.attach(Module.findExportByName('libc.so', 'madvise'), { onEnter: function(args) { this.addr = args[0]; this.len = parseInt(args[1]); this.advice = parseInt(args[2]); if (this.advice === 4) { this.advice = 'MADV_DONTNEED'; } }, onLeave: function(retval) { reportCall('libc.so', ['madvise', this.addr, this.len, this.advice, retval]); return retval; }, }); // int open(const char *pathname, int flags, mode_t mode); Interceptor.attach(Module.findExportByName('libc.so', 'open'), { onEnter: function(args) { this.path = Memory.readUtf8String(args[0]); this.flag = args[1]; if (parseInt(this.flag) === 0) { this.flag = 'O_RDONLY'; } if (typeof args[2] !== 'undefined') { this.mode = args[2]; } else { this.mode = 0; } }, onLeave: function(retval) { var fd = parseInt(retval); if (fd != -1) { if (isInterestingPath(this.path)) { reportCall('libc.so', ['open', this.path, this.flag, this.mode, "fd="+fd]); } updateIOmap(fd, this.path); } return retval; }, }); // int openat(int dirfd, const char *pathname, int flags, mode_t mode); Interceptor.attach(Module.findExportByName('libc.so', 'openat'), { onEnter: function(args) { this.path = Memory.readUtf8String(args[1]); this.flag = args[2]; if (parseInt(this.flag) === 0) { this.flag = 'O_RDONLY'; } this.mode = args[3]; }, onLeave: function(retval) { var fd = parseInt(retval); if (fd != -1) { reportCall('libc.so', ['openat', this.path, this.flag, this.mode, "fd="+fd]); updateIOmap(fd, this.path); } return retval; }, }); // int close(int fildes); Interceptor.attach(Module.findExportByName('libc.so', 'close'), { onEnter: function(args) { this.fd = parseInt(args[0]); }, onLeave: function(retval) { var result = parseInt(retval); var path = lookupIOmap(this.fd); reportCall('libc.so', ['close', path, "fd="+this.fd, result]); return retval; }, }); // ssize_t write(int fd, const void *buf, size_t count); Interceptor.attach(Module.findExportByName('libc.so', 'write'), { onEnter: function(args) { this.fd = parseInt(args[0]); }, onLeave: function(retval) { var result = parseInt(retval); var path = lookupIOmap(this.fd); if (isInterestingPath(path)) { reportCall('libc.so', ['write', path, "fd="+this.fd, result]); } return retval; }, }); // FILE *fopen(const char *restrict filename, const char *restrict mode); Interceptor.attach(Module.findExportByName('libc.so', 'fopen'), { onEnter: function(args) { this.path = Memory.readUtf8String(args[0]); this.mode = Memory.readUtf8String(args[1]); }, onLeave: function(retval) { reportCall('libc.so', ['fopen', this.path, this.mode, retval]); updateFileIOmap(retval, this.path, 'fptr='+retval); return retval; }, }); // int fclose(FILE *stream); Interceptor.attach(Module.findExportByName('libc.so', 'fclose'), { onEnter: function(args) { this.fptr = args[0]; }, onLeave: function(retval) { var path = lookupFileIOmap(this.fptr); reportCall('libc.so', ['fclose', path, 'fptr='+this.fptr, retval]); return retval; }, }); // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, // FILE *restrict stream); Interceptor.attach(Module.findExportByName('libc.so', 'fwrite'), { onEnter: function(args) { this.fptr = args[3]; }, onLeave: function(retval) { var path = lookupFileIOmap(this.fptr); var totalBytes = parseInt(retval); reportCall('libc.so', ['fwrite', path, 'fptr='+this.fptr,totalBytes]); }, }); }); """) script.on( "message", lambda message, data: self._reactor.schedule( lambda: self._on_message(pid, message))) print("v load()") script.load() print("v resume(pid={})".format(pid)) self._device.resume(pid) self._sessions.add(session) def _on_delivered(self, child): print("/ delivered: {}".format(child)) self._instrument(child.pid) def _on_detached(self, pid, session, reason): print("/ detached: pid={}, reason='{}'".format(pid, reason)) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_message(self, pid, message): print("/ message: pid={}, payload={}".format(pid, message["payload"]))
class Application(object): def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) self._device = None self._session = None def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): device = frida.get_remote_device() self._device = device session = self._device.attach("hello2", persist_timeout=30) self._session = session session.on( 'detached', lambda *args: self._reactor.schedule( lambda: self._on_detached(*args))) script = session.create_script(""" let _puts = null; Interceptor.attach(DebugSymbol.getFunctionByName('f'), { onEnter(args) { const n = args[0].toInt32(); send(n); } }); rpc.exports.dispose = () => { puts('Script unloaded'); }; let serial = 1; setInterval(() => { puts(`Agent still here! serial=${serial++}`); }, 5000); function puts(s) { if (_puts === null) { _puts = new NativeFunction(Module.getExportByName(null, 'puts'), 'int', ['pointer']); } _puts(Memory.allocUtf8String(s)); } """) self._script = script script.on( 'message', lambda *args: self._reactor.schedule( lambda: self._on_message(*args))) script.load() def _process_input(self, reactor): while True: try: command = input("> ").strip() except: self._reactor.cancel_io() return if command == "resume": try: self._session.resume() except Exception as e: print("Failed to resume:", e) else: print("Unknown command") def _on_detached(self, reason, crash): print("⚡ detached: reason={}, crash={}".format(reason, crash)) def _on_message(self, message, data): print("⚡ message: {}".format(message))
def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) self._device = None self._session = None
class Application(object): def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) #self._device = frida.get_local_device() self._device = frida.get_usb_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): # argv = ["/system/bin/sh", "-c", "cat /etc/hosts"] # env = { # "BADGER": "badger-badger-badger", # "SNAKE": "mushroom-mushroom", # } # # print("✔ spawn(argv={})".format(argv)) # pid = self._device.spawn(argv, env=env, stdio='pipe') print("✔ spawn com.coolapk.market") pid = self._device.spawn(["com.coolapk.market"]) self._instrument(pid) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): print("✔ attach(pid={})".format(pid)) session = self._device.attach(pid) session.on( "detached", lambda reason: self._reactor.schedule(lambda: self._on_detached( pid, session, reason))) print("✔ enable_child_gating()") session.enable_child_gating() print("✔ create_script()") with open("hook_RegisterNatives.js") as f: script = session.create_script(f.read()) script.on( "message", lambda message, data: self._reactor.schedule( lambda: self._on_message(pid, message))) print("✔ load()") script.load() print("✔ resume(pid={})".format(pid)) self._device.resume(pid) # time.sleep(10) self._sessions.add(session) def _on_child_added(self, child): print("⚡ child_added: {}".format(child)) self._instrument(child.pid) def _on_child_removed(self, child): print("⚡ child_removed: {}".format(child)) def _on_output(self, pid, fd, data): print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) def _on_detached(self, pid, session, reason): print("⚡ detached: pid={}, reason='{}'".format(pid, reason)) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_message(self, pid, message): print("⚡ message: pid={}, payload={}".format(pid, message["payload"]))
class Application: def __init__(self, nick): self._reactor = Reactor(run_until_return=self._process_input) token = { 'nick': nick, 'secret': "knock-knock" } self._device = frida.get_device_manager().add_remote_device("::1", certificate="/Users/oleavr/src/cert.pem", token=json.dumps(token)) self._bus = self._device.bus self._bus.on('message', lambda *args: self._reactor.schedule(lambda: self._on_bus_message(*args))) self._channel = None self._prompt = "> " def run(self): self._reactor.schedule(self._start) self._reactor.run() def _start(self): self._bus.attach() def _process_input(self, reactor): while True: sys.stdout.write("\r") try: text = input(self._prompt).strip() except: self._reactor.cancel_io() return sys.stdout.write("\033[1A\033[K") sys.stdout.flush() if len(text) == 0: self._print("Processes:", self._device.enumerate_processes()) continue if text.startswith("/join "): if self._channel is not None: self._bus.post({ 'type': 'part', 'channel': self._channel }) channel = text[6:] self._channel = channel self._prompt = "{} > ".format(channel) self._bus.post({ 'type': 'join', 'channel': channel }) continue if text.startswith("/announce "): self._bus.post({ 'type': 'announce', 'text': text[10:] }) continue if self._channel is not None: self._bus.post({ 'channel': self._channel, 'type': 'say', 'text': text }) else: self._print("*** Need to /join a channel first") def _on_bus_message(self, message, data): mtype = message['type'] if mtype == 'welcome': self._print("*** Welcome! Available channels:", repr(message['channels'])) elif mtype == 'membership': self._print("*** Joined", message['channel']) self._print("- Members:\n\t" + "\n\t".join(["{} (connected from {})".format(m['nick'], m['address']) for m in message['members']])) for item in message['history']: self._print("<{}> {}".format(item['sender'], item['text'])) elif mtype == 'join': user = message['user'] self._print("👋 {} ({}) joined {}".format(user['nick'], user['address'], message['channel'])) elif mtype == 'part': user = message['user'] self._print("🚪 {} ({}) left {}".format(user['nick'], user['address'], message['channel'])) elif mtype == 'chat': self._print("<{}> {}".format(message['sender'], message['text'])) elif mtype == 'announce': self._print("📣 <{}> {}".format(message['sender'], message['text'])) else: self._print("Unhandled message:", message) def _print(self, *words): print("\r\033[K" + " ".join([str(word) for word in words])) sys.stdout.write(self._prompt) sys.stdout.flush()
class Application(object): def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor( run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on( "child-added", lambda child: self._reactor.schedule( lambda: self._on_child_added(child))) self._device.on( "child-removed", lambda child: self._reactor.schedule( lambda: self._on_child_removed(child))) self._device.on( "output", lambda pid, fd, data: self._reactor.schedule( lambda: self._on_output(pid, fd, data))) def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): self._instrument(1) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): print("✔ attach(pid={})".format(pid)) session = self._device.attach(pid) session.on( "detached", lambda reason: self._reactor.schedule(lambda: self._on_detached( pid, session, reason))) print("✔ enable_child_gating()") session.enable_child_gating() print("✔ create_script()") script = session.create_script(open('frida-ssl-pin.js', 'r').read()) script.on( "message", lambda message, data: self._reactor.schedule( lambda: self._on_message(pid, message))) print("✔ load()") script.load() print("✔ resume(pid={})".format(pid)) try: self._device.resume(pid) except Exception as e: print(e) self._sessions.add(session) def _on_child_added(self, child): print("⚡ child_added: {}".format(child)) self._instrument(child.pid) def _on_child_removed(self, child): print("⚡ child_removed: {}".format(child)) def _on_output(self, pid, fd, data): print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) def _on_detached(self, pid, session, reason): print("⚡ detached: pid={}, reason='{}'".format(pid, reason)) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_message(self, pid, message): print("⚡ message: pid={}, payload={}".format(pid, message["payload"]))
class Application(object): def __init__(self): self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data))) def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): argv = ["/bin/sh", "-c", "cat /etc/hosts"] env = { "BADGER": "badger-badger-badger", "SNAKE": "mushroom-mushroom", } print("✔ spawn(argv={})".format(argv)) pid = self._device.spawn(argv, env=env, stdio='pipe') self._instrument(pid) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def _instrument(self, pid): print("✔ attach(pid={})".format(pid)) session = self._device.attach(pid) session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason))) print("✔ enable_child_gating()") session.enable_child_gating() print("✔ create_script()") script = session.create_script("""\ Interceptor.attach(Module.getExportByName(null, 'open'), { onEnter: function (args) { send({ type: 'open', path: Memory.readUtf8String(args[0]) }); } }); """) script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message))) print("✔ load()") script.load() print("✔ resume(pid={})".format(pid)) self._device.resume(pid) self._sessions.add(session) def _on_child_added(self, child): print("⚡ child_added: {}".format(child)) self._instrument(child.pid) def _on_child_removed(self, child): print("⚡ child_removed: {}".format(child)) def _on_output(self, pid, fd, data): print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) def _on_detached(self, pid, session, reason): print("⚡ detached: pid={}, reason='{}'".format(pid, reason)) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) def _on_message(self, pid, message): print("⚡ message: pid={}, payload={}".format(pid, message["payload"]))
class FriSpyControllerApp(object): def __init__(self, config, logger_obj, api_watch_list): self.config = config self.logger = logger_obj self.api_watch_list = api_watch_list self.execution_timeout = self.config.get_execution_timeout() self.capture_basic_behavior = self.config.get_capture_behavior_report_basic_flag() self.capture_complete_behavior = self.config.get_capture_behavior_report_complete_flag() self.process_list = [] self.target_process_pid = None # Initialize Reporting Module self.report_generator = Reporting(config, logger_obj) # Initialize Queue for FriSpyGUI to receive the events self.event_queue_name = self.config.get_event_queue_name() self.msmqueue_event = MSMQCustom(self.event_queue_name) self.config_queue_name = self.config.get_config_queue_name() self.msmqueue_config = MSMQCustom(self.config_queue_name) # Initialize Controller self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) self._device = frida.get_local_device() self._sessions = set() try: self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data))) self._device.on("process-crashed", lambda crash: self._reactor.schedule(lambda: self._on_process_crashed(crash))) self._device.on("lost", lambda crash: self._reactor.schedule(lambda: self._on_process_crashed(crash))) except Exception as e: self.logger.log("error", "Exception - FriSpyController : run : %s" %(str(e))) self.Controller_cleaup(None) sys.exit(1) def run(self, target_process): # Schedule the execution of target process try: if not target_process: self.logger.log("error", "FriSpyController: run: FriSpy Controller failed to locate target process ") self.Controller_cleaup(None) sys.exit(1) self._reactor.schedule(lambda: self._start(target_process)) except Exception as e: self.logger.log("error", "Exception - FriSpyController : schedule_start : %s" %(str(e))) self.Controller_cleaup(None) sys.exit(1) # Initiate the execution of target process try: self._reactor.run() except Exception as e: self.logger.log("error", "Exception - FriSpyController : run : %s" %(str(e))) self.Controller_cleaup(None) sys.exit(1) def _start(self, target_process): # Spawn the target process try: pid = self._device.spawn((target_process,)) if pid: self.target_process_pid = pid try: self._instrument(pid, target_process) except Exception as e: self.logger.log("error", "Exception - FriSpyController : _start : Failed to instrument : %s" % (traceback.print_exc(file=sys.stdout))) self.Controller_cleaup(None) sys.exit(1) else: self.logger.log("error", "Error - FriSpyController : _start : Failed to instrument") self.Controller_cleaup(None) sys.exit(1) except Exception as e: self.logger.log("error", "Exception - FriSpyController : Failed to spawn : %s" %(str(traceback.print_exc(file=sys.stdout)))) self.Controller_cleaup(None) sys.exit(1) def _stop_if_idle(self): if len(self._sessions) == 0: self._stop_requested.set() def prepare_script(self): try: self.win_lib_dir = self.config.get_win_lib_directory() self.common_lib_dir = self.config.get_common_lib_directory() self.common_def_file_name = self.config.get_common_def_file() self.common_def_file_path = os.path.join(self.common_lib_dir, self.common_def_file_name) self.script_file_content = "" #Load common-lib common_lib_content = self.get_api_lib_implementation(self.common_def_file_path) if common_lib_content == None: self.logger.log("error", "FriSpyController: prepare_script : Failed to load common lib") return False timeout_checker = ''' var timeout_check = function(timeout){ var send_data = {} send_data.Date = Date() send_data.api_name = "timeout_check" send_data.module_name = null send_data.api_arguments = null send(JSON.stringify(send_data, null, 4)); } setInterval(timeout_check, %d) ''' timeout_in_milliseconds = self.config.get_execution_timeout() * 1000# converting seconds to milliseconds timeout_checker_content = ((timeout_checker) % timeout_in_milliseconds) self.script_file_content = "//////// Common Lib ////////\n\n%s\n%s\n" % (common_lib_content, timeout_checker_content) self.logger.log("info", "common-lib loaded successfully") appended_lib_content = "" for lib_info in self.api_watch_list: # Get API lib info lib_file_parent = lib_info.split("_")[0] lib_file_name = lib_info.split("_")[1] lib_file_path = os.path.join(self.win_lib_dir ,lib_file_parent, lib_file_name) + ".js" lib_content = self.get_api_lib_implementation(lib_file_path) if lib_content != None: appended_lib_content = "%s\n//%s\n%s\n" % (appended_lib_content, lib_file_path, lib_content) if appended_lib_content == "": self.logger.log("error", "FriSpyController: prepare_script : Failed to prepare Script") return False self.script_file_content = "%s\n%s\n" % (self.script_file_content, appended_lib_content) status = self.save_script() if not status: return False except Exception as e: self.logger.log("error", "Exception - FriSpyController: prepare_script : Failed to prepare Script: %s"% (str(e))) return False return True def save_script(self): self.api_injector_file = os.path.join(self.config.get_config_directory(), self.config.get_api_injector()) self.logger.log("info", "Saving Script...") if len(self.script_file_content) > 0: try: with open(self.api_injector_file, "w") as filehandle: filehandle.write(self.script_file_content) self.logger.log("info", "Script saved successfully")# : '%s'" % (self.script_file_content)) except Exception as e: self.logger.log("error", "Exception: Failed to save Script watch list : %s" % str(e)) return False else: self.logger.log("error", "Injector Script is empty") return False return True def get_api_lib_implementation(self, api_lib_file_path): lib_content = None if os.path.exists(api_lib_file_path): try: with open (api_lib_file_path, "r") as libhandle: lib_content = libhandle.read() self.logger.log("info", "API Launch Successful : %s" % api_lib_file_path) except Exception as e: self.logger.log("warn", "Exception: Launch Failed : %s"% str(e)) else: self.logger.log("warn", "Launch Failed : %s"% api_lib_file_path) return lib_content def _instrument(self, pid, path): try: self.logger.log("","Target process attach : pid=({})".format(pid)) processinfo = {} processinfo["pid"] = pid processinfo["path"] = path self.logger.log_to_gui("ProcessCreate", "%s" %(json.dumps(processinfo))) self.process_list.append(pid) session = self._device.attach(pid) session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason))) session.enable_child_gating() scriptFile = self.script_file_content script = session.create_script(scriptFile) script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message))) self.logger.log("","Load Injector module") script.load() self.logger.log("","Resume Execution : pid=({})".format(pid)) self.target_exec_start_time = datetime.now() self.logger.log("","Eventing started {} ".format(self.target_exec_start_time)) self.target_exec_end_time = self.target_exec_start_time + timedelta(seconds=self.execution_timeout) self._device.resume(pid) self._sessions.add(session) except Exception as e: self.logger.log("error", "Exception: instrument(): %s" % (str(e))) self.Controller_cleaup(None) sys.exit(1) def _on_child_added(self, child): self.logger.log(""," child_added: {}".format(child)) self._instrument(child.pid, child.path) def _on_child_removed(self, child): self.logger.log(""," child_removed: {}".format(child)) def _on_output(self, pid, fd, data): self.logger.log(""," output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) def _on_detached(self, pid, session, reason): self.logger.log(""," detached: pid={}, reason='{}'".format(pid, reason)) self._device.kill(pid) self._sessions.remove(session) self._reactor.schedule(self._stop_if_idle, delay=0.5) if len(self._sessions) == 0: self.logger.log("","Exiting FriSpy...") def _on_process_crashed(crash): print("on_process_crashed") print("\tcrash:", crash) def is_ready_to_process(self, jsonobj): if "ObjectAttributes" in jsonobj["api_arguments"] and jsonobj["api_arguments"]["ObjectAttributes"] == "0x0": return False if jsonobj["api_name"] == "OpenProcessToken" and "ProcessHandle" in jsonobj["api_arguments"] and jsonobj["api_arguments"]["ProcessHandle"] == "0xffffffff": return False if (jsonobj["api_name"] == "CreateEventExW" or jsonobj["api_name"] == "CreateEventExA" or jsonobj["api_name"] == "CreateEventA" or jsonobj["api_name"] == "CreateEventW" or jsonobj["api_name"] == "CreateMutexExW" or jsonobj["api_name"] == "CreateMutexW" or jsonobj["api_name"] == "CreateSemaphoreExW") and "lpName" in jsonobj["api_arguments"] and jsonobj["api_arguments"]["lpName"] == "0x0": return False return True def _on_message(self, pid, message): try: if message["type"] == "error": # Check for errors in loading Injector Module print (message) self.logger.log("error","Error: Injector Module: %s - %s" % ( message["description"], message["stack"])) self.Controller_cleaup(pid) sys.exit(1) # Get the events from CoreEngine jsobj = (json.loads(message["payload"])) # Abort the execution if the Execution Timeout is triggered if "api_name" in jsobj and jsobj["api_name"] == "timeout_check": self.logger.log("info", "Execution timeout triggered : %s ..." % (jsobj["Date"])) self.logger.log_to_gui("Timeout", "Execution timeout triggered. Aborting FriSpy..") self.Controller_cleaup(pid) return #sys.exit(1) if "api_retval" in jsobj and jsobj["api_retval"] == "warn": self.logger.log("warn", "%s" % (jsobj["api_arguments"])) else: # Collect the events self.logger.log ("",jsobj) jsobj["process_id"] = str(pid) #print(self._sessions) if self.is_ready_to_process(jsobj): # Enrich the events from CoreEngine argument_report_basic_json_obj = {} argument_report_complete_json_obj = {} (argument_report_basic_json_obj, argument_report_complete_json_obj) = self.report_generator.add_behavior_to_report(jsobj) msg_label = "Event" msg_body = None if self.capture_basic_behavior and argument_report_basic_json_obj: msg_body = json.dumps(argument_report_basic_json_obj) if self.capture_complete_behavior and argument_report_complete_json_obj: msg_body = json.dumps(argument_report_complete_json_obj) # Send events to FriSpyGUI if msg_body: self.msmqueue_event.open_queue(2, 0)#MQ_SEND_ACCESS self.msmqueue_event.send_to_queue(msg_label, msg_body) self.msmqueue_event.close_queue() except Exception as e: self.logger.log("error","Exception: on_message : %s : %s: %s " % (str(e), str(jsobj), str(traceback.print_exc(file=sys.stdout)))) self.Controller_cleaup(pid) sys.exit(1) def Controller_cleaup(self, pid): # Terminate the processes print(self.process_list) for pid in self.process_list: if pid: try: os.kill(pid,signal.SIGTERM) #self.process_list.remove(pid) except Exception as e: self.logger.log("Error", "%s" % (str(e))) #spass if self._reactor.is_running(): self._reactor.stop() self._reactor.cancel_all() self._stop_requested.set()