def load_module(params): ''' Callback trigger for every module loaded. ''' global cm global pyrebox_print global entry_point_bp global target_pgd global target_procname import pefile import api from api import BP pid = params["pid"] pgd = params["pgd"] base = params["base"] size = params["size"] name = params["name"] fullname = params["fullname"] if pgd == target_pgd and target_procname.lower().startswith(name.lower()): cm.rm_callback("load_module") # Set a breakpoint on the EP, that will start a shell entry_point_bp = BP(base, pgd, size=size, new_style=True, func=module_entry_point) entry_point_bp.enable() # Call all our internal callbacks for cb in load_module_callbacks: cb(params)
def new_proc(params): ''' Process creation callback. Receives 3 parameters: :param pid: The pid of the process :type pid: int :param pgd: The PGD of the process :type pgd: int :param name: The name of the process :type name: str ''' global pyrebox_print global target_procname global cm global memwrite_breakpoint pid = params["pid"] pgd = params["pgd"] name = params["name"] pyrebox_print("New process created! pid: %x, pgd: %x, name: %s" % (pid, pgd, name)) # For instance, we can start the shell whenever a process is created if target_procname != "" and target_procname.lower() in name.lower(): pyrebox_print( "Creating memory write callback for this process on user address space" ) memwrite_breakpoint = BP(0x0, pgd, size=0x80000000, typ=BP.MEM_WRITE, func=mem_write, new_style=True) memwrite_breakpoint.enable()
def new_proc(params): ''' Process creation callback. Receives 3 parameters: :param pid: The pid of the process :type pid: int :param pgd: The PGD of the process :type pgd: int :param name: The name of the process :type name: str ''' global pyrebox_print global target_procname global cm global memwrite_breakpoint pid = params["pid"] pgd = params["pgd"] name = params["name"] pyrebox_print("New process created! pid: %x, pgd: %x, name: %s" % (pid, pgd, name)) # For instance, we can start the shell whenever a process is created if target_procname != "" and target_procname.lower() in name.lower(): pyrebox_print("Creating memory write callback for this process on user address space") memwrite_breakpoint = BP(0x0, pgd, size=0x80000000, typ=BP.MEM_WRITE, func=mem_write, new_style = True) memwrite_breakpoint.enable()
def add_module_monitoring_hooks(pgd): ''' Adds initial set of breakpoints for a given process, so that we can detect when a new module is inserted, or a module is removed from any of its linked lists. ''' from api import BP import api from vmi import update_modules import functools from utils import pp_error if pgd not in module_load_remove_breakpoints: module_load_remove_breakpoints[pgd] = {} # Update the module list for this pgd hooking_points = update_modules(pgd) if hooking_points is not None: # Add the BPW breakpoints for module_base, addr, size in hooking_points: haddr = api.va_to_pa(pgd, addr) bp = BP(haddr, None, size=size, typ=BP.MEM_WRITE_PHYS, func=functools.partial(module_change_callback, pgd, addr, haddr), new_style=True) module_load_remove_breakpoints[pgd][(module_base, addr, size)] = bp bp.enable() else: pp_error( "Could not set initial list of breakpoints for module monitoring: %x" % pgd)
def add_module_monitoring_hooks(pgd): ''' Adds initial set of breakpoints for a given process, so that we can detect when a new module is inserted, or a module is removed from any of its linked lists. ''' from api import BP import api from vmi import update_modules import functools from utils import pp_error if pgd not in module_load_remove_breakpoints: module_load_remove_breakpoints[pgd] = {} # Update the module list for this pgd hooking_points = update_modules(pgd) if hooking_points is not None: # Add the BPW breakpoints for module_base, addr, size in hooking_points: haddr = api.va_to_pa(pgd, addr) bp = BP(haddr, None, size = size, typ = BP.MEM_WRITE_PHYS, func = functools.partial(module_change_callback, pgd, addr, haddr), new_style = True) module_load_remove_breakpoints[pgd][(module_base, addr, size)] = bp bp.enable() else: pp_error("Could not set initial list of breakpoints for module monitoring: %x" % pgd)
def module_change_callback(pgd, bp_vaddr, bp_haddr, cpu_index, vaddr, size, haddr, data): ''' Callback function triggered whenever there is a change in the list of linked modules for a given process. Updates the module list for that PGD (or kernel). ''' import functools import struct import api from api import BP from vmi import update_modules from utils import pp_error from vmi import set_modules_non_present from vmi import clean_non_present_modules # First, we check if the memory address written points to a module # that we have already detected (it is in our list of hooking points). # In this way we avoid triggering one update operation for every # modified pointer (inserting a module requires to change several # pointers, due to the different linked lists). # Return if it points inside a module that we have already added to our list for module_base, hook_addr, hook_size in module_load_remove_breakpoints[pgd]: if data >= module_base and data < (hook_addr + hook_size): return hooking_points = update_modules(pgd) if hooking_points is not None: # Update hooking points # 1) Remove the breakpoints not used anymore bps_to_remove = [] for hp in module_load_remove_breakpoints[pgd]: if hp not in hooking_points: bps_to_remove.append(hp) for hp in bps_to_remove: module_load_remove_breakpoints[pgd][hp].disable() del module_load_remove_breakpoints[pgd][hp] # 2) Add new breakpoints for hp in hooking_points: if hp not in module_load_remove_breakpoints[pgd]: module_base, addr, size = hp haddr = api.va_to_pa(pgd, addr) bp = BP(haddr, None, size = size, typ = BP.MEM_WRITE_PHYS, func = functools.partial(module_change_callback, pgd, addr, haddr)) module_load_remove_breakpoints[pgd][hp] = bp bp.enable() else: # Just remove all the modules for the process # Mark all modules as non-present set_modules_non_present(None, pgd) # Remove all the modules that are not marked as present clean_non_present_modules(None, pgd)
def context_change(target_pgd, target_mod_name, old_pgd, new_pgd): '''Callback triggered for every context change :param target_pgd: This parameter is inserted using functools.partial (see callback registration) :param target_mod_name: This parameter is inserted using functools.partial (see callback registration) :param old_pgd: This is the first parameter of the callback :param new_pgd: This is the second parameter of the callback ''' global cm if target_pgd == new_pgd: ep = find_ep(target_pgd, target_mod_name) if ep is not None: pyrebox_print("The entry point for %s is %x\n" % (target_mod_name, ep)) cm.rm_callback("context_change") # Set a breakpoint on the EP, that will start a shell bp = BP(ep, target_pgd) bp.enable()
def load_module(params): ''' Callback trigger for every module loaded. ''' global cm global pyrebox_print global entry_point_bp global target_pgd global target_procname import pefile import api from api import BP pid = params["pid"] pgd = params["pgd"] base = params["base"] size = params["size"] name = params["name"] fullname = params["fullname"] if pgd == target_pgd and target_procname.lower().startswith(name.lower()): # Loaded main module, try to read EP ep = None try: pe_data = api.r_va(pgd, base, 0x1000) pe = pefile.PE(data=pe_data) ep = base + pe.OPTIONAL_HEADER.AddressOfEntryPoint except Exception as e: print(e) pyrebox_print("Could not read EP from module %s on load" % name) # If we have the EP, put a breakpoint there if ep is not None: pyrebox_print("The entry point for %s is 0x%x\n" % (target_procname, ep)) cm.rm_callback("load_module") pyrebox_print("Setting BP on entrypoint") # Set a breakpoint on the EP, that will start a shell entry_point_bp = BP(ep, pgd, new_style=True, func=module_entry_point) entry_point_bp.enable()
def context_change(target_pgd, target_mod_name, params): '''Callback triggered for every context change :param target_pgd: This parameter is inserted using functools.partial (see callback registration) :param target_mod_name: This parameter is inserted using functools.partial (see callback registration) :param old_pgd: This is the first parameter of the callback :param new_pgd: This is the second parameter of the callback ''' global cm old_pgd = params["old_pgd"] new_pgd = params["new_pgd"] if target_pgd == new_pgd: ep = find_ep(target_pgd, target_mod_name) if ep is not None: pyrebox_print("The entry point for %s is %x\n" % (target_mod_name, ep)) cm.rm_callback("context_change") # Set a breakpoint on the EP, that will start a shell bp = BP(ep, target_pgd, new_style = True) bp.enable()
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 module_change_callback(pgd, bp_vaddr, bp_haddr, params): ''' Callback function triggered whenever there is a change in the list of linked modules for a given process. Updates the module list for that PGD (or kernel). ''' import functools import struct import api from api import BP from vmi import update_modules from utils import pp_error from vmi import set_modules_non_present from vmi import clean_non_present_modules cpu_index = params["cpu_index"] vaddr = params["vaddr"] size = params["size"] haddr = params["haddr"] data = params["data"] # First, we check if the memory address written points to a module # that we have already detected (it is in our list of hooking points). # In this way we avoid triggering one update operation for every # modified pointer (inserting a module requires to change several # pointers, due to the different linked lists). # Return if it points inside a module that we have already added to our list for module_base, hook_addr, hook_size in module_load_remove_breakpoints[pgd]: if data >= module_base and data < (hook_addr + hook_size): return hooking_points = update_modules(pgd) if hooking_points is not None: # Update hooking points # 1) Remove the breakpoints not used anymore bps_to_remove = [] for hp in module_load_remove_breakpoints[pgd]: if hp not in hooking_points: bps_to_remove.append(hp) for hp in bps_to_remove: module_load_remove_breakpoints[pgd][hp].disable() del module_load_remove_breakpoints[pgd][hp] # 2) Add new breakpoints for hp in hooking_points: if hp not in module_load_remove_breakpoints[pgd]: module_base, addr, size = hp haddr = api.va_to_pa(pgd, addr) bp = BP(haddr, None, size = size, typ = BP.MEM_WRITE_PHYS, func = functools.partial(module_change_callback, pgd, addr, haddr), new_style = True) module_load_remove_breakpoints[pgd][hp] = bp bp.enable() else: # Just remove all the modules for the process # Mark all modules as non-present set_modules_non_present(None, pgd) # Remove all the modules that are not marked as present clean_non_present_modules(None, pgd)
def gdb_breakpoint_insert(thread_id, thread_list, addr, length, bp_type): ''' Insert a breakpoing for GDB ''' global gdb_breakpoint_list from api import BP import functools # Obtain PGD from thread thread = None # First, check if we can read the register from the CPU object for element in thread_list: if element['id'] == thread_id: thread = element break if thread is None: return 0 pgd = thread['pgd'] if bp_type not in gdb_breakpoint_list: gdb_breakpoint_list[bp_type] = {} if pgd not in gdb_breakpoint_list[bp_type]: gdb_breakpoint_list[bp_type][pgd] = {} if addr not in gdb_breakpoint_list[bp_type][pgd]: gdb_breakpoint_list[bp_type][pgd][addr] = [] nb_breakpoints_added = 0 if bp_type == GDB_BREAKPOINT_SW: f = functools.partial(gdb_breakpoint_callback, addr, pgd, length, bp_type) bp = BP(addr=addr, pgd=pgd, size=length, typ=BP.EXECUTION, func=f, new_style=True) bp.enable() gdb_breakpoint_list[bp_type][pgd][addr].append(bp) nb_breakpoints_added += 1 if bp_type == GDB_BREAKPOINT_HW: f = functools.partial(gdb_breakpoint_callback, addr, pgd, length, bp_type, new_style=True) bp = BP(addr=addr, pgd=pgd, size=length, typ=BP.EXECUTION, func=f) bp.enable() gdb_breakpoint_list[bp_type][pgd][addr].append(bp) nb_breakpoints_added += 1 if bp_type == GDB_WATCHPOINT_WRITE or bp_type == GDB_WATCHPOINT_ACCESS: f = functools.partial(gdb_breakpoint_callback, addr, pgd, length, bp_type, new_style=True) bp = BP(addr=addr, pgd=pgd, size=length, typ=BP.MEM_WRITE, func=f) bp.enable() gdb_breakpoint_list[bp_type][pgd][addr].append(bp) nb_breakpoints_added += 1 if bp_type == GDB_WATCHPOINT_READ or bp_type == GDB_WATCHPOINT_ACCESS: f = functools.partial(gdb_breakpoint_callback, addr, pgd, length, bp_type, new_style=True) bp = BP(addr=addr, pgd=pgd, size=length, typ=BP.MEM_READ, func=f) bp.enable() gdb_breakpoint_list[bp_type][pgd][addr].append(bp) nb_breakpoints_added += 1 return nb_breakpoints_added