def render_text(self, outfd, data): addr_space = utils.load_as(self._config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: outfd.write("SSDT[{0}] at {1:x} with {2} entries\n".format(idx, table, n)) for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" outfd.write(" Entry {0:#06x}: {1:#x} ({2}) owned by {3}\n".format(idx * 0x1000 + i, syscall_addr, syscall_name, syscall_modname)) ## check for inline hooks if in --verbose mode, we're analyzing ## an x86 model system and the sycall_mod is available if (self._config.VERBOSE and addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' and syscall_mod is not None): ## leverage this static method from apihooks ret = apihooks.ApiHooks.check_inline(va = syscall_addr, addr_space = vm, mem_start = syscall_mod.DllBase, mem_end = syscall_mod.DllBase + syscall_mod.SizeOfImage) ## could not analyze the memory if ret == None: continue (hooked, data, dest_addr) = ret ## the function isn't hooked if not hooked: continue ## we found a hook, try to resolve the hooker. no mask required because ## we currently only work on x86 anyway hook_mod = tasks.find_module(mods, mod_addrs, dest_addr) if hook_mod: hook_name = hook_mod.BaseDllName else: hook_name = "UNKNOWN" ## report it now outfd.write(" ** INLINE HOOK? => {0:#x} ({1})\n".format(dest_addr, hook_name))
def calculate(self): addr_space = utils.load_as(self._config) modlist = list(modules.lsmod(addr_space)) mods = dict( (addr_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) drivers = dtree.DriverIrp(self._config).calculate() driver_name = "UNKNOWN" service_key = "UNKNOWN" driver_name3 = "UNKNOWN" module_name = "UNKNOWN" if self._config.ADDR: find_address = self._config.ADDR module_name = tasks.find_module( mods, mod_addrs, list(mods.values())[0].obj_vm.address_mask(find_address), ) if module_name: module_name = (module_name.BaseDllName or module_name.FullDllName) for driver in drivers: if (driver.DriverStart <= find_address < driver.DriverStart + driver.DriverSize): header = driver.get_object_header() driver_name = header.NameInfo.Name driver_name = str(driver.get_object_header().NameInfo.Name or '') service_key = str(driver.DriverExtension.ServiceKeyName or '') driver_name3 = str(driver.DriverName or '') break yield (module_name, driver_name, service_key, driver_name3) else: for driver in drivers: driver_name = str(driver.get_object_header().NameInfo.Name or '') service_key = str(driver.DriverExtension.ServiceKeyName or '') driver_name3 = str(driver.DriverName or '') owning_module = tasks.find_module( mods, mod_addrs, list(mods.values())[0].obj_vm.address_mask( driver.DriverStart), ) module_name = "UNKNOWN" if owning_module: module_name = (owning_module.BaseDllName or owning_module.FullDllName) yield (module_name, driver_name, service_key, driver_name3)
def render_text(self, outfd, data): addr_space = utils.load_as(self._config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: outfd.write("SSDT[{0}] at {1:x} with {2} entries\n".format(idx, table, n)) for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, syscall_addr) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" outfd.write(" Entry {0:#06x}: {1:#x} ({2}) owned by {3}\n".format(idx * 0x1000 + i, syscall_addr, syscall_name, syscall_modname))
def __init__(self, start, stack_base, stack_limit, eproc, modules=None, module_addrs=None, *args, **kwargs): EBP.__init__(self, start, stack_base, stack_limit, eproc, *args, **kwargs) if modules == None: self.modules = dict( (m.DllBase, m) for m in list(sysmods.lsmod(eproc.get_process_address_space())) + list(eproc.get_load_modules()) ) self.module_addrs = sorted(self.modules.keys()) else: self.modules = modules self.module_addrs = module_addrs mod = tasks.find_module(self.modules, self.module_addrs, self.eip) self.security_cookie = None self.cookie = None security_cookie_addr = None if mod != None: load_config = mod.get_load_config_directory() if load_config == None: # Attempt to use PDB symbols to locate this module's ___security_cookie addrs = eproc.lookup("{0}/.data!___security_cookie".format(str(mod.BaseDllName))) if len(addrs) > 0: security_cookie_addr = addrs[0] else: # Use _IMAGE_LOAD_CONFIG_DIRECTORY to locate this module's ___security_cookie security_cookie_addr = load_config.SecurityCookie if security_cookie_addr != None and self.addrspace.is_valid_address(security_cookie_addr): self.security_cookie = self.addrspace.read_long_phys(self.addrspace.vtop(security_cookie_addr)) if self.addrspace.is_valid_address(self.ebp - self.alignment): self.cookie = self.addrspace.read_long_phys(self.addrspace.vtop(self.ebp - self.alignment))
def callbacks(self): """Volatility callbacks plugin. @see volatility/plugins/malware/callbacks.py """ log.debug("Executing Volatility callbacks plugin on " "{0}".format(self.memdump)) self.__config() results = [] command = self.plugins["callbacks"](self.config) for (sym, cb, detail), mods, mod_addrs in command.calculate(): module = tasks.find_module(mods, mod_addrs, self.addr_space.address_mask(cb)) if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" new = { "type": str(sym), "callback": hex(int(cb)), "module": str(module_name), "details": str(detail or "-"), } results.append(new) return dict(config={}, data=results)
def callbacks(self): """Volatility callbacks plugin. @see volatility/plugins/malware/callbacks.py """ results = [] command = self.plugins["callbacks"](self.config) for (sym, cb, detail), mods, mod_addrs in command.calculate(): module = tasks.find_module(mods, mod_addrs, self.addr_space.address_mask(cb)) if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" new = { "type": str(sym), "callback": hex(int(cb)), "module": str(module_name), "details": str(detail or "-"), } results.append(new) return dict(config={}, data=results)
def calculate(self): addr_space = utils.load_as(self._config) # Currently we only support x86. The x64 does still have a IDT # but hooking is prohibited and results in bugcheck. if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) for kpcr in tasks.get_kdbg(addr_space).kpcrs(): # Get the GDT for access to selector bases gdt = dict((i * 8, sd) for i, sd in kpcr.gdt_entries()) for i, entry in kpcr.idt_entries(): # Where the IDT entry points. addr = entry.Address # Per MITRE, add the GDT selector base if available. # This allows us to detect sneaky attempts to hook IDT # entries by changing the entry's GDT selector. gdt_entry = gdt.get(entry.Selector.v()) if gdt_entry != None and "Code" in gdt_entry.Type: addr += gdt_entry.Base # Lookup the function's owner module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(addr)) yield i, entry, addr, module
def render_text(self, outfd, data): self.table_header( outfd, [ ("Type", "36"), ("Callback", "[addrpad]"), ("Module", "20"), ("Details", ""), ], ) for (sym, cb, detail), mods, mod_addrs in data: module = tasks.find_module( mods, mod_addrs, list(mods.values())[0].obj_vm.address_mask(cb)) ## The original callbacks plugin searched driver objects ## if the owning module isn't found (Rustock.B). We leave that ## task up to the user this time, and will be incoporating ## some different module association methods later. if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" self.table_row(outfd, sym, cb, module_name, detail or "-")
def render_text(self, outfd, data): # Kernel AS for looking up modules kernel_space = utils.load_as(self._config) # Modules sorted for address lookups mods = dict((kernel_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(kernel_space)) mod_addrs = sorted(mods.keys()) for session in data: outfd.write("*" * 50 + "\n") outfd.write("Session(V): {0:x} ID: {1} Processes: {2}\n".format( session.obj_offset, session.SessionId, len(list(session.processes())), )) outfd.write("PagedPoolStart: {0:x} PagedPoolEnd {1:x}\n".format( session.PagedPoolStart, session.PagedPoolEnd, )) for process in session.processes(): outfd.write(" Process: {0} {1} {2}\n".format( process.UniqueProcessId, process.ImageFileName, process.CreateTime, )) for image in session.images(): module = tasks.find_module(mods, mod_addrs, kernel_space.address_mask(image.Address)) outfd.write(" Image: {0:#x}, Address {1:x}, Name: {2}\n".format( image.obj_offset, image.Address, str(module and module.BaseDllName or '') ))
def calculate(self): if not has_yara: debug.error( "Please install Yara from https://plusvic.github.io/yara/") addr_space = utils.load_as(self._config) rules = self._compile_rules() if self._config.KERNEL: # Find KDBG so we know where kernel memory begins. Do not assume # the starting range is 0x80000000 because we may be dealing with # an image with the /3GB boot switch. kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") # Modules so we can map addresses to owners mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # There are multiple views (GUI sessions) of kernel memory. # Since we're scanning virtual memory and not physical, # all sessions must be scanned for full coverage. This # really only has a positive effect if the data you're # searching for is in GUI memory. sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId # Skip sessions we've already seen if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = DiscontigYaraScanner(address_space=session_space, rules=rules) for hit, address in scanner.scan(start_offset=start): module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(address)) yield (module, address, hit, session_space.zread(address - self._config.REVERSE, self._config.SIZE)) else: for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): yield (task, address, hit, scanner.address_space.zread( address - self._config.REVERSE, self._config.SIZE))
def render_text(self, outfd, data): # Kernel AS for looking up modules kernel_space = utils.load_as(self._config) # Modules sorted for address lookups mods = dict((kernel_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(kernel_space)) mod_addrs = sorted(mods.keys()) for session in data: outfd.write("*" * 50 + "\n") outfd.write("Session(V): {0:x} ID: {1} Processes: {2}\n".format( session.obj_offset, session.SessionId, len(list(session.processes())), )) outfd.write("PagedPoolStart: {0:x} PagedPoolEnd {1:x}\n".format( session.PagedPoolStart, session.PagedPoolEnd, )) for process in session.processes(): outfd.write(" Process: {0} {1} {2}\n".format( process.UniqueProcessId, process.ImageFileName, process.CreateTime, )) for image in session.images(): module = tasks.find_module( mods, mod_addrs, kernel_space.address_mask(image.Address)) outfd.write( " Image: {0:#x}, Address {1:x}, Name: {2}\n".format( image.obj_offset, image.Address, str(module and module.BaseDllName or '')))
def render_text(self, outfd, data): addr_space = utils.load_as(self._config) # Compile the regular expression for filtering by driver name if self._config.regex != None: mod_re = re.compile(self._config.regex, re.I) else: mod_re = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) bits = addr_space.profile.metadata.get('memory_model', '32bit') self.table_header(None, [('i', ">4"), ('Funcs', "36"), ('addr', '[addrpad]'), ('name', '')]) for object_obj, driver_obj, _ in data: driver_name = str(object_obj.NameInfo.Name or '') # Continue if a regex was supplied and it doesn't match if mod_re != None: if not (mod_re.search(driver_name) or mod_re.search(driver_name)): continue # Write the standard header for each driver object outfd.write("{0}\n".format("-" * 50)) outfd.write("DriverName: {0}\n".format(driver_name)) outfd.write("DriverStart: {0:#x}\n".format(driver_obj.DriverStart)) outfd.write("DriverSize: {0:#x}\n".format(driver_obj.DriverSize)) outfd.write("DriverStartIo: {0:#x}\n".format( driver_obj.DriverStartIo)) # Write the address and owner of each IRP function for i, function in enumerate(driver_obj.MajorFunction): function = driver_obj.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '') else: module_name = "Unknown" # This is where we check for inline hooks once the # ApiHooks plugin is ported to 2.1. self.table_row(outfd, i, MAJOR_FUNCTIONS[i], function, module_name) if self._config.verbose: data = addr_space.zread(function, 64) outfd.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(data=data, start=function, bits=bits, stoponret=True) ])) outfd.write("\n")
def get_hooked_tables(self, addr_space): """This function finds SSDTs in an address space, checks if there are any hooked functions in the SSDTs, and returns a dictionary where SSDT base addresses are the keys and the values are lists of hooked function names. @param addr_space: a kernel address space. """ # Names of the legit executive modules for SSDT tables executive_modules = [ # SSDT 0 ["ntoskrnl.exe", "ntkrnlpa.exe", "ntkrnlmp.exe", "ntkrpamp.exe"], # SSDT 1 ["win32k.sys"], # SSDT 2 ["spud.sys"], # SSDT 3 [] ] syscalls = addr_space.profile.syscalls hooked_tables = {} for info in ssdt.SSDT(self._config).calculate(): idx, table, n, vm, mods, mod_addrs = info # This is straight out of ssdt.py. Too bad there's no better way # to not duplicate code? for i in range(n): if self.bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs # relative to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, syscall_addr) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" if str(syscall_modname).lower() not in executive_modules[idx]: fields = (i, syscall_name, syscall_addr, syscall_modname) if table in hooked_tables: hooked_tables[table].append(fields) else: hooked_tables[table] = [(fields)] return hooked_tables
def render_text(self, outfd, data): addr_space = utils.load_as(self._config) # Compile the regular expression for filtering by driver name if self._config.regex != None: mod_re = re.compile(self._config.regex, re.I) else: mod_re = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) bits = addr_space.profile.metadata.get('memory_model', '32bit') self.table_header(None, [('i', ">4"), ('Funcs', "36"), ('addr', '[addrpad]'), ('name', '') ]) for driver in data: header = driver.get_object_header() driver_name = str(header.NameInfo.Name or '') # Continue if a regex was supplied and it doesn't match if mod_re != None: if not (mod_re.search(driver_name) or mod_re.search(driver_name)): continue # Write the standard header for each driver object outfd.write("{0}\n".format("-" * 50)) outfd.write("DriverName: {0}\n".format(driver_name)) outfd.write("DriverStart: {0:#x}\n".format(driver.DriverStart)) outfd.write("DriverSize: {0:#x}\n".format(driver.DriverSize)) outfd.write("DriverStartIo: {0:#x}\n".format(driver.DriverStartIo)) # Write the address and owner of each IRP function for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '') else: module_name = "Unknown" # This is where we check for inline hooks once the # ApiHooks plugin is ported to 2.1. self.table_row(outfd, i, MAJOR_FUNCTIONS[i], function, module_name) if self._config.verbose: data = addr_space.zread(function, 64) outfd.write("\n".join( ["{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(data = data, start = function, bits = bits, stoponret = True) ])) outfd.write("\n")
def get_hooked_tables(self, addr_space): """This function finds SSDTs in an address space, checks if there are any hooked functions in the SSDTs, and returns a dictionary where SSDT base addresses are the keys and the values are lists of hooked function names. @param addr_space: a kernel address space. """ # Names of the legit executive modules for SSDT tables executive_modules = [ # SSDT 0 ["ntoskrnl.exe", "ntkrnlpa.exe", "ntkrnlmp.exe", "ntkrpamp.exe"], # SSDT 1 ["win32k.sys"], # SSDT 2 ["spud.sys"], # SSDT 3 []] syscalls = addr_space.profile.syscalls hooked_tables = {} for info in ssdt.SSDT(self._config).calculate(): idx, table, n, vm, mods, mod_addrs = info # This is straight out of ssdt.py. Too bad there's no better way # to not duplicate code? for i in range(n): if self.bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs # relative to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, syscall_addr) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" if str(syscall_modname).lower() not in executive_modules[idx]: fields = (i, syscall_name, syscall_addr, syscall_modname) if hooked_tables.has_key(table): hooked_tables[table].append(fields) else: hooked_tables[table] = [(fields)] return hooked_tables
def check(self): """This check is True for system threads whose start address do not map back to known/loaded kernel drivers.""" module = tasks.find_module(self.mods, self.mod_addrs, self.thread.StartAddress) return ('PS_CROSS_THREAD_FLAGS_SYSTEM' in self.flags and module == None)
def calculate(self): if not has_pydeep: debug.error( "Please install ssdeep and pydeep from http://ssdeep.sourceforge.net/ and https://github.com/kbandla/pydeep" ) addr_space = utils.load_as(self._config) self._addr_space = addr_space page_sig = self._pydeep_page() if page_sig == None: debug.error("Pydeep was not able to hash the input") if self._config.KERNEL: # Find KDBG so we know where kernel memory begins. Do not assume # the starting range is 0x80000000 because we may be dealing with # an image with the /3GB boot switch. kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") # Modules so we can map addresses to owners mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # There are multiple views (GUI sessions) of kernel memory. # Since we're scanning virtual memory and not physical, # all sessions must be scanned for full coverage. This # really only has a positive effect if the data you're # searching for is in GUI memory. sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId # Skip sessions we've already seen if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = DiscontigSSDeepScanner(address_space=session_space, rules=rules) for hit, address in scanner.scan(start_offset=start): module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address)) yield (module, address, hit, session_space.zread(address - self._config.REVERSE, self._config.SIZE)) else: for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = VadSSDeepScanner(task=task, pydeep_hash=page_sig) for sig, vStart, vLength, offset, alike in scanner.scan(): yield (task, sig, vStart, vLength, offset, alike, scanner.address_space.zread(offset, 0x1000))
def calculate(self): addr_space = utils.load_as(self._config) modlist = list(modules.lsmod(addr_space)) mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) drivers = dtree.DriverIrp(self._config).calculate() driver_name = "UNKNOWN" service_key = "UNKNOWN" driver_name3 = "UNKNOWN" module_name = "UNKNOWN" if self._config.ADDR: find_address = self._config.ADDR module_name = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(find_address)) if module_name: module_name = module_name.BaseDllName or module_name.FullDllName for driver in drivers: if driver.DriverStart <= find_address < driver.DriverStart + driver.DriverSize: header = driver.get_object_header() driver_name = header.NameInfo.Name driver_name = str(driver.get_object_header().NameInfo.Name or '') service_key = str(driver.DriverExtension.ServiceKeyName or '') driver_name3 = str(driver.DriverName or '') break yield (module_name, driver_name, service_key, driver_name3) else: for driver in drivers: driver_name = str(driver.get_object_header().NameInfo.Name or '') service_key = str(driver.DriverExtension.ServiceKeyName or '') driver_name3 = str(driver.DriverName or '') owning_module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(driver.DriverStart)) module_name = "UNKNOWN" if owning_module: module_name = owning_module.BaseDllName or owning_module.FullDllName yield (module_name, driver_name, service_key, driver_name3)
def calculate(self): addr_space = utils.load_as(self._config) modlist = list(modules.lsmod(addr_space)) mods = dict( (addr_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) drivers = dtree.DriverIrp(self._config).calculate() found_driver = "UNKNOWN" if self._config.ADDR: find_address = self._config.ADDR found_module = tasks.find_module( mods, mod_addrs, mods.values()[0].obj_vm.address_mask(find_address)) if found_module: found_module = found_module.BaseDllName or found_module.FullDllName else: found_module = "UNKNOWN" for driver in drivers: if driver.DriverStart <= find_address < driver.DriverStart + driver.DriverSize: header = driver.get_object_header() found_driver = header.NameInfo.Name break yield (found_module, found_driver) else: for driver in drivers: driver_name = driver.get_object_header().NameInfo.Name owning_module = tasks.find_module( mods, mod_addrs, mods.values()[0].obj_vm.address_mask(driver.DriverStart)) if owning_module: module_name = owning_module.BaseDllName or owning_module.FullDllName else: module_name = "UNKNOWN" yield (module_name, driver_name)
def get_alloc(self, addr_space): ''' Mimics volatility's PPP plugin. ''' import volatility.plugins.malware.callbacks as callbacks import volatility.win32.tasks as tasks # for conn in connections.Connections(self.vol.config).calculate(): vol_callback = callbacks.Callbacks(self.vol.config) for (sym, cb, detail), mods, mod_addrs in vol_callback.calculate(): module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(cb)) yield Callback(module, sym, cb, detail, 0)
def check(self): """This check is True for system threads whose start address do not map back to known/loaded kernel drivers.""" # Take the address space from any module object addr_space = self.mods.values()[0].obj_vm module = tasks.find_module(self.mods, self.mod_addrs, addr_space.address_mask(self.thread.StartAddress)) return ('PS_CROSS_THREAD_FLAGS_SYSTEM' in self.flags and module == None)
def calculate(self): if not has_yara: debug.error("Please install Yara from code.google.com/p/yara-project") addr_space = utils.load_as(self._config) rules = self._compile_rules() if self._config.KERNEL: # Find KDBG so we know where kernel memory begins. Do not assume # the starting range is 0x80000000 because we may be dealing with # an image with the /3GB boot switch. kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") # Modules so we can map addresses to owners mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # There are multiple views (GUI sessions) of kernel memory. # Since we're scanning virtual memory and not physical, # all sessions must be scanned for full coverage. This # really only has a positive effect if the data you're # searching for is in GUI memory. sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId # Skip sessions we've already seen if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = DiscontigYaraScanner(address_space = session_space, rules = rules) for hit, address in scanner.scan(start_offset = start): module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address)) yield (module, address, hit, session_space.zread(address, 1024)) else: for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = VadYaraScanner(task = task, rules = rules) for hit, address in scanner.scan(): yield (task, address, hit, scanner.address_space.zread(address, 1024))
def calculate(self): addr_space = utils.load_as(self._config) modlist = list(modules.lsmod(addr_space)) mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) drivers = dtree.DriverIrp(self._config).calculate() found_driver = "UNKNOWN" if self._config.ADDR: find_address = self._config.ADDR found_module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(find_address)) if found_module: found_module = found_module.BaseDllName or found_module.FullDllName else: found_module = "UNKNOWN" for driver in drivers: if driver.DriverStart <= find_address < driver.DriverStart + driver.DriverSize: header = driver.get_object_header() found_driver = header.NameInfo.Name break yield (found_module, found_driver) else: for driver in drivers: driver_name = driver.get_object_header().NameInfo.Name owning_module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(driver.DriverStart)) if owning_module: module_name = owning_module.BaseDllName or owning_module.FullDllName else: module_name = "UNKNOWN" yield (module_name, driver_name)
def decide(analyzer, signatures): breach = False ioc_list = [] rootkit_signatures = signatures.get("rootkits", {}) entries = rootkit_signatures.get("entries", []) aux = analyzer.run_plugin("ssdt", "SSDT") config_obj = analyzer.get_config() addr_space = utils.load_as(config_obj) syscalls = addr_space.profile.syscalls # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in aux: for i in range(n): # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module( mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" # must match all values that are filled (empty values accept any) for entry in entries: address = entry.get("address", syscall_addr) name = entry.get("name", syscall_name) module = entry.get("module", syscall_modname) matches_rule = address == str( hex(syscall_addr)) and name == str( syscall_name) and module == str(syscall_modname) if matches_rule: ioc_list.append([ "-- Rootkits IoC --", str(hex(syscall_addr)), syscall_name, syscall_modname ]) return decision_tree.Decision(ioc_list, breach)
def get_alloc(self, addr_space): ''' Mimics volatility's PPP plugin. ''' import volatility.plugins.malware.callbacks as callbacks import volatility.win32.tasks as tasks # for conn in connections.Connections(self.vol.config).calculate(): vol_callback = callbacks.Callbacks(self.vol.config) for (sym, cb, detail), mods, mod_addrs in vol_callback.calculate(): module = tasks.find_module( mods, mod_addrs, mods.values()[0].obj_vm.address_mask(cb)) yield Callback(module, sym, cb, detail, 0)
def execute(self, config): addr_space = utils.load_as(config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' data = SSDTS.SSDT(config).calculate() sdtObjectList = datastructs.rootType() # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: sdtObject = sdtObjectList.SSDTs.SSDT.add() sdtObject.VirtAddr = table sdtEntries = sdtObject.SSDTEntries sdtEntries.count = n for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module( mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" sdtEntry = sdtEntries.SSDTEntry.add() sdtEntry.FunctionName = adutils.SmartUnicode(syscall_name) sdtEntry.ModuleName = adutils.SmartUnicode(syscall_modname) sdtEntry.VirtAddr = int(syscall_addr) sdtsfile = open(config.OUTPUT_PATH + "sdts.xml", "w") #sdtsfile.write(sdtObjectList.SerializeToString()) sdtsfile.write(proto2xml(sdtObjectList, indent=0)) logging.debug("Completed exporting the sdts on the system")
def _scan_kernel_memory(self, addr_space, rules): # Find KDBG so we know where kernel memory begins. Do not assume # the starting range is 0x80000000 because we may be dealing with # an image with the /3GB boot switch. kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") # Modules so we can map addresses to owners mods = dict( (addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space) ) mod_addrs = sorted(mods.keys()) # There are multiple views (GUI sessions) of kernel memory. # Since we're scanning virtual memory and not physical, # all sessions must be scanned for full coverage. This # really only has a positive effect if the data you're # searching for is in GUI memory. sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId # Skip sessions we've already seen if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = DiscontigYaraScanner( address_space=session_space, rules=rules ) for hit, address in scanner.scan(start_offset=start): module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(address) ) yield ( module, address - self._config.REVERSE, hit, session_space.zread( address - self._config.REVERSE, self._config.SIZE ), )
def generator(self, data): for (sym, cb, detail), mods, mod_addrs in data: module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(cb)) ## The original callbacks plugin searched driver objects ## if the owning module isn't found (Rustock.B). We leave that ## task up to the user this time, and will be incoporating ## some different module association methods later. if module: module_name = module.FullDllName or module.BaseDllName else: module_name = "UNKNOWN" yield (0, [str(sym), Address(cb), str(module_name), str(detail or "-")])
def execute(self,config): addr_space = utils.load_as(config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' data = SSDTS.SSDT(config).calculate() sdtObjectList = datastructs.rootType() # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: sdtObject = sdtObjectList.SSDTs.SSDT.add() sdtObject.VirtAddr=table sdtEntries = sdtObject.SSDTEntries sdtEntries.count=n for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" sdtEntry = sdtEntries.SSDTEntry.add() sdtEntry.FunctionName=adutils.SmartUnicode(syscall_name) sdtEntry.ModuleName=adutils.SmartUnicode(syscall_modname) sdtEntry.VirtAddr=int(syscall_addr) sdtsfile = open(config.OUTPUT_PATH + "sdts.xml", "w") #sdtsfile.write(sdtObjectList.SerializeToString()) sdtsfile.write(proto2xml(sdtObjectList,indent=0)) logging.debug("Completed exporting the sdts on the system")
def calculate(self): addr_space = utils.load_as(self._config) if addr_space.profile.metadata.get("memory_model", "") == "32bit": inc = 4 else: inc = 8 srv_module = self._get_srv(addr_space) if not srv_module: debug.error("Driver srv.sys not found.") return if not self._config.PDB_FILE: guid, pdb = self._get_debug_symbols(addr_space, srv_module) pdb_file = self._download_pdb_file(guid, pdb) if not pdb_file: debug.error( "The pdb file could not be downloaded. Try it with the PDB_FILE option." ) return else: pdb_file = self._config.PDB_FILE off_sym = self._get_srvtrans_symbol(pdb_file, srv_module.DllBase) if not off_sym: debug.error( "SrvTransaction2DispatchTable symbol address not found") return rva_sym = off_sym + srv_module.DllBase mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in win32.modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) for i in range(17): if inc == 4: addr = struct.unpack("<I", addr_space.zread(rva_sym, inc))[0] else: addr = struct.unpack("<Q", addr_space.zread(rva_sym, inc))[0] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(addr)) rva_sym += inc yield Address(addr), module
def render_text(self, outfd, data): outfd.write("{0}||{1}||{2}||{3}\n".format('Type', 'Callback', 'Module', 'Details')) for (sym, cb, detail), mods, mod_addrs in data: module = tasks.find_module(mods, mod_addrs, self.kern_space.address_mask(cb)) ## The original callbacks plugin searched driver objects ## if the owning module isn't found (Rustock.B). We leave that ## task up to the user this time, and will be incoporating ## some different module association methods later. if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" outfd.write("{0}||{1:#x}||{2}||{3}\n".format(sym, cb, module_name, detail or "-" ))
def decide(analyzer, signatures): breach = False ioc_list = [] rootkit_signatures = signatures.get("rootkits", {}) entries = rootkit_signatures.get("entries", []) aux = analyzer.run_plugin("ssdt", "SSDT") config_obj = analyzer.get_config() addr_space = utils.load_as(config_obj) syscalls = addr_space.profile.syscalls # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in aux: for i in range(n): # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" # must match all values that are filled (empty values accept any) for entry in entries: address = entry.get("address", syscall_addr) name = entry.get("name", syscall_name) module = entry.get("module", syscall_modname) matches_rule = address == str(hex(syscall_addr)) and name == str(syscall_name) and module == str(syscall_modname) if matches_rule: ioc_list.append(["-- Rootkits IoC --", str(hex(syscall_addr)) , syscall_name, syscall_modname ]) return decision_tree.Decision(ioc_list, breach)
def calculate(self): if not has_yara: debug.error( "Please install Yara from code.google.com/p/yara-project") addr_space = utils.load_as(self._config) rules = yara.compile(sources=ghost_sig) decrypted_data = None mal_proc = {} kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = malfind.DiscontigYaraScanner(address_space=session_space, rules=rules) for hit, address in scanner.scan(start_offset=start): module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address)) content = session_space.zread(address, 1024) header_size = content.find("\x78\x9c") magic_header_size = header_size - 8 magic_keyword = content[:magic_header_size] comp_uncomp_size = content[magic_header_size:header_size] s = struct.Struct("I I") comp_size, uncomp_size = s.unpack(comp_uncomp_size) enc_data = content[0:comp_size] to_decrypt = content[header_size:comp_size] dec_data = self.decrypt_communication(to_decrypt) if not mal_proc: self.get_ghost_process(magic_keyword, mal_proc, addr_space) os_version = self.get_os_version(addr_space) yield (mal_proc, address, magic_keyword, enc_data, dec_data, os_version)
def __init__(self, start, stack_base, stack_limit, eproc, modules=None, module_addrs=None, *args, **kwargs): EBP.__init__(self, start, stack_base, stack_limit, eproc, *args, **kwargs) if modules == None: self.modules = dict( (m.DllBase, m) for m in list(sysmods.lsmod(eproc.get_process_address_space())) + list(eproc.get_load_modules())) self.module_addrs = sorted(self.modules.keys()) else: self.modules = modules self.module_addrs = module_addrs mod = tasks.find_module(self.modules, self.module_addrs, self.eip) self.security_cookie = None self.cookie = None security_cookie_addr = None if mod != None: load_config = mod.get_load_config_directory() if load_config == None: # Attempt to use PDB symbols to locate this module's ___security_cookie addrs = eproc.lookup("{0}/.data!___security_cookie".format( str(mod.BaseDllName))) if len(addrs) > 0: security_cookie_addr = addrs[0] else: # Use _IMAGE_LOAD_CONFIG_DIRECTORY to locate this module's ___security_cookie security_cookie_addr = load_config.SecurityCookie if security_cookie_addr != None and self.addrspace.is_valid_address( security_cookie_addr): self.security_cookie = self.addrspace.read_long_phys( self.addrspace.vtop(security_cookie_addr)) if self.addrspace.is_valid_address(self.ebp - self.alignment): self.cookie = self.addrspace.read_long_phys( self.addrspace.vtop(self.ebp - self.alignment))
def calculate(self): if not has_yara: debug.error("Please install Yara from code.google.com/p/yara-project") addr_space = utils.load_as(self._config) rules = yara.compile(sources=ghost_sig) decrypted_data = None mal_proc = {} kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = malfind.DiscontigYaraScanner(address_space = session_space, rules = rules) for hit, address in scanner.scan(start_offset = start): module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address)) content = session_space.zread(address,1024) header_size = content.find("\x78\x9c") magic_header_size = header_size - 8 magic_keyword = content[:magic_header_size] comp_uncomp_size = content[magic_header_size:header_size] s = struct.Struct("I I") comp_size, uncomp_size = s.unpack(comp_uncomp_size) enc_data = content[0:comp_size] to_decrypt = content[header_size:comp_size] dec_data = self.decrypt_communication(to_decrypt) if not mal_proc: self.get_ghost_process(magic_keyword, mal_proc, addr_space) os_version = self.get_os_version(addr_space) yield (mal_proc, address, magic_keyword, enc_data, dec_data, os_version)
def generator(self, data): for (sym, cb, detail), mods, mod_addrs in data: module = tasks.find_module( mods, mod_addrs, mods.values()[0].obj_vm.address_mask(cb)) ## The original callbacks plugin searched driver objects ## if the owning module isn't found (Rustock.B). We leave that ## task up to the user this time, and will be incoporating ## some different module association methods later. if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" yield (0, [ str(sym), Address(cb), str(module_name), str(detail or "-") ])
def render_text(self, outfd, data): self.table_header(outfd, [("Type", "36"), ("Callback", "[addrpad]"), ("Module", "20"), ("Details", ""), ]) for (sym, cb, detail), mods, mod_addrs in data: module = tasks.find_module(mods, mod_addrs, mods.values()[0].obj_vm.address_mask(cb)) ## The original callbacks plugin searched driver objects ## if the owning module isn't found (Rustock.B). We leave that ## task up to the user this time, and will be incoporating ## some different module association methods later. if module: module_name = module.BaseDllName or module.FullDllName else: module_name = "UNKNOWN" self.table_row(outfd, sym, cb, module_name, detail or "-")
def render_text(self, outfd, data): addr_space = utils.load_as(self._config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: outfd.write("SSDT[{0}] at {1:x} with {2} entries\n".format( idx, table, n)) for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, syscall_addr) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" outfd.write( " Entry {0:#06x}: {1:#x} ({2}) owned by {3}\n".format( idx * 0x1000 + i, syscall_addr, syscall_name, syscall_modname))
def _scan_kernel_memory(self, addr_space, rules): # Find KDBG so we know where kernel memory begins. Do not assume # the starting range is 0x80000000 because we may be dealing with # an image with the /3GB boot switch. kdbg = tasks.get_kdbg(addr_space) start = kdbg.MmSystemRangeStart.dereference_as("Pointer") # Modules so we can map addresses to owners mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # There are multiple views (GUI sessions) of kernel memory. # Since we're scanning virtual memory and not physical, # all sessions must be scanned for full coverage. This # really only has a positive effect if the data you're # searching for is in GUI memory. sessions = [] for proc in tasks.pslist(addr_space): sid = proc.SessionId # Skip sessions we've already seen if sid == None or sid in sessions: continue session_space = proc.get_process_address_space() if session_space == None: continue sessions.append(sid) scanner = DiscontigYaraScanner(address_space = session_space, rules = rules) for hit, address in scanner.scan(start_offset = start): module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address)) yield (module, address - self._config.REVERSE, hit, session_space.zread(address - self._config.REVERSE, self._config.SIZE))
def ssdt(self): """Volatility ssdt plugin. @see volatility/plugins/malware/ssdt.py """ log.debug("Executing Volatility ssdt plugin on " "{0}".format(self.memdump)) self.__config() results = [] command = self.plugins["ssdt"](self.config) # Comment: this code is pretty much ripped from render_text in volatility. addr_space = utils.load_as(self.config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get("memory_model", "32bit") == "32bit" for idx, table, n, vm, mods, mod_addrs in command.calculate(): for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object("address", table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object("long", table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module( mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = "{0}".format(syscall_mod.BaseDllName) else: syscall_modname = "UNKNOWN" new = { "index": int(idx), "table": hex(int(table)), "entry": "{0:#06x}".format(idx * 0x1000 + i), "syscall_name": syscall_name, "syscall_addr": syscall_addr, "syscall_modname": syscall_modname, } if bits32 and syscall_mod is not None: ret = apihooks.ApiHooks.check_inline( va=syscall_addr, addr_space=vm, mem_start=syscall_mod.DllBase, mem_end=syscall_mod.DllBase + syscall_mod.SizeOfImage) # Could not analyze the memory. if ret is not None: hooked, data, dest_addr = ret if hooked: # We found a hook, try to resolve the hooker. # No mask required because we currently only work # on x86 anyway. hook_mod = tasks.find_module( mods, mod_addrs, dest_addr) if hook_mod: hook_name = "{0}".format(hook_mod.BaseDllName) else: hook_name = "UNKNOWN" # Report it now. new.update({ "hook_dest_addr": "{0:#x}".format(dest_addr), "hook_name": hook_name, }) results.append(new) return dict(config={}, data=results)
def get_json(self, data): results = {} addr_space = utils.load_as(self._config) # Compile the regular expression for filtering by driver name if self._config.regex != None: mod_re = re.compile(self._config.regex, re.I) else: mod_re = None mods = dict((mod.DllBase, mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) bits = addr_space.profile.metadata.get('memory_model', '32bit') for driver in data: header = driver.get_object_header() driver_name = str(header.NameInfo.Name or '') # Continue if a regex was supplied and it doesn't match if mod_re != None: if not (mod_re.search(driver_name) or mod_re.search(driver_name)): continue row = {'DriverName':driver_name, 'DriverStart':int(driver.DriverStart), 'DriverSize':int(driver.DriverSize), 'DriverStartIo':int(driver.DriverStartIo), 'IrpFunctions':[], 'Devices':[], } # Write the address and owner of each IRP function for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, function) irp = {'index':int(i), 'FunctionName':str(MAJOR_FUNCTIONS[i]), 'FunctionAddress':int(function), 'Disassembly':[] } if module: irp['BaseDllName'] = str(module.BaseDllName or '') else: irp['BaseDllName'] = '' if self._config.verbose: data = addr_space.zread(function, 64) irp["Disassembly"] = [{'Address':int(o), "Bytes":str(h), "Instruction":str(i)} for o, i, h in malfind.Disassemble(data = data, start = function, bits = bits, stoponret = True) ] row['IrpFunctions'].append(irp) for device in driver.devices(): device_header = obj.Object("_OBJECT_HEADER", offset = device.obj_offset - device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), vm = device.obj_vm, native_vm = device.obj_native_vm ) device_name = str(device_header.NameInfo.Name or '') dev = {'Offset': int(device.obj_offset), 'DeviceName': device_name, 'DeviceCodes': DEVICE_CODES.get(device.DeviceType.v(), "UNKNOWN"), 'AttachedDevices': []} level = 0 for att_device in device.attached_devices(): device_header = obj.Object("_OBJECT_HEADER", offset = att_device.obj_offset - att_device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), vm = att_device.obj_vm, native_vm = att_device.obj_native_vm ) device_name = str(device_header.NameInfo.Name or '') name = (device_name + " - " + str(att_device.DriverObject.DriverName or '')) attached_device = {'Offset': att_device.obj_offset, 'DeviceName': name, 'DeviceCodes': DEVICE_CODES.get(att_device.DeviceType.v(), "UNKNOWN"), 'Level': level} level += 1 dev['AttachedDevices'].append(attached_device) row['Devices'].append(dev) _addr = str(row['DriverStart']) results [_addr ] = row return results
def calculate(self): addr_space = utils.load_as(self._config) if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") # Get the OS version we're analyzing version = (addr_space.profile.metadata.get('major', 0), addr_space.profile.metadata.get('minor', 0)) modlist = list(modules.lsmod(addr_space)) mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) # KTIMERs collected timers = [] # Valid KTIMER.Header.Type values TimerNotificationObject = 8 TimerSynchronizationObject = 9 valid_types = (TimerNotificationObject, TimerSynchronizationObject) if version == (5, 1) or (version == (5, 2) and addr_space.profile.metadata.get('build', 0) == 3789): # On XP SP0-SP3 x86 and Windows 2003 SP0, KiTimerTableListHead # is an array of 256 _LIST_ENTRY for _KTIMERs. KiTimerTableListHead = self.find_list_head(modlist[0], "KeUpdateSystemTime", "\x25\xFF\x00\x00\x00\x8D\x0C\xC5") lists = obj.Object("Array", offset = KiTimerTableListHead, vm = addr_space, targetType = '_LIST_ENTRY', count = 256) for l in lists: for t in l.list_of_type("_KTIMER", "TimerListEntry"): timers.append(t) elif version == (5, 2) or version == (6, 0): # On XP x64, Windows 2003 SP1-SP2, and Vista SP0-SP2, KiTimerTableListHead # is an array of 512 _KTIMER_TABLE_ENTRY structs. KiTimerTableListHead = self.find_list_head(modlist[0], "KeCancelTimer", "\xC1\xE7\x04\x81\xC7") lists = obj.Object("Array", offset = KiTimerTableListHead, vm = addr_space, targetType = '_KTIMER_TABLE_ENTRY', count = 512) for l in lists: for t in l.Entry.list_of_type("_KTIMER", "TimerListEntry"): timers.append(t) elif version == (6, 1): # On Windows 7, there is no more KiTimerTableListHead. The list is # at _KPCR.PrcbData.TimerTable.TimerEntries (credits to Matt Suiche # for this one. See http://pastebin.com/FiRsGW3f). for kpcr in tasks.get_kdbg(addr_space).kpcrs(): for table in kpcr.ProcessorBlock.TimerTable.TimerEntries: for t in table.Entry.list_of_type("_KTIMER", "TimerListEntry"): timers.append(t) for timer in timers: # Sanity check on the timer type if timer.Header.Type not in valid_types: continue # Ignore timers without DPCs if not timer.Dpc.is_valid() or not timer.Dpc.DeferredRoutine.is_valid(): continue # Lookup the module containing the DPC module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(timer.Dpc.DeferredRoutine)) yield timer, module
def render_text(self, outfd, data): # Determine which filters the user wants to see if self._config.FILTER: filters = set(self._config.FILTER.split(',')) else: filters = set() for thread, addr_space, mods, mod_addrs, instances, hooked_tables in data: # If the user didn't set filters, display all results. If # the user set one or more filters, only show threads # with matching results. tags = set([t for t, v in instances.items() if v.check()]) if filters and not filters & tags: continue s = "------\n" s += "ETHREAD: {0:#010x} Pid: {1} Tid: {2}\n".format( thread.obj_offset, thread.Cid.UniqueProcess, thread.Cid.UniqueThread) s += "Tags: {0}\n".format(','.join(tags)) s += "Created: {0}\n".format(thread.CreateTime) s += "Exited: {0}\n".format(thread.ExitTime) s += "Owning Process: {0}\n".format( thread.owning_process().ImageFileName) s += "Attached Process: {0}\n".format( thread.attached_process().ImageFileName) # Lookup the thread's state state = str(thread.Tcb.State) # Append the wait reason if state == 'Waiting': state = state + ':' + str(thread.Tcb.WaitReason) s += "State: {0}\n".format(state) s += "BasePriority: {0:#x}\n".format(thread.Tcb.BasePriority) s += "Priority: {0:#x}\n".format(thread.Tcb.Priority) s += "TEB: {0:#010x}\n".format(thread.Tcb.Teb) # If its a system thread, get the owning module if "SystemThread" in tags: owner = tasks.find_module(mods, mod_addrs, thread.StartAddress) else: owner = None if owner: owner_name = str(owner.BaseDllName or '') else: owner_name = "UNKNOWN" s += "StartAddress: {0:#010x} {1}\n".format( thread.StartAddress, owner_name) # Check the flag which indicates whether Win32StartAddress is valid if thread.SameThreadApcFlags & 1: s += "Win32StartAddress: {0:#010x}\n".format( thread.Win32StartAddress) if self.bits32: s += "ServiceTable: {0:#010x}\n".format(thread.Tcb.ServiceTable) ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", offset = thread.Tcb.ServiceTable, vm = addr_space ) if ssdt_obj != None: for i, desc in enumerate(ssdt_obj.Descriptors): if desc.is_valid(): s += " [{0}] {1:#010x}\n".format(i, desc.KiServiceTable.v()) else: s += " [{0}] -\n".format(i) # Show exactly which functions are hooked table = desc.KiServiceTable.v() if table not in hooked_tables.keys(): continue for (i, func_name, func_addr, mod_name) in hooked_tables[table]: s += " [{0:#x}] {1} {2:#x} {3}\n".format( i, func_name, func_addr, mod_name) s += "Win32Thread: {0:#010x}\n".format(thread.Tcb.Win32Thread) s += "CrossThreadFlags: {0}\n".format(thread.CrossThreadFlags) # Print the registers if possible trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME") if trapframe and self.bits32: s += "Eip: {0:#10x}\n".format(trapframe.Eip) s += " eax={0:#010x} ebx={1:#010x} ecx={2:#010x}".format( trapframe.Eax, trapframe.Ebx, trapframe.Ecx) s += " edx={0:#010x} esi={1:#010x} edi={2:#010x}\n".format( trapframe.Edx, trapframe.Esi, trapframe.Edi) s += " eip={0:#010x} esp={1:#010x} ebp={2:#010x} err={3:#010x}\n".format( trapframe.Eip, trapframe.HardwareEsp, trapframe.Ebp, trapframe.ErrCode) s += " cs={0:#04x} ss={1:#04x} ds={2:#04x}".format( trapframe.SegCs, trapframe.HardwareSegSs, trapframe.SegDs) s += " es={0:#04x} gs={1:#04x} efl={2:#010x}\n".format( trapframe.SegEs, trapframe.SegGs, trapframe.EFlags) s += " dr0={0:#010x} dr1={1:#010x} dr2={2:#010x}".format( trapframe.Dr0, trapframe.Dr1, trapframe.Dr2) s += " dr3={0:#010x} dr6={1:#010x} dr7={2:#010x}\n".format( trapframe.Dr3, trapframe.Dr6, trapframe.Dr7) # Disasemble the start address if possible if addr_space.is_valid_address(thread.StartAddress): buf = addr_space.zread(thread.StartAddress, 24) s += "\n".join(["{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(buf, thread.StartAddress.v())]) outfd.write("{0}\n".format(s))
def render_text(self, outfd, data): # Determine which filters the user wants to see if self._config.FILTER: filters = set(self._config.FILTER.split(',')) else: filters = set() for thread, addr_space, mods, mod_addrs, instances, hooked_tables in data: # If the user didn't set filters, display all results. If # the user set one or more filters, only show threads # with matching results. tags = set([t for t, v in list(instances.items()) if v.check()]) if filters and not filters & tags: continue s = "------\n" s += "ETHREAD: {0:#010x} Pid: {1} Tid: {2}\n".format( thread.obj_offset, thread.Cid.UniqueProcess, thread.Cid.UniqueThread) s += "Tags: {0}\n".format(','.join(tags)) s += "Created: {0}\n".format(thread.CreateTime) s += "Exited: {0}\n".format(thread.ExitTime) s += "Owning Process: {0}\n".format( thread.owning_process().ImageFileName) s += "Attached Process: {0}\n".format( thread.attached_process().ImageFileName) # Lookup the thread's state state = str(thread.Tcb.State) # Append the wait reason if state == 'Waiting': state = state + ':' + str(thread.Tcb.WaitReason) s += "State: {0}\n".format(state) s += "BasePriority: {0:#x}\n".format(thread.Tcb.BasePriority) s += "Priority: {0:#x}\n".format(thread.Tcb.Priority) s += "TEB: {0:#010x}\n".format(thread.Tcb.Teb) # If its a system thread, get the owning module if "SystemThread" in tags: owner = tasks.find_module(mods, mod_addrs, thread.StartAddress) else: owner = None if owner: owner_name = str(owner.BaseDllName or '') else: owner_name = "UNKNOWN" s += "StartAddress: {0:#010x} {1}\n".format( thread.StartAddress, owner_name) # Check the flag which indicates whether Win32StartAddress is valid if thread.SameThreadApcFlags & 1: s += "Win32StartAddress: {0:#010x}\n".format( thread.Win32StartAddress) if self.bits32: s += "ServiceTable: {0:#010x}\n".format( thread.Tcb.ServiceTable) ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", offset=thread.Tcb.ServiceTable, vm=addr_space) if ssdt_obj != None: for i, desc in enumerate(ssdt_obj.Descriptors): if desc.is_valid(): s += " [{0}] {1:#010x}\n".format( i, desc.KiServiceTable.v()) else: s += " [{0}] -\n".format(i) # Show exactly which functions are hooked table = desc.KiServiceTable.v() if table not in list(hooked_tables.keys()): continue for (i, func_name, func_addr, mod_name) in hooked_tables[table]: s += " [{0:#x}] {1} {2:#x} {3}\n".format( i, func_name, func_addr, mod_name) s += "Win32Thread: {0:#010x}\n".format(thread.Tcb.Win32Thread) s += "CrossThreadFlags: {0}\n".format(thread.CrossThreadFlags) # Print the registers if possible trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME") if trapframe and self.bits32: s += "Eip: {0:#10x}\n".format(trapframe.Eip) s += " eax={0:#010x} ebx={1:#010x} ecx={2:#010x}".format( trapframe.Eax, trapframe.Ebx, trapframe.Ecx) s += " edx={0:#010x} esi={1:#010x} edi={2:#010x}\n".format( trapframe.Edx, trapframe.Esi, trapframe.Edi) s += " eip={0:#010x} esp={1:#010x} ebp={2:#010x} err={3:#010x}\n".format( trapframe.Eip, trapframe.HardwareEsp, trapframe.Ebp, trapframe.ErrCode) s += " cs={0:#04x} ss={1:#04x} ds={2:#04x}".format( trapframe.SegCs, trapframe.HardwareSegSs, trapframe.SegDs) s += " es={0:#04x} gs={1:#04x} efl={2:#010x}\n".format( trapframe.SegEs, trapframe.SegGs, trapframe.EFlags) s += " dr0={0:#010x} dr1={1:#010x} dr2={2:#010x}".format( trapframe.Dr0, trapframe.Dr1, trapframe.Dr2) s += " dr3={0:#010x} dr6={1:#010x} dr7={2:#010x}\n".format( trapframe.Dr3, trapframe.Dr6, trapframe.Dr7) # Disasemble the start address if possible if addr_space.is_valid_address(thread.StartAddress): buf = addr_space.zread(thread.StartAddress, 24) s += "\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(buf, thread.StartAddress.v()) ]) outfd.write("{0}\n".format(s))
def calculate(self): if self._config.BASELINEIMG == None: print "Baseline image required!" sys.exit() if self._config.ONLYKNOWN and self._config.ONLYUNKNOWN: print "Select only one of the options (-K, -U)!" sys.exit(-1) ####################################### #Searching for drivers in baseline image ###################################### # Saving original image orig_img = self._config.LOCATION # Setting up baseline image self._config.LOCATION = "file://" + self._config.BASELINEIMG # Instantiating DriverScan plugin addr_space = utils.load_as(self._config) drv_scan = DriverScan(self._config) if volatility.constants.VERSION == "2.6" or volatility.constants.VERSION == "2.4": for driver in drv_scan.calculate(): header = driver.get_object_header() if driver.DriverExtension.ServiceKeyName != None: service_key_name = str( driver.DriverExtension.ServiceKeyName).lower() else: service_key_name = None if header.NameInfo.Name != None: name = str(header.NameInfo.Name).lower() else: name = None if driver.DriverName != None: driver_name = str(driver.DriverName).lower() else: driver_name = None if driver.DriverSize != None: driver_size = driver.DriverSize else: driver_size = None if driver.DriverStart != None: driver_start = driver.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.baseline_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs }) else: for obj, drv, ext in drv_scan.calculate(): if ext.ServiceKeyName != None: service_key_name = str(ext.ServiceKeyName).lower() else: service_key_name = None if obj.NameInfo.Name != None: name = str(obj.NameInfo.Name).lower() else: name = None if drv.DriverName != None: driver_name = str(drv.DriverName).lower() else: driver_name = None if drv.DriverSize != None: driver_size = drv.DriverSize else: driver_size = None if drv.DriverStart != None: driver_start = drv.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(drv.MajorFunction): function = drv.MajorFunction[i] module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.baseline_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs }) # Instantiating Modules plugin for m in lsmod(addr_space): self.baseline_mod_list.append({ 'full_dll_name': str(m.FullDllName).lower(), 'base_dll_name': str(m.BaseDllName).lower(), 'dll_base': m.DllBase }) for drv in self.baseline_drv_list: if drv['driver_start'] == m.DllBase: if m.FullDllName != None: drv['full_dll_name'] = str(m.FullDllName).lower() else: drv['full_dll_name'] = None if m.BaseDllName != None: drv['base_dll_name'] = str(m.BaseDllName).lower() else: drv['base_dll_name'] = None # Fixing entries that are not in the list of loaded modules list for drv in self.baseline_drv_list: f = False for m in self.baseline_mod_list: if m['dll_base'] == drv['driver_start']: f = True if not f: drv['full_dll_name'] = None drv['base_dll_name'] = None #################################### #Searching for drivers in the image to be analyzed ################################## # Restoring original image self._config.LOCATION = orig_img # Instantiating DriverScan plugin addr_space = utils.load_as(self._config) drv_scan = DriverScan(self._config) if volatility.constants.VERSION == "2.6" or volatility.constants.VERSION == "2.4": for driver in drv_scan.calculate(): header = driver.get_object_header() if driver.DriverExtension.ServiceKeyName != None: service_key_name = str( driver.DriverExtension.ServiceKeyName).lower() else: service_key_name = None if header.NameInfo.Name != None: name = str(header.NameInfo.Name).lower() else: name = None if driver.DriverName != None: driver_name = str(driver.DriverName).lower() else: driver_name = None if driver.DriverSize != None: driver_size = driver.DriverSize else: driver_size = None if driver.DriverStart != None: driver_start = driver.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.image_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs, 'obj': header, 'drv': driver, 'ext': driver.DriverExtension }) else: for obj, drv, ext in drv_scan.calculate(): if ext.ServiceKeyName != None: service_key_name = str(ext.ServiceKeyName).lower() else: service_key_name = None if obj.NameInfo.Name != None: name = str(obj.NameInfo.Name).lower() else: name = None if drv.DriverName != None: driver_name = str(drv.DriverName).lower() else: driver_name = None if drv.DriverSize != None: driver_size = drv.DriverSize else: driver_size = None if drv.DriverStart != None: driver_start = drv.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(drv.MajorFunction): function = drv.MajorFunction[i] module = tasks.find_module( mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.image_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs, 'obj': obj, 'drv': drv, 'ext': ext }) for m in lsmod(addr_space): self.image_mod_list.append({ 'full_dll_name': str(m.FullDllName).lower(), 'base_dll_name': str(m.BaseDllName).lower(), 'dll_base': m.DllBase }) for drv in self.image_drv_list: if drv['driver_start'] == m.DllBase: if m.FullDllName != None: drv['full_dll_name'] = str(m.FullDllName).lower() else: drv['full_dll_name'] = None if m.BaseDllName != None: drv['base_dll_name'] = str(m.BaseDllName).lower() else: drv['base_dll_name'] = None # Fixing up entries that are not in the list of loaded modules list for drv in self.image_drv_list: f = False for m in self.image_mod_list: if m['dll_base'] == drv['driver_start']: f = True if not f: drv['full_dll_name'] = None drv['base_dll_name'] = None # Compare the lists for drv in self.image_drv_list: known = False d_name = False drv_name = False drv_size = False drv_mod = False drv_irp = False drv_bl = None for bl_drv in self.baseline_drv_list: if drv['service_key_name'] == bl_drv['service_key_name']: known = True if drv['name'] == bl_drv['name']: d_name = True elif self._config.VERBOSE: print "Name:" print "Baseline: " + bl_drv['name'] print "Image: " + drv['name'] if drv['driver_name'] == bl_drv['driver_name']: drv_name = True elif self._config.VERBOSE: print "Driver Name:" print "Baseline: " + str(bl_drv['driver_name']) print "Image: " + str(drv['driver_name']) if drv['driver_size'] == bl_drv['driver_size']: drv_size = True elif self._config.VERBOSE: print "Driver Size:" print "Baseline: " + str(bl_drv['driver_size']) print "Image: " + str(drv['driver_size']) if drv['full_dll_name'] == bl_drv['full_dll_name']: drv_mod = True elif self._config.VERBOSE: print "Module:" print "Baseline: " + str(bl_drv['full_dll_name']) print "Image: " + str(drv['full_dll_name']) drv_irp = True for m in drv['irps']: if drv['irps'][m] != bl_drv['irps'][m]: drv_irp = False if known: drv_bl = bl_drv break if self._config.ONLYKNOWN: if known: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], drv_bl['irps']) if self._config.ONLYUNKNOWN: if not known: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], None) if not self._config.ONLYKNOWN and not self._config.ONLYUNKNOWN: if drv_bl: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], drv_bl['irps']) else: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], None)
def get_json(self, data): results = {} addr_space = utils.load_as(self._config) # Compile the regular expression for filtering by driver name if self._config.regex != None: mod_re = re.compile(self._config.regex, re.I) else: mod_re = None mods = dict((mod.DllBase, mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) bits = addr_space.profile.metadata.get('memory_model', '32bit') for driver in data: header = driver.get_object_header() driver_name = str(header.NameInfo.Name or '') # Continue if a regex was supplied and it doesn't match if mod_re != None: if not (mod_re.search(driver_name) or mod_re.search(driver_name)): continue row = { 'DriverName': driver_name, 'DriverStart': int(driver.DriverStart), 'DriverSize': int(driver.DriverSize), 'DriverStartIo': int(driver.DriverStartIo), 'IrpFunctions': [], 'Devices': [], } # Write the address and owner of each IRP function for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, function) irp = { 'index': int(i), 'FunctionName': str(MAJOR_FUNCTIONS[i]), 'FunctionAddress': int(function), 'Disassembly': [] } if module: irp['BaseDllName'] = str(module.BaseDllName or '') else: irp['BaseDllName'] = '' if self._config.verbose: data = addr_space.zread(function, 64) irp["Disassembly"] = [{ 'Address': int(o), "Bytes": str(h), "Instruction": str(i) } for o, i, h in malfind.Disassemble( data=data, start=function, bits=bits, stoponret=True)] row['IrpFunctions'].append(irp) for device in driver.devices(): device_header = obj.Object( "_OBJECT_HEADER", offset=device.obj_offset - device.obj_vm.profile.get_obj_offset( "_OBJECT_HEADER", "Body"), vm=device.obj_vm, native_vm=device.obj_native_vm) device_name = str(device_header.NameInfo.Name or '') dev = { 'Offset': int(device.obj_offset), 'DeviceName': device_name, 'DeviceCodes': DEVICE_CODES.get(device.DeviceType.v(), "UNKNOWN"), 'AttachedDevices': [] } level = 0 for att_device in device.attached_devices(): device_header = obj.Object( "_OBJECT_HEADER", offset=att_device.obj_offset - att_device.obj_vm.profile.get_obj_offset( "_OBJECT_HEADER", "Body"), vm=att_device.obj_vm, native_vm=att_device.obj_native_vm) device_name = str(device_header.NameInfo.Name or '') name = (device_name + " - " + str(att_device.DriverObject.DriverName or '')) attached_device = { 'Offset': att_device.obj_offset, 'DeviceName': name, 'DeviceCodes': DEVICE_CODES.get(att_device.DeviceType.v(), "UNKNOWN"), 'Level': level } level += 1 dev['AttachedDevices'].append(attached_device) row['Devices'].append(dev) _addr = str(row['DriverStart']) results[_addr] = row return results
def calculate(self): if self._config.BASELINEIMG == None: print "Baseline image required!" sys.exit() if self._config.ONLYKNOWN and self._config.ONLYUNKNOWN: print "Select only one of the options (-K, -U)!" sys.exit(-1) ####################################### #Searching for drivers in baseline image ###################################### # Saving original image orig_img = self._config.LOCATION # Setting up baseline image self._config.LOCATION = "file://" + self._config.BASELINEIMG # Instantiating DriverScan plugin addr_space = utils.load_as(self._config) drv_scan = DriverScan(self._config) if volatility.constants.VERSION != "2.4": for obj, drv, ext in drv_scan.calculate(): if ext.ServiceKeyName != None: service_key_name = str(ext.ServiceKeyName).lower() else: service_key_name = None if obj.NameInfo.Name != None: name = str(obj.NameInfo.Name).lower() else: name = None if drv.DriverName != None: driver_name = str(drv.DriverName).lower() else: driver_name = None if drv.DriverSize != None: driver_size = drv.DriverSize else: driver_size = None if drv.DriverStart != None: driver_start = drv.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(drv.MajorFunction): function = drv.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.baseline_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs }) else: for driver in drv_scan.calculate(): header = driver.get_object_header() if driver.DriverExtension.ServiceKeyName != None: service_key_name = str(driver.DriverExtension.ServiceKeyName).lower() else: service_key_name = None if header.NameInfo.Name != None: name = str(header.NameInfo.Name).lower() else: name = None if driver.DriverName != None: driver_name = str(driver.DriverName).lower() else: driver_name = None if driver.DriverSize != None: driver_size = driver.DriverSize else: driver_size = None if driver.DriverStart != None: driver_start = driver.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.baseline_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs }) # Instantiating Modules plugin for m in lsmod(addr_space): self.baseline_mod_list.append({ 'full_dll_name': str(m.FullDllName).lower(), 'base_dll_name': str(m.BaseDllName).lower(), 'dll_base': m.DllBase }) for drv in self.baseline_drv_list: if drv['driver_start'] == m.DllBase: if m.FullDllName != None: drv['full_dll_name'] = str(m.FullDllName).lower() else: drv['full_dll_name'] = None if m.BaseDllName != None: drv['base_dll_name'] = str(m.BaseDllName).lower() else: drv['base_dll_name'] = None # Fixing entries that are not in the list of loaded modules list for drv in self.baseline_drv_list: f = False for m in self.baseline_mod_list: if m['dll_base'] == drv['driver_start']: f = True if not f: drv['full_dll_name'] = None drv['base_dll_name'] = None #################################### #Searching for drivers in the image to be analyzed ################################## # Restoring original image self._config.LOCATION = orig_img # Instantiating DriverScan plugin addr_space = utils.load_as(self._config) drv_scan = DriverScan(self._config) if volatility.constants.VERSION != "2.4": for obj, drv, ext in drv_scan.calculate(): if ext.ServiceKeyName != None: service_key_name = str(ext.ServiceKeyName).lower() else: service_key_name = None if obj.NameInfo.Name != None: name = str(obj.NameInfo.Name).lower() else: name = None if drv.DriverName != None: driver_name = str(drv.DriverName).lower() else: driver_name = None if drv.DriverSize != None: driver_size = drv.DriverSize else: driver_size = None if drv.DriverStart != None: driver_start = drv.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(drv.MajorFunction): function = drv.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.image_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs, 'obj': obj, 'drv': drv, 'ext': ext }) else: for driver in drv_scan.calculate(): header = driver.get_object_header() if driver.DriverExtension.ServiceKeyName != None: service_key_name = str(driver.DriverExtension.ServiceKeyName).lower() else: service_key_name = None if header.NameInfo.Name != None: name = str(header.NameInfo.Name).lower() else: name = None if driver.DriverName != None: driver_name = str(driver.DriverName).lower() else: driver_name = None if driver.DriverSize != None: driver_size = driver.DriverSize else: driver_size = None if driver.DriverStart != None: driver_start = driver.DriverStart else: driver_start = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in lsmod(addr_space)) mod_addrs = sorted(mods.keys()) IRPs = {} for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '').lower() else: module_name = "unknown" IRPs[MAJOR_FUNCTIONS[i]] = module_name self.image_drv_list.append({ 'service_key_name': service_key_name, 'name': name, 'driver_name': driver_name, 'driver_size': driver_size, 'driver_start': driver_start, 'irps': IRPs, 'obj': header, 'drv': driver, 'ext': driver.DriverExtension }) for m in lsmod(addr_space): self.image_mod_list.append({ 'full_dll_name': str(m.FullDllName).lower(), 'base_dll_name': str(m.BaseDllName).lower(), 'dll_base': m.DllBase }) for drv in self.image_drv_list: if drv['driver_start'] == m.DllBase: if m.FullDllName != None: drv['full_dll_name'] = str(m.FullDllName).lower() else: drv['full_dll_name'] = None if m.BaseDllName != None: drv['base_dll_name'] = str(m.BaseDllName).lower() else: drv['base_dll_name'] = None # Fixing up entries that are not in the list of loaded modules list for drv in self.image_drv_list: f = False for m in self.image_mod_list: if m['dll_base'] == drv['driver_start']: f = True if not f: drv['full_dll_name'] = None drv['base_dll_name'] = None # Compare the lists for drv in self.image_drv_list: known = False d_name = False drv_name = False drv_size = False drv_mod = False drv_irp = False drv_bl = None for bl_drv in self.baseline_drv_list: if drv['service_key_name'] == bl_drv['service_key_name']: known = True if drv['name'] == bl_drv['name']: d_name = True elif self._config.VERBOSE: print "Name:" print "Baseline: " + bl_drv['name'] print "Image: " + drv['name'] if drv['driver_name'] == bl_drv['driver_name']: drv_name = True elif self._config.VERBOSE: print "Driver Name:" print "Baseline: " + str(bl_drv['driver_name']) print "Image: " + str(drv['driver_name']) if drv['driver_size'] == bl_drv['driver_size']: drv_size = True elif self._config.VERBOSE: print "Driver Size:" print "Baseline: " + str(bl_drv['driver_size']) print "Image: " + str(drv['driver_size']) if drv['full_dll_name'] == bl_drv['full_dll_name']: drv_mod = True elif self._config.VERBOSE: print "Module:" print "Baseline: " + str(bl_drv['full_dll_name']) print "Image: " + str(drv['full_dll_name']) drv_irp = True for m in drv['irps']: if drv['irps'][m] != bl_drv['irps'][m]: drv_irp = False if known: drv_bl = bl_drv break if self._config.ONLYKNOWN: if known: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], drv_bl['irps']) if self._config.ONLYUNKNOWN: if not known: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], None) if not self._config.ONLYKNOWN and not self._config.ONLYUNKNOWN: if drv_bl: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], drv_bl['irps']) else: yield (drv['obj'], drv['drv'], drv['ext'], known, d_name, drv_name, drv_mod, drv_size, drv['full_dll_name'], drv_irp, drv['irps'], None)
def get_json(self, data): results = {} # Determine which filters the user wants to see if self._config.FILTER: filters = set(self._config.FILTER.split(',')) else: filters = set() for thread, addr_space, mods, mod_addrs, \ instances, hooked_tables, system_range, owner_name in data: # If the user didn't set filters, display all results. If # the user set one or more filters, only show threads # with matching results. tags = set([t for t, v in instances.items() if v.check()]) if filters and not filters & tags: continue row = {'offset': int(thread.obj_offset), 'UniqueProcess': int(thread.Cid.UniqueProcess), 'UniqueThread': int(thread.Cid.UniqueThread), 'Tags': [str(i) for i in tags], 'CreateTime': str(thread.CreateTime), 'ExitTime': str(thread.ExitTime), 'ImageFileName': str(thread.owning_process().ImageFileName), 'Attached': str(thread.attached_process().ImageFileName), 'BasePriority': int(thread.Tcb.BasePriority), 'Priority': int(thread.Tcb.Priority), 'Teb': int(thread.Tcb.Teb), 'State': str(thread.Tcb.State), 'WaitReason': str(thread.Tcb.WaitReason), 'StartAddress': int(thread.StartAddress), "SystemThread": bool("SystemThread" in tags), "OwnerName": "", "Win32StartAddressValid": thread.SameThreadApcFlags & 1, "Win32StartAddress": int(thread.Win32StartAddress), 'ServiceTable': int(thread.Tcb.ServiceTable) if self.bits32 else "", "Win32Thread": int(thread.Tcb.Win32Thread), "CrossThreadFlags": int(thread.CrossThreadFlags), "TrapFrame": {}, 'SSDT': {}, "Disassembly": [] } # Print the registers if possible trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME") if trapframe and self.bits32: row["TrapFrame"] = {key: int(eval('trapframe.%s' % key, {'trapframe': trapframe})) for key in trapframe.members.keys()} # Disasemble the start address if possible if addr_space.is_valid_address(thread.StartAddress): buf = addr_space.zread(thread.StartAddress, 24) row["Disassembly"] = [{'Address': int(o), "Bytes": str(h), "Instruction": str(i)} for o, i, h in malfind.Disassemble(buf, thread.StartAddress.v()) ] # If its a system thread, get the owning module if row["SystemThread"]: owner = tasks.find_module(mods, mod_addrs, thread.StartAddress) if not owner is None: row["OwnerName"] = str(owner.BaseDllName or owner_name) if self.bits32: ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", offset=thread.Tcb.ServiceTable, vm=addr_space ) if ssdt_obj is not None: for i, desc in enumerate(ssdt_obj.Descriptors): row['SSDT'][str(i)] = {'index': i, 'KiServiceTable': '', 'HookedSSDT': []} if desc.is_valid(): row['SSDT'][str(i)]['KiServiceTable'] = desc.KiServiceTable.v() table = desc.KiServiceTable.v() if table not in hooked_tables.keys(): continue # no use for this data so far # # for (j, func_name, func_addr, mod_name) in hooked_tables[table]: # row['SSDT'][str(i)]['HookedSSDT'].append({'index': j, # 'FunctionName': func_name, # 'FunctionAddress': func_addr, # 'ModuleName': str(mod_name)}) results[str(row['offset'])] = row return results
def generator(self, data): addr_space = utils.load_as(self._config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: table_name = "SSDT[{0}]".format(idx) table_offset = Address(table) num_entries = int(n) for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" if not self._config.VERBOSE: yield (0, [table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname)]) ## check for inline hooks if in --verbose mode, we're analyzing ## an x86 model system and the sycall_mod is available if (self._config.VERBOSE and addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' and syscall_mod is not None): ## leverage this static method from apihooks ret = apihooks.ApiHooks.check_inline(va = syscall_addr, addr_space = vm, mem_start = syscall_mod.DllBase, mem_end = syscall_mod.DllBase + syscall_mod.SizeOfImage) ## could not analyze the memory if ret == None: yield (0, [table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(0), "NotInline"]) continue (hooked, data, dest_addr) = ret ## the function isn't hooked if not hooked: yield (0, [table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(0), "NotInline"]) continue ## we found a hook, try to resolve the hooker. no mask required because ## we currently only work on x86 anyway hook_mod = tasks.find_module(mods, mod_addrs, dest_addr) if hook_mod: hook_name = hook_mod.BaseDllName else: hook_name = "UNKNOWN" ## report it now yield (0, [table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(dest_addr), str(hook_name)])
def ssdt(self): """Volatility ssdt plugin. @see volatility/plugins/ssdt.py """ results = [] command = self.plugins["ssdt"](self.config) # Comment: this code is pretty much ripped from render_text in volatility. addr_space = self.addr_space syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get("memory_model", "32bit") == "32bit" for idx, table, n, vm, mods, mod_addrs in command.calculate(): for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object("address", table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object("long", table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = "{0}".format(syscall_mod.BaseDllName) else: syscall_modname = "UNKNOWN" new = { "index": int(idx), "table": "0x%x" % int(table), "entry": "{0:#06x}".format(idx * 0x1000 + i), "syscall_name": syscall_name, "syscall_addr": "0x%x" % int(syscall_addr), "syscall_modname": syscall_modname, } if bits32 and syscall_mod is not None: ret = apihooks.ApiHooks.check_inline( va=syscall_addr, addr_space=vm, mem_start=syscall_mod.DllBase, mem_end=syscall_mod.DllBase + syscall_mod.SizeOfImage) # Could not analyze the memory. if ret is not None: hooked, data, dest_addr = ret if hooked: # We found a hook, try to resolve the hooker. # No mask required because we currently only work # on x86 anyway. hook_mod = tasks.find_module(mods, mod_addrs, dest_addr) if hook_mod: hook_name = "{0}".format(hook_mod.BaseDllName) else: hook_name = "UNKNOWN" # Report it now. new.update({ "hook_dest_addr": "{0:#x}".format(dest_addr), "hook_name": hook_name, }) results.append(new) return dict(config={}, data=results)
def get_json(self, data): results = {} # Determine which filters the user wants to see if self._config.FILTER: filters = set(self._config.FILTER.split(',')) else: filters = set() for thread, addr_space, mods, mod_addrs, \ instances, hooked_tables, system_range, owner_name in data: # If the user didn't set filters, display all results. If # the user set one or more filters, only show threads # with matching results. tags = set([t for t, v in instances.items() if v.check()]) if filters and not filters & tags: continue row = { 'offset': int(thread.obj_offset), 'UniqueProcess': int(thread.Cid.UniqueProcess), 'UniqueThread': int(thread.Cid.UniqueThread), 'Tags': [str(i) for i in tags], 'CreateTime': str(thread.CreateTime), 'ExitTime': str(thread.ExitTime), 'ImageFileName': str(thread.owning_process().ImageFileName), 'Attached': str(thread.attached_process().ImageFileName), 'BasePriority': int(thread.Tcb.BasePriority), 'Priority': int(thread.Tcb.Priority), 'Teb': int(thread.Tcb.Teb), 'State': str(thread.Tcb.State), 'WaitReason': str(thread.Tcb.WaitReason), 'StartAddress': int(thread.StartAddress), "SystemThread": bool("SystemThread" in tags), "OwnerName": "", "Win32StartAddressValid": thread.SameThreadApcFlags & 1, "Win32StartAddress": int(thread.Win32StartAddress), 'ServiceTable': int(thread.Tcb.ServiceTable) if self.bits32 else "", "Win32Thread": int(thread.Tcb.Win32Thread), "CrossThreadFlags": int(thread.CrossThreadFlags), "TrapFrame": {}, 'SSDT': {}, "Disassembly": [] } # Print the registers if possible trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME") if trapframe and self.bits32: row["TrapFrame"] = { key: int(eval('trapframe.%s' % key, {'trapframe': trapframe})) for key in trapframe.members.keys() } # Disasemble the start address if possible if addr_space.is_valid_address(thread.StartAddress): buf = addr_space.zread(thread.StartAddress, 24) row["Disassembly"] = [{ 'Address': int(o), "Bytes": str(h), "Instruction": str(i) } for o, i, h in malfind.Disassemble(buf, thread.StartAddress.v())] # If its a system thread, get the owning module if row["SystemThread"]: owner = tasks.find_module(mods, mod_addrs, thread.StartAddress) if not owner is None: row["OwnerName"] = str(owner.BaseDllName or owner_name) if self.bits32: ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", offset=thread.Tcb.ServiceTable, vm=addr_space) if ssdt_obj is not None: for i, desc in enumerate(ssdt_obj.Descriptors): row['SSDT'][str(i)] = { 'index': i, 'KiServiceTable': '', 'HookedSSDT': [] } if desc.is_valid(): row['SSDT'][str(i)][ 'KiServiceTable'] = desc.KiServiceTable.v() table = desc.KiServiceTable.v() if table not in hooked_tables.keys(): continue # no use for this data so far # # for (j, func_name, func_addr, mod_name) in hooked_tables[table]: # row['SSDT'][str(i)]['HookedSSDT'].append({'index': j, # 'FunctionName': func_name, # 'FunctionAddress': func_addr, # 'ModuleName': str(mod_name)}) results[str(row['offset'])] = row return results
def generator(self, data): addr_space = utils.load_as(self._config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: table_name = "SSDT[{0}]".format(idx) table_offset = Address(table) num_entries = int(n) for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module( mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" if not self._config.VERBOSE: yield (0, [ table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname) ]) ## check for inline hooks if in --verbose mode, we're analyzing ## an x86 model system and the sycall_mod is available if (self._config.VERBOSE and addr_space.profile.metadata.get( 'memory_model', '32bit') == '32bit' and syscall_mod is not None): ## leverage this static method from apihooks ret = apihooks.ApiHooks.check_inline( va=syscall_addr, addr_space=vm, mem_start=syscall_mod.DllBase, mem_end=syscall_mod.DllBase + syscall_mod.SizeOfImage) ## could not analyze the memory if ret == None: yield (0, [ table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(0), "NotInline" ]) continue (hooked, data, dest_addr) = ret ## the function isn't hooked if not hooked: yield (0, [ table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(0), "NotInline" ]) continue ## we found a hook, try to resolve the hooker. no mask required because ## we currently only work on x86 anyway hook_mod = tasks.find_module(mods, mod_addrs, dest_addr) if hook_mod: hook_name = hook_mod.BaseDllName else: hook_name = "UNKNOWN" ## report it now yield (0, [ table_name, table_offset, num_entries, Address(idx * 0x1000 + i), Address(syscall_addr), str(syscall_name), str(syscall_modname), Address(dest_addr), str(hook_name) ])
def calculate(self): if not has_distorm3: debug.warning("For best results please install distorm3") # Checks that subclass AbstractThreadCheck checks = registry.get_plugin_classes(AbstractThreadCheck) # If --listtags is chosen, just print the tags and return if self._config.LISTTAGS: for cls_name, cls in checks.items(): sys.stdout.write("{0:<20} {1}\n".format(cls_name, pydoc.getdoc(cls))) return addr_space = utils.load_as(self._config) system_range = tasks.get_kdbg(addr_space).MmSystemRangeStart.dereference_as("Pointer") # Only show threads owned by particular processes pidlist = [] if self._config.PID: pidlist = [int(p) for p in self._config.PID.split(',')] elif self._config.OFFSET: process = self.virtual_process_from_physical_offset(addr_space, self._config.OFFSET) if process: pidlist = [int(process.UniqueProcessId)] # Get sorted list of kernel modules mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # Are we on x86 or x64. Save this for render_text self.bits32 = addr_space.profile.metadata.\ get("memory_model", "32bit") == "32bit" # Get a list of hooked SSDTs but only on x86 if self.bits32: hooked_tables = self.get_hooked_tables(addr_space) else: hooked_tables = None # Dictionary to store threads. Keys are physical offsets of # ETHREAD objects. Values are tuples, where the first item is # a boolean specifying if the object was found by scanning and # the second item is the actual ETHREAD object. seen_threads = dict() # Gather threads by list traversal of active/linked processes for task in taskmods.DllList(self._config).calculate(): for thread in task.ThreadListHead.\ list_of_type("_ETHREAD", "ThreadListEntry"): seen_threads[thread.obj_vm.vtop(thread.obj_offset)] = (False, thread) # Now scan for threads and save any that haven't been seen for thread in modscan.ThrdScan(self._config).calculate(): if not seen_threads.has_key(thread.obj_offset): seen_threads[thread.obj_offset] = (True, thread) # Keep a record of processes whose DLLs we've already enumerated process_dll_info = {} for _offset, (found_by_scanner, thread) in seen_threads.items(): # Skip processes the user doesn't want to see if ((self._config.PID or self._config.OFFSET) and not pidlist) or (pidlist and thread.Cid.UniqueProcess not in pidlist): continue # Do we need to gather DLLs for module resolution if addr_space.address_compare(thread.StartAddress, system_range) != -1: owner = tasks.find_module(mods, mod_addrs, addr_space.address_mask(thread.StartAddress)) else: owning_process = thread.owning_process() if not owning_process.is_valid(): owner = None else: try: user_mod_addrs, user_mods = process_dll_info[owning_process.obj_offset] except KeyError: user_mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in owning_process.get_load_modules()) user_mod_addrs = sorted(user_mods.keys()) process_dll_info[owning_process.obj_offset] = (user_mod_addrs, user_mods) owner = tasks.find_module(user_mods, user_mod_addrs, addr_space.address_mask(thread.StartAddress)) if owner: owner_name = str(owner.BaseDllName or '') else: owner_name = "UNKNOWN" # Replace the dummy class with an instance instances = dict( (cls_name, cls(thread, mods, mod_addrs, hooked_tables, found_by_scanner)) for cls_name, cls in checks.items() ) yield thread, addr_space, mods, mod_addrs, \ instances, hooked_tables, system_range, owner_name