def import_module(module_name): global MODULE_COUNTER import api_internal from ipython_shell import add_command try: already_imported = False for mod in modules: if module_name == modules[mod][0]: already_imported = True break if not already_imported: pp_print("[*] Importing %s\n" % module_name) mod = __import__(module_name, fromlist=['']) mod.initialize_callbacks( MODULE_COUNTER, functools.partial( api_internal.print_internal, module_name)) # Add commands declared by the module for element in dir(mod): if element.startswith("do_"): add_command(element[3:], getattr(mod, element)) modules[MODULE_COUNTER] = (module_name, mod) MODULE_COUNTER += 1 else: pp_warning("[*] Module %s already imported\n" % module_name) except Exception as e: pp_error("[!] Could not initialize python module due to exception\n") pp_error(" %s\n" % str(e)) return
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 import windows_vmi from utils import pp_print 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"] windows_vmi.windows_update_modules(proc_pgd,update_symbols=True) 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 for mod in diff_modules.values(): for ordinal,addr,name in mod.get_symbols(): syms.append({"mod": mod.get_name(),"name": name, "addr": addr}) return syms
def list_modules(): t = PrettyTable(["Hdl", "Module name", "Loaded"]) for mod in modules: t.add_row([ mod, modules[mod].get_module_name(), "Yes" if modules[mod].is_loaded() else "No" ]) pp_print(str(t) + "\n")
def unload(self): from ipython_shell import remove_command if self.__loaded is True: pp_print("[*] Unloading %s\n" % self.__module_name) # Add commands declared by the module for element in dir(self.__module): if element.startswith("do_"): remove_command(element[3:]) self.__module.clean() self.__loaded = False else: pp_warning("[*] Module %d is not loaded!\n" % self.__id)
def bp_func(bp_num, params): ''' Function to use as a callback on breakpoints ''' from ipython_shell import start_shell import api from utils import pp_print # The first argument of insn begin and mem write/read callbacks should # always be cpu_index cpu_index = params["cpu_index"] cpu = api.r_cpu(cpu_index) pp_print("[!] Breakpoint %s hit at address %x\n" % (bp_num, cpu.PC)) start_shell()
def load(self): import api_internal from ipython_shell import add_command pp_print("[*] Loading python module %s\n" % self.__module_name) self.__module = __import__(self.__module_name, fromlist=['']) self.__loaded = True self.__module.initialize_callbacks( self.__id, functools.partial(api_internal.print_internal, self.__module_name)) # Add commands declared by the module for element in dir(self.__module): if element.startswith("do_"): add_command(element[3:], getattr(self.__module, element))
def unload_module(mod): from ipython_shell import remove_command if isinstance(mod, int) and mod in modules: pp_print("[*] Unloading %s\n" % modules[mod][0]) # Add commands declared by the module for element in dir(modules[mod][1]): if element.startswith("do_"): remove_command(element[3:]) modules[mod][1].clean() # Remove module from list del modules[mod] else: pp_warning("[*] Module not loaded!\n")
def reload(self): import api_internal from ipython_shell import add_command if self.__module is not None: pp_print("[*] Reloading python module %s\n" % self.__module_name) if self.__loaded is True: self.unload() reload(self.__module) # Add again commands and call initialize_callbacks: self.__module.initialize_callbacks(self.__id, functools.partial(api_internal.print_internal, self.__module_name)) # Add commands declared by the module for element in dir(self.__module): if element.startswith("do_"): add_command(element[3:], getattr(self.__module, element)) self.__loaded = True else: pp_warning("[!] The module was not correctly imported!\n")
def load(self): import api_internal from ipython_shell import add_command pp_print("[*] Loading python module %s\n" % self.__module_name) self.__module = __import__(self.__module_name, fromlist=['']) # Import other modules or plugins required by the module if hasattr(self.__module, "requirements"): for el in self.__module.requirements: import_module(el) self.__loaded = True self.__module.initialize_callbacks(self.__id, functools.partial(api_internal.print_internal, self.__module_name)) # Add commands declared by the module for element in dir(self.__module): if element.startswith("do_"): add_command(element[3:], getattr(self.__module, element))
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 add_module(proc, params): global cm global interproc_breakpoints global entry_point_bps global breakpoints global bp_funcs from utils import ConfigurationManager as conf_m import api pid = params["pid"] pgd = params["pgd"] base = params["base"] size = params["size"] name = params["name"] fullname = params["fullname"] pid = proc.get_pid() pgd = proc.get_pgd() # Update Process instance with module info proc.set_module(fullname, base, size) from interproc_callbacks import ntcreateprocess from interproc_callbacks import ntopenprocess from interproc_callbacks import ntwritevirtualmemory from interproc_callbacks import ntreadvirtualmemory from interproc_callbacks import ntreadfile from interproc_callbacks import ntwritefile from interproc_callbacks import ntmapviewofsection from interproc_callbacks import ntunmapviewofsection from interproc_callbacks import ntvirtualprotect from interproc_callbacks import ntallocatevirtualmemory # Add callbacks, if ntdll is loaded if "windows/syswow64/ntdll.dll" in fullname.lower(): # breakpoints - Dictionary to store breakpoints for the following APIs: # bp_funcs - Dictionary that maps dll-function name to breakpoint callbacks and boolean # that tells whether the VAD list for the process must be updated after the call # or not. mod_name = "windows/syswow64/ntdll.dll" if (mod_name, "ZwOpenProcess") not in breakpoints: breakpoints[(mod_name, "ZwOpenProcess")] = None bp_funcs[(mod_name, "ZwOpenProcess")] = (ntopenprocess, True, 4) if (mod_name, "ZwReadFile") not in breakpoints: breakpoints[(mod_name, "ZwReadFile")] = None bp_funcs[(mod_name, "ZwReadFile")] = (ntreadfile, False, 4) if (mod_name, "ZwWriteFile") not in breakpoints: breakpoints[(mod_name, "ZwWriteFile")] = None bp_funcs[(mod_name, "ZwWriteFile")] = (ntwritefile, False, 4) if (mod_name, "ZwMapViewOfSection") not in breakpoints: breakpoints[(mod_name, "ZwMapViewOfSection")] = None bp_funcs[(mod_name, "ZwMapViewOfSection")] = (ntmapviewofsection, True, 4) if (mod_name, "ZwUnmapViewOfSection") not in breakpoints: breakpoints[(mod_name, "ZwUnmapViewOfSection")] = None bp_funcs[(mod_name, "ZwUnmapViewOfSection")] = (ntunmapviewofsection, True, 4) if (mod_name, "ZwWriteVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwWriteVirtualMemory")] = None bp_funcs[(mod_name, "ZwWriteVirtualMemory")] = (ntwritevirtualmemory, False, 4) if (mod_name, "ZwReadVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwReadVirtualMemory")] = None bp_funcs[(mod_name, "ZwReadVirtualMemory")] = (ntreadvirtualmemory, False, 4) if (mod_name, "ZwProtectVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwProtectVirtualMemory")] = None bp_funcs[(mod_name, "ZwProtectVirtualMemory")] = (ntvirtualprotect, False, 4) if (mod_name, "NtAllocateVirtualMemory") not in breakpoints: breakpoints[(mod_name, "NtAllocateVirtualMemory")] = None bp_funcs[(mod_name, "NtAllocateVirtualMemory")] = (ntallocatevirtualmemory, True, 4) profile = conf_m.vol_profile if (mod_name, "ZwCreateProcessEx") not in breakpoints: # We hook both, because although Kernel32 calls the "Ex" version, a # program may call directy ZwCreateProcess breakpoints[(mod_name, "ZwCreateProcessEx")] = None bp_funcs[(mod_name, "ZwCreateProcessEx")] = ( ntcreateprocess, True, 4) if (mod_name, "ZwCreateProcess") not in breakpoints: breakpoints[(mod_name, "ZwCreateProcess")] = None bp_funcs[(mod_name, "ZwCreateProcess")] = ( ntcreateprocess, True, 4) if not ("WinXP" in profile or "Win2003" in profile): # On Vista (and onwards), kernel32.dll no longer uses # ZwCreateProcess/ZwCreateProcessEx (although these function remain # in ntdll.dll. It Uses ZwCreateUserProcess. if (mod_name, "ZwCreateUserProcess") not in breakpoints: breakpoints[(mod_name, "ZwCreateUserProcess")] = None bp_funcs[(mod_name, "ZwCreateUserProcess")] = ( ntcreateprocess, True, 4) elif "windows/system32/ntdll.dll" in fullname.lower(): mod_name = "windows/system32/ntdll.dll" if (mod_name, "ZwOpenProcess") not in breakpoints: breakpoints[(mod_name, "ZwOpenProcess")] = None bp_funcs[(mod_name, "ZwOpenProcess")] = (ntopenprocess, True, TARGET_LONG_SIZE) if (mod_name, "ZwReadFile") not in breakpoints: breakpoints[(mod_name, "ZwReadFile")] = None bp_funcs[(mod_name, "ZwReadFile")] = (ntreadfile, False, TARGET_LONG_SIZE) if (mod_name, "ZwWriteFile") not in breakpoints: breakpoints[(mod_name, "ZwWriteFile")] = None bp_funcs[(mod_name, "ZwWriteFile")] = (ntwritefile, False, TARGET_LONG_SIZE) if (mod_name, "ZwMapViewOfSection") not in breakpoints: breakpoints[(mod_name, "ZwMapViewOfSection")] = None bp_funcs[(mod_name, "ZwMapViewOfSection")] = (ntmapviewofsection, True, TARGET_LONG_SIZE) if (mod_name, "ZwUnmapViewOfSection") not in breakpoints: breakpoints[(mod_name, "ZwUnmapViewOfSection")] = None bp_funcs[(mod_name, "ZwUnmapViewOfSection")] = (ntunmapviewofsection, True, TARGET_LONG_SIZE) if (mod_name, "ZwWriteVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwWriteVirtualMemory")] = None bp_funcs[(mod_name, "ZwWriteVirtualMemory")] = (ntwritevirtualmemory, False, TARGET_LONG_SIZE) if (mod_name, "ZwReadVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwReadVirtualMemory")] = None bp_funcs[(mod_name, "ZwReadVirtualMemory")] = (ntreadvirtualmemory, False, TARGET_LONG_SIZE) if (mod_name, "ZwProtectVirtualMemory") not in breakpoints: breakpoints[(mod_name, "ZwProtectVirtualMemory")] = None bp_funcs[(mod_name, "ZwProtectVirtualMemory")] = (ntvirtualprotect, False, TARGET_LONG_SIZE) if (mod_name, "NtAllocateVirtualMemory") not in breakpoints: breakpoints[(mod_name, "NtAllocateVirtualMemory")] = None bp_funcs[(mod_name, "NtAllocateVirtualMemory")] = (ntallocatevirtualmemory, True, TARGET_LONG_SIZE) profile = conf_m.vol_profile if (mod_name, "ZwCreateProcessEx") not in breakpoints: # We hook both, because although Kernel32 calls the "Ex" version, a # program may call directy ZwCreateProcess breakpoints[(mod_name, "ZwCreateProcessEx")] = None bp_funcs[(mod_name, "ZwCreateProcessEx")] = ( ntcreateprocess, True, TARGET_LONG_SIZE) if (mod_name, "ZwCreateProcess") not in breakpoints: breakpoints[(mod_name, "ZwCreateProcess")] = None bp_funcs[(mod_name, "ZwCreateProcess")] = ( ntcreateprocess, True, TARGET_LONG_SIZE) if not ("WinXP" in profile or "Win2003" in profile): # On Vista (and onwards), kernel32.dll no longer uses # ZwCreateProcess/ZwCreateProcessEx (although these function remain # in ntdll.dll. It Uses ZwCreateUserProcess. if (mod_name, "ZwCreateUserProcess") not in breakpoints: breakpoints[(mod_name, "ZwCreateUserProcess")] = None bp_funcs[(mod_name, "ZwCreateUserProcess")] = ( ntcreateprocess, True, TARGET_LONG_SIZE) # Add breakpoint if necessary for (mod, fun) in breakpoints: if breakpoints[(mod, fun)] is None: try: f_callback = bp_funcs[(mod, fun)][0] update_vads = bp_funcs[(mod, fun)][1] long_size = bp_funcs[(mod, fun)][2] callback = functools.partial( f_callback, cm=cm, proc=proc, update_vads=update_vads, long_size = long_size) bp = api.BP(str("%s!%s" % (mod, fun)), pgd, func = callback, new_style = True) bp.enable() interproc_breakpoints.append(bp) breakpoints[(mod, fun)] = (bp, bp.get_addr()) pp_print("Adding breakpoint at %s:%s %x:%x from process with PID %x\n" % (mod, fun, bp.get_addr(), pgd, pid)) except Exception as e: pyrebox_print("Could not set breakpoint on interproc: %s" % str(e)) # Main module of the process. Only set entry point callback if it has not been set already. # In some cases the main module gets reloaded. if name.lower() == proc.get_proc_name() and pgd not in entry_point_bps: # Set a breakpoint on the EP entry_point_bps[pgd] = api.BP(base, pgd, size = size, new_style = True, func = functools.partial(module_entry_point, proc)) entry_point_bps[pgd].enable() # Call all our internal callbacks interproc_data.deliver_load_module_callback(params)
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 list_modules(): t = PrettyTable(["Hdl", "Module name"]) for mod in modules: t.add_row([mod, modules[mod][0]]) pp_print(str(t) + "\n")
def __init__(self, pgd, section_object): import api global interproc_data TARGET_LONG_SIZE = api.get_os_bits() / 8 # Volatility object representing the section self.__section_object = section_object # Volatility lacks the vtype for _SECTION, which # has scarce documentation: # http://forum.sysinternals.com/section-object_topic24975.html # These structures seem to remain consistent # across different Windows versions. # typedef struct _MMADDRESS_NODE { # union { # LONG_PTR Balance : 2; # struct _MMADDRESS_NODE *Parent; # } u1; # struct _MMADDRESS_NODE *LeftChild; # struct _MMADDRESS_NODE *RightChild; # ULONG_PTR StartingVpn; # ULONG_PTR EndingVpn; # } MMADDRESS_NODE, *PMMADDRESS_NODE; # typedef struct _SECTION { # MMADDRESS_NODE Address; # PSEGMENT Segment; # LARGE_INTEGER SizeOfSection; # union { # ULONG LongFlags; # MMSECTION_FLAGS Flags; # } u; # MM_PROTECTION_MASK InitialPageProtection; # } SECTION, *PSECTION; # As we can see, Volatility has instead a _SECTION_OBJECT # vtype, which, consistently across Windows versions, # has at the beginning of the structure, 5 pointers, just # like the MMADDRESS_NODE for _SECTION. Therefore, the Segment # field seems to be at the same offset on both structures: # _SECTION and _SECTION_OBJECT, both for 32 and 64 bits. # Flags are located after Segment (PSEGMENT) + LARGE_INTEGER (64 bits independently of arch) # --> The offset should be the size of 6 pointers + size of LARGE_INTEGER # Flags are always 4 bytes # Compute FileBacked and CopyOnWrite try: self.__flags = struct.unpack( "I", api.r_va( pgd, self.__section_object.obj_offset + ((TARGET_LONG_SIZE * 6) + 8), 0x4))[0] except: self.__flags = 0x00000000 pp_print("Could not read flags in Section __init__\n") self.__cow = ((self.__flags & 0x00000800) != 0) self.__file_backed = ((self.__flags & 0x00000080) != 0) self.__backing_file = None # If so, get corresponding file. if self.__file_backed: # Dereference as _SEGMENT, that is different from _SEGMENT_OBJECT # This is because the volatility profile lacks the _SECTION object, # and instead has the _SECTION_OBJECT. Since the Segment field # of _SECTION and _SECTION_OBJECT are aligned, we can just dereference # that offset. Nevertheless, _SECTION_OBJECT has a _SEGMENT_OBJECT type # Segment, while _SECTION has a _SEGMENT type Segment... # http://forum.sysinternals.com/section-object_topic24975.html self.__segment = self.__section_object.Segment.dereference_as( "_SEGMENT") file_obj = self.__segment.ControlArea.FilePointer from volatility.plugins.overlays.windows.windows import _FILE_OBJECT from volatility.obj import Pointer # on winxp file_obj is volatility.obj.Pointer with .target being _FILE_OBJECT if not (type(file_obj) is Pointer and type(file_obj.dereference()) is _FILE_OBJECT): #from volatility.plugins.overlays.windows.windows import _EX_FAST_REF if "_EX_FAST_REF" in str(type(file_obj)): # on newer volatility profiles, FilePointer is _EX_FAST_REF, needs deref file_obj = file_obj.dereference_as("_FILE_OBJECT") else: raise TypeError("The type for self.segment.ControlArea.FilePointer in Section" + \ "class does not match _FILE_OBJECT or _EX_FAST_REF: %r (type %r)" % (file_obj, type(file_obj))) self.__backing_file = interproc_data.get_file_by_file_name( str(file_obj.FileName)) # If we have still not recorded the file, add it to files record if self.__backing_file is None: self.__backing_file = File(str(file_obj.FileName)) interproc_data.add_file(self.__backing_file) self.__unpickled = False self.__offset = self.__section_object.obj_offset
def list_modules(): t = PrettyTable(["Hdl", "Module name", "Loaded"]) for mod in modules: t.add_row([mod, modules[mod].get_module_name(), "Yes" if modules[mod].is_loaded() else "No"]) pp_print(str(t) + "\n")
def ntcreateprocessret(params, cm, callback_name, proc_hdl_p, proc, update_vads, long_size): import volatility.win32.tasks as tasks from interproc import interproc_start_monitoring_process from core import Process from api import get_running_process from utils import get_addr_space import api global interproc_data global interproc_config TARGET_LONG_SIZE = api.get_os_bits() / 8 cpu_index = params["cpu_index"] cpu = params["cpu"] pgd = get_running_process(cpu_index) # First, remove callback cm.rm_callback(callback_name) # Do not continue if EAX/RAX returns and invalid return code. if read_return_parameter(cpu) != 0: return # Load volatility address space addr_space = get_addr_space(pgd) # Get list of processes, and filter out by the process that triggered the # call (current process id) eprocs = [ t for t in tasks.pslist(addr_space) if t.UniqueProcessId == proc.get_pid() ] # Initialize proc_obj, that will point to the eprocess of the new created # process proc_obj = None # Dereference the output argument containing the hdl of the newly created # process proc_hdl = dereference_target_long(proc_hdl_p, pgd, long_size) # Search handle table for the new created process for task in eprocs: if task.UniqueProcessId == proc.get_pid( ) and task.ObjectTable.HandleTableList: for handle in task.ObjectTable.handles(): if handle.is_valid( ) and handle.HandleValue == proc_hdl and handle.get_object_type( ) == "Process": proc_obj = handle.dereference_as("_EPROCESS") break break if proc_obj is not None: if interproc_config.interproc_text_log and interproc_config.interproc_text_log_handle is not None: f = interproc_config.interproc_text_log_handle f.write("[PID: %08x] NtCreateProcess: %s - PID: %x - CR3: %x\n" % (proc.get_pid(), str( proc_obj.ImageFileName), int(proc_obj.UniqueProcessId), int(proc_obj.Pcb.DirectoryTableBase.v()))) # Check if we are already monitoring the process if interproc_data.get_process_by_pid(int( proc_obj.UniqueProcessId)) is not None: return pp_print("Following %s %x %x\n" % (proc_obj.ImageFileName, proc_obj.UniqueProcessId, proc_obj.Pcb.DirectoryTableBase.v())) params["pid"] = int(proc_obj.UniqueProcessId) params["pgd"] = int(proc_obj.Pcb.DirectoryTableBase.v()) params["name"] = str(proc_obj.ImageFileName) interproc_start_monitoring_process(params) else: if TARGET_LONG_SIZE == 4: pp_error( "Error while trying to retrieve EPROCESS for handle %x, PID %x, EAX: %x\n" % (proc_hdl, proc.get_pid(), cpu.EAX)) elif TARGET_LONG_SIZE == 8: pp_error( "Error while trying to retrieve EPROCESS for handle %x, PID %x, EAX: %x\n" % (proc_hdl, proc.get_pid(), cpu.RAX)) if update_vads: proc.update_vads() return