def module_entry_point(params): ''' Callback on the entry point of the main module being monitored ''' global cm global UNPACKER_LOG_PATH global UNPACKER_DUMP_PATH global pyrebox_print global ntdll_space from api import CallbackManager import api # Get pameters cpu_index = params["cpu_index"] cpu = params["cpu"] # Get running process pgd = api.get_running_process(cpu_index) pyrebox_print("Reached entry point of new process: %x" % pgd) # Add memory write / memory execute callbacks, and their triggers cm.add_callback(CallbackManager.MEM_WRITE_CB, mem_write, name="mem_write_%x" % pgd) cm.add_callback(CallbackManager.BLOCK_BEGIN_CB, block_exec, name="block_begin_%x" % pgd) cm.add_trigger("mem_write_%x" % pgd, "triggers/trigger_memwrite_wx.so") cm.set_trigger_var("mem_write_%x" % pgd, "begin", 0x0) if TARGET_LONG_SIZE == 4: cm.set_trigger_var("mem_write_%x" % pgd, "end", 0x80000000) else: cm.set_trigger_var("mem_write_%x" % pgd, "end", 0x000007FFFFFFFFFF) cm.set_trigger_var("mem_write_%x" % pgd, "pgd", pgd) cm.add_trigger("block_begin_%x" % pgd, "triggers/trigger_blockbegin_wx.so") cm.set_trigger_var("block_begin_%x" % pgd, "begin", 0x0) if TARGET_LONG_SIZE == 4: cm.set_trigger_var("block_begin_%x" % pgd, "end", 0x80000000) else: cm.set_trigger_var("block_begin_%x" % pgd, "end", 0x000007FFFFFFFFFF) cm.set_trigger_var("block_begin_%x" % pgd, "pgd", pgd) # Start monitoring process api.start_monitoring_process(pgd) # Create a dump, on process entry point for every process generate_dump(pgd, "Dump at process entry point for PGD 0x%x" % pgd) # Get the address space for ntdll for mod in api.get_module_list(pgd): if "ntdll.dll" in mod["name"].lower(): ntdll_space = (mod["base"], mod["size"])
def update_symbols(self): import api from api import CallbackManager global mods_pending_symbol_resolution if self.unpickled: return syms = api.get_symbol_list() # Check if we can remove the module from the list of modules with # pending symbol resolution for mod in api.get_module_list(self.get_pgd()): if mod["symbols_resolved"] and mod["name"] in mods_pending_symbol_resolution.get(self.get_pgd(), []): del mods_pending_symbol_resolution[self.get_pgd()][mod["name"]] for d in syms: mod = d["mod"] fun = d["name"] addr = d["addr"] pos = bisect.bisect_left(self.symbols, Symbol("", "", addr)) if pos >= 0 and pos < len(self.symbols) and self.symbols[pos].get_addr() == addr: continue if mod in self.modules: for pair in self.modules[mod]: # Update the (include/exclude addresses in apitracer) if mwmon.include_apis is not None: if (mod.lower(), fun.lower()) in mwmon.include_apis: if (pair[0] + addr) not in mwmon.include_apis_addrs: mwmon.include_apis_addrs.append(pair[0] + addr) if mwmon.exclude_apis is not None: if (mod.lower(), fun.lower()) in mwmon.exclude_apis: if (pair[0] + addr) not in mwmon.exclude_apis_addrs: mwmon.exclude_apis_addrs.append(pair[0] + addr) bisect.insort( self.symbols, Symbol(mod, fun, pair[0] + addr)) if mwmon.interproc or mwmon.api_tracer or mwmon.dumper: # Add breakpoint if necessary if (mod, fun) in self.breakpoints and self.breakpoints[(mod, fun)] is None: f_callback = self.bp_funcs[(mod, fun)][0] update_vads = self.bp_funcs[(mod, fun)][1] callback = functools.partial( f_callback, pid=self.pid, proc=self, update_vads=update_vads) bp = mwmon.cm.add_callback(CallbackManager.INSN_BEGIN_CB, callback, name="api_bp_%x_%s" % (self.pid, fun), addr=pair[0] + addr, pgd=self.pgd) self.breakpoints[(mod, fun)] = (bp, pair[0] + addr) mwmon.printer("Adding breakpoint at %s:%s %x:%x from process with PID %x" % (mod, fun, pair[0] + addr, self.pgd, self.pid))
def context_change(new_proc, target_mod_name, params): '''Callback triggered for every context change''' global ntdll_breakpoint from mw_monitor_classes import mwmon from api import BP import api from api import CallbackManager from functools import partial old_pgd = params["old_pgd"] new_pgd = params["new_pgd"] if new_proc.get_pgd() == new_pgd: ep = find_ep(new_proc, target_mod_name) if ep is not None: mwmon.printer("The entry point for %s is %x\n" % (target_mod_name, ep)) mwmon.cm.rm_callback("context_change_%x" % new_proc.get_pgd()) try: # Load modules and symbols for the process mods = api.get_module_list(new_proc.get_pgd()) if mods is not None: for m in mods: name = m["name"] base = m["base"] size = m["size"] new_proc.set_module(name, base, size) # NTDLL is a special case, and we set a breakpoint # on the code of the main module to trigger the symbol resolution # as soon as we execute one instruction in its # region if target_mod_name in name: ntdll_breakpoint[new_proc.get_pgd()] = BP( base, new_proc.get_pgd(), size=size, func=partial(ntdll_breakpoint_func, new_proc), new_style=True) ntdll_breakpoint[new_proc.get_pgd()].enable() except ValueError as e: # The process has not been created yet, so we need to # wait for symbol resolution pass # Callback for each module loaded mwmon.cm.add_callback(CallbackManager.LOADMODULE_CB, module_loaded, pgd=new_proc.get_pgd(), name=("load_module_%x" % new_proc.get_pgd()))
def context_change(new_proc, target_mod_name, params): '''Callback triggered for every context change''' global ntdll_breakpoint from mw_monitor_classes import mwmon from api import BP import api from api import CallbackManager from functools import partial old_pgd = params["old_pgd"] new_pgd = params["new_pgd"] if new_proc.get_pgd() == new_pgd: ep = find_ep(new_proc, target_mod_name) if ep is not None: mwmon.printer("The entry point for %s is %x\n" % (target_mod_name, ep)) mwmon.cm.rm_callback("context_change_%x" % new_proc.get_pgd()) try: # Load modules and symbols for the process mods = api.get_module_list(new_proc.get_pgd()) if mods is not None: for m in mods: name = m["name"] base = m["base"] size = m["size"] new_proc.set_module(name, base, size) # NTDLL is a special case, and we set a breakpoint # on the code of the main module to trigger the symbol resolution # as soon as we execute one instruction in its # region if target_mod_name in name: ntdll_breakpoint[new_proc.get_pgd()] = BP(base, new_proc.get_pgd(), size = size, func = partial(ntdll_breakpoint_func, new_proc), new_style = True) ntdll_breakpoint[new_proc.get_pgd()].enable() except ValueError as e: # The process has not been created yet, so we need to # wait for symbol resolution pass # Callback for each module loaded mwmon.cm.add_callback(CallbackManager.LOADMODULE_CB, module_loaded, pgd = new_proc.get_pgd(), name = ("load_module_%x" % new_proc.get_pgd()))
def interproc_start_monitoring_process(params): ''' Given a Process instance, do the magic to start monitoring the process for the interproc module ''' global cm global interproc_data import api from core import Process from api import CallbackManager # Get parameters pid = params["pid"] pgd = params["pgd"] name = params["name"] proc = Process(name) proc.set_pgd(pgd) proc.set_pid(pid) # Append process to process list interproc_data.add_process(proc) # add_module, for every module loaded so far for this process. Because # this function might be triggered by a call to NtOpenProcess over # an already existing process try: for mod in api.get_module_list(pgd): add_module(proc, {"pid": pid, "pgd": pgd, "base": mod["base"], "size": mod["size"], "name": mod["name"], "fullname": mod["fullname"]}) # Callback for each module loaded cm.add_callback(CallbackManager.LOADMODULE_CB, functools.partial(module_loaded, proc), pgd = pgd, name = ("load_module_%x" % pgd)) except ValueError: # Could happen that the process is still not on the list of # created processes pp_debug("Process still not in the list of created processes, setting CB on TLB exec.\n") cm.add_callback(CallbackManager.TLB_EXEC_CB, functools.partial(tlb_exec, proc), name=("tlb_exec_%d" % pgd))
def find_ep(pgd, proc_name): '''Given an address space and a process name, uses pefile module to get its entry point ''' global cm global loaded_processes import api for m in api.get_module_list(pgd): name = m["name"] base = m["base"] # size = m["size"] if name == proc_name: try: pe_data = api.r_va(pgd, base, 0x1000) pe = pefile.PE(data=pe_data) ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint return (base + ep) except Exception: pyrebox_print("Unable to run pefile on loaded module %s" % name)
def __context_change_callback(self, target_pgd, target_mod_name, params): """ Updates the module base (to have the absolute agent buffer address) as soon as it is available. """ global cm old_pgd = params["old_pgd"] new_pgd = params["new_pgd"] try: if target_pgd == new_pgd and self.__status == GuestAgentPlugin.__AGENT_RUNNING: lowest_addr = None for m in api.get_module_list(target_pgd): name = m["name"] base = m["base"] # size = m["size"] if name == target_mod_name or target_mod_name in name: if lowest_addr is None: lowest_addr = base elif base < lowest_addr: lowest_addr = base if self.__agent_buffer_offset is not None and \ lowest_addr is not None: self.__agent_buffer_address = lowest_addr + \ self.__agent_buffer_offset # Now, our agent is fully up and running self.__status = GuestAgentPlugin.__AGENT_READY # Now, we add the opcode hook and start monitoring the # process self.__cb.add_callback( api.CallbackManager.REMOVEPROC_CB, self.__remove_process_callback, name="host_file_plugin_process_REMOVE") self.__cb.rm_callback("context_change_guest_agent") except Exception as e: self.__printer( "Exception occurred on context change callback: %s" % str(e))
def find_ep(proc, proc_name): '''Given an address space and a process name, uses pefile module to get its entry point ''' import api import pefile from mw_monitor_classes import mwmon try: for m in api.get_module_list(proc.get_pgd()): name = m["name"] base = m["base"] # size = m["size"] if name == proc_name: pe_data = api.r_va(proc.get_pgd(), base, 0x1000) pe = pefile.PE(data=pe_data) ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint return (base + ep) except Exception as e: mwmon.printer("Unable to run pefile on loaded module %s (%s)" % (proc_name, str(e))) pass return None
def find_ep(proc, proc_name): '''Given an address space and a process name, uses pefile module to get its entry point ''' import api import pefile from mw_monitor_classes import mwmon try: for m in api.get_module_list(proc.get_pgd()): name = m["name"] base = m["base"] # size = m["size"] if proc_name in name: pe_data = api.r_va(proc.get_pgd(), base, 0x1000) pe = pefile.PE(data=pe_data) ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint return (base + ep) except Exception as e: mwmon.printer("Unable to run pefile on loaded module %s (%s)" % (proc_name, str(e))) pass return None
def __context_change_callback(self, target_pgd, target_mod_name, params): """ Updates the module base (to have the absolute agent buffer address) as soon as it is available. """ global cm old_pgd = params["old_pgd"] new_pgd = params["new_pgd"] try: if target_pgd == new_pgd and self.__status == GuestAgentPlugin.__AGENT_RUNNING: lowest_addr = None for m in api.get_module_list(target_pgd): name = m["name"] base = m["base"] # size = m["size"] if name == target_mod_name or target_mod_name in name: if lowest_addr is None: lowest_addr = base elif base < lowest_addr: lowest_addr = base if self.__agent_buffer_offset is not None and \ lowest_addr is not None: self.__agent_buffer_address = lowest_addr + \ self.__agent_buffer_offset # Now, our agent is fully up and running self.__status = GuestAgentPlugin.__AGENT_READY # Now, we add the opcode hook and start monitoring the # process self.__cb.add_callback( api.CallbackManager.REMOVEPROC_CB, self.__remove_process_callback, name="host_file_plugin_process_REMOVE") self.__cb.rm_callback("context_change_guest_agent") except Exception as e: self.__printer("Exception occurred on context change callback: %s" % str(e))