def get_module_list(pgd): """ Return list of modules for a given PGD :param pgd: The PGD of the process for which we want to extract the modules, or 0 to extract kernel modules :type pgd: int :return: List of modules, each element is a dictionary with keys: "name", "base", and "size" :rtype: list """ import vmi proc_list = get_process_list() mods = [] found = False if pgd == 0: proc_pid = 0 proc_pgd = 0 found = True else: for proc in proc_list: proc_pid = proc["pid"] proc_pgd = proc["pgd"] if proc_pgd == pgd: found = True break if found: vmi.update_modules(proc_pgd, update_symbols=False) if (proc_pid, proc_pgd) in vmi.modules: for mod in vmi.modules[(proc_pid, proc_pgd)].values(): mods.append({"name": mod.get_name(), "base": mod.get_base(), "size": mod.get_size()}) return mods else: raise ValueError("Process with PGD %x not found" % 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 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 get_symbol_list(): """ Return list of symbols :return: List of symbols, each element is a dictionary with keys: "mod", "name", and "addr" :rtype: list """ import vmi from utils import pp_print res_syms = [] diff_modules = {} proc_list = get_process_list() pp_print("[*] Updating symbol list... Be patient, this may take a while\n") for proc in proc_list: proc_pid = proc["pid"] proc_pgd = proc["pgd"] if proc_pgd != 0: vmi.update_modules(proc_pgd, update_symbols=True) if (proc_pid, proc_pgd) in vmi.modules: for module in vmi.modules[proc_pid, proc_pgd].values(): c = module.get_checksum() n = module.get_fullname() if (c, n) not in diff_modules: diff_modules[(c, n)] = module # Include kernel modules too vmi.update_modules(0, update_symbols=True) if (0, 0) in vmi.modules: for module in vmi.modules[0, 0].values(): c = module.get_checksum() n = module.get_fullname() if (c, n) not in diff_modules: diff_modules[(c, n)] = module for mod in diff_modules.values(): syms = mod.get_symbols() for name in syms: res_syms.append({ "mod": mod.get_name(), "name": name, "addr": syms[name] }) return res_syms
def get_module_list(pgd): """ Return list of modules for a given PGD :param pgd: The PGD of the process for which we want to extract the modules, or 0 to extract kernel modules :type pgd: int :return: List of modules, each element is a dictionary with keys: "name", "base", "size", and "symbols_resolved" :rtype: list """ import vmi proc_list = get_process_list() mods = [] found = False if pgd == 0: proc_pid = 0 proc_pgd = 0 found = True else: for proc in proc_list: proc_pid = proc["pid"] proc_pgd = proc["pgd"] if proc_pgd == pgd: found = True break if found: vmi.update_modules(proc_pgd, update_symbols=False) if (proc_pid, proc_pgd) in vmi.modules: for mod in vmi.modules[(proc_pid, proc_pgd)].values(): mods.append({"name": mod.get_name(), "base": mod.get_base(), "size": mod.get_size(), "symbols_resolved" : mod.are_symbols_resolved()}) return mods else: raise ValueError("Process with PGD %x not found" % pgd)
def get_symbol_list(pgd = None): """ Return list of symbols :param pgd: The pgd to obtain the symbols from. 0 to get kernel symbols :type pgd: int :return: List of symbols, each element is a dictionary with keys: "mod", "name", and "addr" :rtype: list """ import vmi from utils import pp_print res_syms = [] diff_modules = {} if pgd is None: proc_list = get_process_list() pp_print("[*] Updating symbol list... Be patient, this may take a while\n") for proc in proc_list: proc_pid = proc["pid"] proc_pgd = proc["pgd"] if proc_pgd != 0: vmi.update_modules(proc_pgd, update_symbols=True) if (proc_pid, proc_pgd) in vmi.modules: for module in vmi.modules[proc_pid, proc_pgd].values(): c = module.get_checksum() n = module.get_fullname() if (c, n) not in diff_modules: diff_modules[(c, n)] = [module] else: diff_modules[(c, n)].append(module) # Include kernel modules too vmi.update_modules(0, update_symbols=True) if (0, 0) in vmi.modules: for module in vmi.modules[0, 0].values(): c = module.get_checksum() n = module.get_fullname() if (c, n) not in diff_modules: diff_modules[(c, n)] = [module] else: diff_modules[(c, n)].append(module) else: pp_print("[*] Updating symbol list for one process... Be patient, this may take a while\n") vmi.update_modules(pgd, update_symbols=True) for proc_pid, proc_pgd in vmi.modules: if proc_pgd == pgd: for module in vmi.modules[proc_pid, proc_pgd].values(): c = module.get_checksum() n = module.get_fullname() if (c, n) not in diff_modules: diff_modules[(c, n)] = [module] else: diff_modules[(c, n)].append(module) for mod_list in diff_modules.values(): added_names = [] for mod in mod_list: syms = mod.get_symbols() for name in syms: if name not in added_names: res_syms.append({"mod": mod.get_name(), "name": name, "addr": syms[name]}) added_names.append(name) return res_syms
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)