def calculate(self): addr_space = utils.load_as(self._config) ## Get a sorted list of module addresses mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) ssdts = set() if addr_space.profile.metadata.get('memory_model', '32bit') == '32bit': # Gather up all SSDTs referenced by threads debug.info("[x86] Gathering all referenced SSDTs from KTHREADs...") for proc in tasks.pslist(addr_space): for thread in proc.ThreadListHead.list_of_type( "_ETHREAD", "ThreadListEntry"): ssdt_obj = thread.Tcb.ServiceTable.dereference_as( '_SERVICE_DESCRIPTOR_TABLE') ssdts.add(ssdt_obj) else: debug.info( "[x64] Gathering all referenced SSDTs from KeAddSystemServiceTable..." ) # The NT module always loads first ntos = list(modules.lsmod(addr_space))[0] func_rva = ntos.getprocaddress("KeAddSystemServiceTable") if func_rva == None: raise StopIteration("Cannot locate KeAddSystemServiceTable") KeAddSystemServiceTable = ntos.DllBase + func_rva for table_rva in find_tables(KeAddSystemServiceTable, addr_space): ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", ntos.DllBase + table_rva, addr_space) ssdts.add(ssdt_obj) # Get a list of *unique* SSDT entries. Typically we see only two. tables = set() for ssdt_obj in ssdts: for i, desc in enumerate(ssdt_obj.Descriptors): # Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit # should be greater than 0 but not unbelievably high if not desc.is_valid( ) or desc.ServiceLimit <= 0 or desc.ServiceLimit >= 0xFFFF or desc.KiServiceTable <= 0x80000000: break else: tables.add( (i, desc.KiServiceTable.v(), desc.ServiceLimit.v())) debug.info("Finding appropriate address space for tables...") tables_with_vm = [] procs = list(tasks.pslist(addr_space)) for idx, table, n in tables: vm = tasks.find_space(addr_space, procs, table) if vm: tables_with_vm.append((idx, table, n, vm)) else: debug.debug("[SSDT not resident at 0x{0:08X}]\n".format(table)) for idx, table, n, vm in sorted(tables_with_vm, key=itemgetter(0)): yield idx, table, n, vm, mods, mod_addrs
def calculate(self): addr_space = utils.load_as(self._config) ## Get a sorted list of module addresses mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) ssdts = set() if addr_space.profile.metadata.get("memory_model", "32bit") == "32bit": # Gather up all SSDTs referenced by threads print "[x86] Gathering all referenced SSDTs from KTHREADs..." for proc in tasks.pslist(addr_space): for thread in proc.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"): ssdt_obj = thread.Tcb.ServiceTable.dereference_as("_SERVICE_DESCRIPTOR_TABLE") ssdts.add(ssdt_obj) else: print "[x64] Gathering all referenced SSDTs from KeAddSystemServiceTable..." # The NT module always loads first ntos = list(modules.lsmod(addr_space))[0] func_rva = ntos.getprocaddress("KeAddSystemServiceTable") if func_rva == None: raise StopIteration("Cannot locate KeAddSystemServiceTable") KeAddSystemServiceTable = ntos.DllBase + func_rva for table_rva in find_tables(KeAddSystemServiceTable, addr_space): ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", ntos.DllBase + table_rva, addr_space) ssdts.add(ssdt_obj) # Get a list of *unique* SSDT entries. Typically we see only two. tables = set() for ssdt_obj in ssdts: for i, desc in enumerate(ssdt_obj.Descriptors): # Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit # should be greater than 0 but not unbelievably high if ( desc.is_valid() and desc.ServiceLimit > 0 and desc.ServiceLimit < 0xFFFF and desc.KiServiceTable > 0x80000000 ): tables.add((i, desc.KiServiceTable.v(), desc.ServiceLimit.v())) print "Finding appropriate address space for tables..." tables_with_vm = [] procs = list(tasks.pslist(addr_space)) for idx, table, n in tables: vm = tasks.find_space(addr_space, procs, table) if vm: tables_with_vm.append((idx, table, n, vm)) else: debug.debug("[SSDT not resident at 0x{0:08X}]\n".format(table)) for idx, table, n, vm in sorted(tables_with_vm, key=itemgetter(0)): yield idx, table, n, vm, mods, mod_addrs
def driver_dump(self): procs = list(tasks.pslist(self.addr_space)) mods = dict( (mod.DllBase.v(), mod) for mod in modules.lsmod(self.addr_space)) for mod in mods.values(): mod_base = mod.DllBase.v() mode_end = mod_base + mod.SizeOfImage space = tasks.find_space(self.addr_space, procs, mod_base) if space: pe_data = self.get_pe_content(space, mod_base) if self._config.LIST_SECTIONS: yield PESection(mod.BaseDllName, self.get_pe_sections(pe_data)) else: sections = self.process_section(None, self._config.SECTION, pe_data) for sec in sections: for engine in self.hash_engines: yield DriverObject(sec['data'], mod_base, mode_end, mod.FullDllName, engine, sec['section']) if self._config.TMP_FOLDER: dump_path = os.path.join( self._config.TMP_FOLDER, 'driver.{0:x}.{1}{2}.sys'.format( mod_base, mod.BaseDllName, sec['section'])) self.backup_file(dump_path, sec['data'])
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 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 calculate(self): addr_space = utils.load_as(self._config) if self._config.REGEX: try: if self._config.IGNORE_CASE: mod_re = re.compile(self._config.REGEX, re.I) else: mod_re = re.compile(self._config.REGEX) except re.error as e: debug.error('Error parsing regular expression: %s' % e) mods = dict((mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space)) # We need the process list to find spaces for some drivers. Enumerate them here # instead of inside the find_space function, so we only have to do it once. procs = list(tasks.pslist(addr_space)) if self._config.BASE: if self._config.BASE in mods: mod_name = mods[self._config.BASE].BaseDllName else: mod_name = "UNKNOWN" yield addr_space, procs, int(self._config.BASE), mod_name else: for mod in list(mods.values()): if self._config.REGEX: if not mod_re.search(str(mod.FullDllName or '')) and not mod_re.search(str(mod.BaseDllName or '')): continue yield addr_space, procs, mod.DllBase.v(), mod.BaseDllName
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): addr_space = utils.load_as(self._config) if self._config.REGEX: try: if self._config.IGNORE_CASE: mod_re = re.compile(self._config.REGEX, re.I) else: mod_re = re.compile(self._config.REGEX) except re.error as e: debug.error('Error parsing regular expression: {0}'.format(e)) mods = dict( (mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space)) # We need the process list to find spaces for some drivers. Enumerate them here # instead of inside the find_space function, so we only have to do it once. procs = list(tasks.pslist(addr_space)) if self._config.BASE: if self._config.BASE in mods: mod_name = mods[self._config.BASE].BaseDllName else: mod_name = "UNKNOWN" yield addr_space, procs, int(self._config.BASE), mod_name else: for mod in list(mods.values()): if self._config.REGEX: if not mod_re.search(str(mod.FullDllName or '')) and not mod_re.search( str(mod.BaseDllName or '')): continue yield addr_space, procs, mod.DllBase.v(), mod.BaseDllName
def calculate(self): addr_space = utils.load_as(self._config) tasklist = [] modslist = [] if self._config.SCAN: if not self._config.KERNEL_ONLY: for t in filescan.PSScan(self._config).calculate(): v = self.virtual_process_from_physical_offset(addr_space, t.obj_offset) if v: tasklist.append(v) if not self._config.PROCESS_ONLY: modslist = [m for m in modscan.ModScan(self._config).calculate()] else: if not self._config.KERNEL_ONLY: tasklist = [t for t in tasks.pslist(addr_space)] if not self._config.PROCESS_ONLY: modslist = [m for m in modules.lsmod(addr_space)] for task in tasklist: for mod in task.get_load_modules(): yield task, mod for mod in modslist: yield None, mod
def gather_exports_symbols_values(self): symbols_values = [] addr_space = utils.load_as(self._config) ############################# # collect kernel mode exports if self._config.PID == None: all_mods = list(modules.lsmod(addr_space)) for mod in all_mods: if mod.DllBase != self._config.BASE: dllBaseAppended = False for ordinal, func_addr, func_name in mod.exports(): if func_addr != None: name = func_name or ordinal or '' if self._config.AGGRESIVE or ( "%s" % mod.BaseDllName ).lower() in self.kernel_common_mods: if self._config.DLLBASES and not dllBaseAppended: symbols_values.append( (mod.DllBase, ("dllbase_%s" % mod.BaseDllName).replace( ".", "_").lower())) dllBaseAppended = True symbols_values.append( (mod.DllBase + func_addr, str(name) )) #"%s_%s" % (mod.BaseDllName, name)) ########################### # collect user mode exports # for specified process else: for prc in tasks.pslist(addr_space): if prc.UniqueProcessId == self._config.PID: #addr_space = prc.get_process_address_space() for mod in prc.get_load_modules(): if mod.DllBase != self._config.BASE: dllBaseAppended = False for ordinal, func_addr, func_name in mod.exports(): if func_addr != None: name = func_name or ordinal or '' if self._config.AGGRESIVE or ( "%s" % mod.BaseDllName ).lower() in self.user_common_mods: if self._config.DLLBASES and not dllBaseAppended: symbols_values.append( (mod.DllBase, ("dllbase_%s" % mod.BaseDllName).replace( ".", "_").lower())) dllBaseAppended = True symbols_values.append( (mod.DllBase + func_addr, str(name)) ) #"%s_%s" % (mod.BaseDllName, name))) break return symbols_values
class ModDump(procdump.ProcDump): """Dump a kernel driver to an executable file sample""" def __init__(self, config, *args, **kwargs): procdump.ProcDump.__init__(self, config, *args, **kwargs) config.remove_option("PID") config.remove_option("OFFSET") config.remove_option("NAME") config.add_option('REGEX', short_option='r', help='Dump modules matching REGEX', action='store', type='string') config.add_option('IGNORE-CASE', short_option='i', help='Ignore case in pattern match', action='store_true', default=False) config.add_option('BASE', short_option='b', default=None, help='Dump driver with BASE address (in hex)', action='store', type='int') @cache.CacheDecorator( lambda self: "tests/moddump/regex={0}/ignore-case={1}/base={2}".format( self._config.REGEX, self._config.IGNORE_CASE, self._config.BASE)) def calculate(self): addr_space = utils.load_as(self._config) if self._config.REGEX: try: if self._config.IGNORE_CASE: mod_re = re.compile(self._config.REGEX, re.I) else: mod_re = re.compile(self._config.REGEX) except re.error, e: debug.error('Error parsing regular expression: {0}'.format(e)) mods = dict( (mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space)) # We need the process list to find spaces for some drivers. Enumerate them here # instead of inside the find_space function, so we only have to do it once. procs = list(tasks.pslist(addr_space)) if self._config.BASE: if mods.has_key(self._config.BASE): mod_name = mods[self._config.BASE].BaseDllName else: mod_name = "UNKNOWN" yield addr_space, procs, int(self._config.BASE), mod_name else: for mod in mods.values(): if self._config.REGEX: if not mod_re.search(str(mod.FullDllName or '')) and not mod_re.search( str(mod.BaseDllName or '')): continue yield addr_space, procs, mod.DllBase.v(), mod.BaseDllName
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 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) # 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 calculate(self): addr_space = utils.load_as(self._config) for mod in modules.lsmod(addr_space): # Finding the VC kernel module if str(mod.BaseDllName).lower() == "veracrypt.sys" or str( mod.BaseDllName).lower() == "veracrypt-x64.sys": for offset, password in self.scan_module( addr_space, mod.DllBase, self._config.MIN_LENGTH): yield offset, password
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) addr_space.profile.add_types(sde_types) if addr_space.profile.metadata.get("major", 0) == 5 and addr_space.profile.metadata.get("minor", 0) == 2: addr_space.profile.add_types(sdt_types_2k3) else: addr_space.profile.add_types(sdt_types) ## Get a sorted list of module addresses mods = dict((mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # Gather up all SSDTs referenced by threads print "Gathering all referenced SSDTs from KTHREADs..." ssdts = set() for proc in tasks.pslist(addr_space): for thread in proc.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"): ssdt_obj = thread.Tcb.ServiceTable.dereference_as("_SERVICE_DESCRIPTOR_TABLE") ssdts.add(ssdt_obj) # Get a list of *unique* SSDT entries. Typically we see only two. tables = set() for ssdt_obj in ssdts: for i, desc in enumerate(ssdt_obj.Descriptors): # Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit # should be greater than 0 but not unbelievably high if ( desc.is_valid() and desc.ServiceLimit > 0 and desc.ServiceLimit < 0xFFFF and desc.KiServiceTable > 0x80000000 ): tables.add((i, desc.KiServiceTable.v(), desc.ServiceLimit.v())) print "Finding appropriate address space for tables..." tables_with_vm = [] for idx, table, n in tables: found = False for p in tasks.pslist(addr_space): ## This is the process address space ps_ad = p.get_process_address_space() ## Is the table accessible from the process AS? if ps_ad.is_valid_address(table): tables_with_vm.append((idx, table, n, ps_ad)) found = True break ## If not we use the kernel address space if not found: # Any VM is equally bad... tables_with_vm.append((idx, table, n, addr_space)) for idx, table, n, vm in sorted(tables_with_vm, key=itemgetter(0)): yield idx, table, n, vm, mods, mod_addrs
def calculate(self): addr_space = utils.load_as(self._config) for mod in modules.lsmod(addr_space): # Finding the TC kernel module if str(mod.BaseDllName).lower() != "truecrypt.sys": continue for offset, password in self.scan_module(addr_space, mod.DllBase, self._config.MIN_LENGTH): yield offset, password
def calculate(self): if self._config.TAP_FILE is None or not os.path.exists( self._config.TAP_FILE): debug.error("Tap file not found") taplist = open(self._config.TAP_FILE, "r") taps = [] for line in taplist: line = line.split() (stack, cr3) = line[:-1], line[-1] try: stack = [int(s, 16) for s in stack] cr3 = int(cr3, 16) except ValueError: debug.error("Tap file format invalid.") taps.append((stack, cr3)) cr3s = set(t[1] for t in taps) cr3s.discard(0) # First do the userland ones addr_space = utils.load_as(self._config) procs = list(tasks.pslist(addr_space)) # CR3 => proc mapping proc_map = {} for proc in procs: dtb = proc.Pcb.DirectoryTableBase.v() if dtb in cr3s: proc_map[dtb] = proc for cr3, proc in proc_map.items(): print ">>> Working on {0}[{1}]".format(proc.ImageFileName, proc.UniqueProcessId) ps_ad = proc.get_process_address_space() proc_taps = [t for t in taps if t[1] == cr3] mods = list(proc.get_load_modules()) sorted_mods = sorted([(m.DllBase.v(), m.SizeOfImage.v(), str(m.BaseDllName)) for m in mods]) for v in self.resolve_taps(proc_taps, sorted_mods, lambda m: ps_ad): yield v + (proc.ImageFileName, ) # Now kernel mode taps print ">>> Working on kernel taps" kern_taps = [t for t in taps if t[1] == 0] sorted_mods = sorted([(mod.DllBase.v(), mod.SizeOfImage.v(), str(mod.BaseDllName)) for mod in modules.lsmod(addr_space)]) bases = [m[0] for m in sorted_mods] for v in self.resolve_taps( kern_taps, sorted_mods, lambda m: tasks.find_space(addr_space, procs, m)): yield v + ("Kernel", )
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): # All scanners will share a kernel and physical space self.kern_space = utils.load_as(self._config) self.phys_space = utils.load_as(self._config, astype='physical') # We currently dont support x64 if not self.is_valid_profile(self.kern_space.profile): debug.error("This command does not support the selected profile.") # Get the OS version we're analyzing version = (self.kern_space.profile.metadata.get('major', 0), self.kern_space.profile.metadata.get('minor', 0)) modlist = list(modules.lsmod(self.kern_space)) mods = dict((self.kern_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) # First few routines are valid on all OS versions for info in self.get_fs_callbacks(): yield info, mods, mod_addrs for info in self.get_bugcheck_callbacks(): yield info, mods, mod_addrs for info in self.get_shutdown_callbacks(): yield info, mods, mod_addrs for info in self.get_generic_callbacks(): yield info, mods, mod_addrs for info in self.get_bugcheck_reason_callbacks(modlist[0]): yield info, mods, mod_addrs for info in self.get_kernel_callbacks(modlist[0]): yield info, mods, mod_addrs # Valid for Vista and later if version >= (6, 0): for info in self.get_dbgprint_callbacks(): yield info, mods, mod_addrs for info in self.get_registry_callbacks(): yield info, mods, mod_addrs for info in self.get_pnp_callbacks(): yield info, mods, mod_addrs # Valid for XP if version == (5, 1): for info in self.get_registry_callbacks_legacy(modlist[0]): yield info, mods, mod_addrs
def calculate(self): # All scanners will share a kernel and physical space self.kern_space = utils.load_as(self._config) self.phys_space = utils.load_as(self._config, astype = 'physical') # We currently dont support x64 if not self.is_valid_profile(self.kern_space.profile): debug.error("This command does not support the selected profile.") # Get the OS version we're analyzing version = (self.kern_space.profile.metadata.get('major', 0), self.kern_space.profile.metadata.get('minor', 0)) modlist = list(modules.lsmod(self.kern_space)) mods = dict((self.kern_space.address_mask(mod.DllBase), mod) for mod in modlist) mod_addrs = sorted(mods.keys()) # First few routines are valid on all OS versions for info in self.get_fs_callbacks(): yield info, mods, mod_addrs for info in self.get_bugcheck_callbacks(): yield info, mods, mod_addrs for info in self.get_shutdown_callbacks(): yield info, mods, mod_addrs for info in self.get_generic_callbacks(): yield info, mods, mod_addrs for info in self.get_bugcheck_reason_callbacks(modlist[0]): yield info, mods, mod_addrs for info in self.get_kernel_callbacks(modlist[0]): yield info, mods, mod_addrs # Valid for Vista and later if version >= (6, 0): for info in self.get_dbgprint_callbacks(): yield info, mods, mod_addrs for info in self.get_registry_callbacks(): yield info, mods, mod_addrs for info in self.get_pnp_callbacks(): yield info, mods, mod_addrs # Valid for XP if version == (5, 1): for info in self.get_registry_callbacks_legacy(modlist[0]): yield info, mods, mod_addrs
def get_thread_modules(thread, config): # get the loaded modules of the process containing the thread # this function also pays respect to already gathered modules # for increased performance global kernel_modules global enumerated_processes thread_modules = [] user_modules = [] addr_space = utils.load_as(config) system_range = tasks.get_kdbg( addr_space).MmSystemRangeStart.dereference_as("Pointer") if len(kernel_modules) == 0: for mod in modules.lsmod(addr_space): if mod: thread_modules.append(ThreadModule(mod)) thread_modules[-1].functions = get_module_exports( thread, thread_modules[-1].ldr_object) thread_modules[-1].functions = sorted( thread_modules[-1].functions, key=lambda item: item.address) thread_modules = sorted(thread_modules, key=lambda item: item.ldr_object.DllBase) kernel_modules = thread_modules else: pass owning_process = thread.owning_process() if not owning_process.is_valid(): owner = None else: try: user_modules = enumerated_processes[owning_process.obj_offset] except KeyError: for mod in owning_process.get_load_modules(): if mod: user_modules.append(ThreadModule(mod)) user_modules[-1].functions = get_module_exports( thread, user_modules[-1].ldr_object) user_modules[-1].functions = sorted( user_modules[-1].functions, key=lambda item: item.address) user_modules = sorted(user_modules, key=lambda item: item.ldr_object.DllBase) enumerated_processes[owning_process.obj_offset] = user_modules thread_modules = user_modules + kernel_modules return thread_modules
def Win32KBase(self): """Get the base address of the win32k.sys as mapped into this session's memory. Since win32k.sys is always the first image to be mapped, we can just grab the first list entry. Update: we no longer use the session image list, because it seems to have gone away in Win8/2012.""" for mod in modules.lsmod(self.obj_vm): if str(mod.BaseDllName or '').lower() == "win32k.sys": return mod.DllBase return obj.Object("Cannot find win32k.sys base address")
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 calculate(self): addr_space = utils.load_as(self._config) for mod in modules.lsmod(addr_space): # Finding the TC kernel module if str(mod.BaseDllName).lower() != "truecrypt.sys": continue dos_header = obj.Object("_IMAGE_DOS_HEADER", offset = mod.DllBase, vm = addr_space) nt_header = dos_header.get_nt_header() # Finding the PE data section data_section = None for sec in nt_header.get_sections(): if str(sec.Name) == ".data": data_section = sec break if not data_section: break base = sec.VirtualAddress + mod.DllBase size = sec.Misc.VirtualSize # Looking for the Length member, DWORD-aligned ints = obj.Object("Array", targetType = "int", offset = base, count = size / 4, vm = addr_space) for length in ints: # Min and max passphrase lengths if length >= self._config.MIN_LENGTH and length <= 64: offset = length.obj_offset + 4 passphrase = addr_space.read(offset, length) if not passphrase: continue # All characters in the range must be ASCII chars = [c for c in passphrase if ord(c) >= 0x20 and ord(c) <= 0x7F] if len(chars) != length: continue # At least three zero-bad bytes must follow if addr_space.read(offset + length, 3) != "\x00" * 3: continue yield offset, passphrase
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 get_target_mod_name(self): addr_space = utils.load_as(self._config) # kernel mod if self._config.PID == None: all_mods = list(modules.lsmod(addr_space)) for mod in all_mods: if self._config.BASE == mod.DllBase: return os.path.splitext(str(mod.BaseDllName))[0] # user mod else: for prc in tasks.pslist(addr_space): if prc.UniqueProcessId == self._config.PID: print "pid: %d" % prc.UniqueProcessId for mod in prc.get_load_modules(): print "mod: %x" % mod.DllBase if self._config.BASE == mod.DllBase: return os.path.splitext(str(mod.BaseDllName))[0] break return "unknown"
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 calculate(self): addr_space = utils.load_as(self._config) for mod in modules.lsmod(addr_space): # Finding the TC kernel module if str(mod.BaseDllName).lower() != "truecrypt.sys": continue dos_header = obj.Object("_IMAGE_DOS_HEADER", offset=mod.DllBase, vm=addr_space) nt_header = dos_header.get_nt_header() # Finding the PE data section data_section = None for sec in nt_header.get_sections(): if str(sec.Name) == ".data": data_section = sec break if not data_section: break base = sec.VirtualAddress + mod.DllBase size = sec.Misc.VirtualSize # Looking for the Length member, DWORD-aligned ints = obj.Object("Array", targetType="int", offset=base, count=size / 4, vm=addr_space) for length in ints: # Min and max passphrase lengths if length >= self._config.MIN_LENGTH and length <= 64: offset = length.obj_offset + 4 passphrase = addr_space.read(offset, length) if not passphrase: continue # All characters in the range must be ASCII chars = [c for c in passphrase if ord(c) >= 0x20 and ord(c) <= 0x7F] if len(chars) != length: continue # At least three zero-bad bytes must follow if addr_space.read(offset + length, 3) != "\x00" * 3: continue yield offset, passphrase
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 gather_exports_symbols_values(self): symbols_values = [] addr_space = utils.load_as(self._config) ############################# # collect kernel mode exports if self._config.PID == None: all_mods = list(modules.lsmod(addr_space)) for mod in all_mods: if mod.DllBase != self._config.BASE: dllBaseAppended = False for ordinal, func_addr, func_name in mod.exports(): if func_addr != None: name = func_name or ordinal or '' if self._config.AGGRESIVE or ("%s" % mod.BaseDllName).lower() in self.kernel_common_mods: if self._config.DLLBASES and not dllBaseAppended: symbols_values.append((mod.DllBase, ("dllbase_%s" % mod.BaseDllName).replace(".","_").lower())) dllBaseAppended = True symbols_values.append((mod.DllBase + func_addr, str(name))) #"%s_%s" % (mod.BaseDllName, name)) ########################### # collect user mode exports # for specified process else: for prc in tasks.pslist(addr_space): if prc.UniqueProcessId == self._config.PID: #addr_space = prc.get_process_address_space() for mod in prc.get_load_modules(): if mod.DllBase != self._config.BASE: dllBaseAppended = False for ordinal, func_addr, func_name in mod.exports(): if func_addr != None: name = func_name or ordinal or '' if self._config.AGGRESIVE or ("%s" % mod.BaseDllName).lower() in self.user_common_mods: if self._config.DLLBASES and not dllBaseAppended: symbols_values.append((mod.DllBase, ("dllbase_%s" % mod.BaseDllName).replace(".","_").lower())) dllBaseAppended = True symbols_values.append((mod.DllBase + func_addr, str(name))) #"%s_%s" % (mod.BaseDllName, name))) break return symbols_values
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 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 _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 calculate(self): addr_space = utils.load_as(self._config) bits32 = addr_space.profile.metadata.get("memory_model", "32bit") == "32bit" # 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()) # Valid for Vista and later if version >= (6, 0): self.scanners.append(PoolScanDbgPrintCallback) self.scanners.append(PoolScanRegistryCallback) self.scanners.append(PoolScanPnp9) self.scanners.append(PoolScanPnpD) self.scanners.append(PoolScanPnpC) for objct in self.scan_results(addr_space): name = objct.obj_name if name == "_REGISTRY_CALLBACK": info = "CmRegisterCallback", objct.Function, None yield info, mods, mod_addrs elif name == "_DBGPRINT_CALLBACK": info = "DbgSetDebugPrintCallback", objct.Function, None yield info, mods, mod_addrs elif name == "_SHUTDOWN_PACKET": driver = objct.DeviceObject.dereference().DriverObject index = devicetree.MAJOR_FUNCTIONS.index('IRP_MJ_SHUTDOWN') address = driver.MajorFunction[index] details = str(driver.DriverName or "-") info = "IoRegisterShutdownNotification", address, details yield info, mods, mod_addrs elif name == "_GENERIC_CALLBACK": info = "GenericKernelCallback", objct.Callback, None yield info, mods, mod_addrs elif name == "_NOTIFY_ENTRY_HEADER": # Dereference the driver object pointer driver = objct.DriverObject.dereference() # Instantiate an object header for the driver name header = driver.get_object_header() # Grab the object name driver_name = header.NameInfo.Name.v() info = objct.EventCategory, objct.CallbackRoutine, driver_name yield info, mods, mod_addrs elif name == "_NOTIFICATION_PACKET": info = "IoRegisterFsRegistrationChange", objct.NotificationRoutine, None yield info, mods, mod_addrs for info in self.get_kernel_callbacks(modlist[0]): yield info, mods, mod_addrs for info in self.get_bugcheck_callbacks(addr_space): yield info, mods, mod_addrs for info in self.get_bugcheck_reason_callbacks(modlist[0]): yield info, mods, mod_addrs # Valid for XP if bits32 and version == (5, 1): for info in self.get_registry_callbacks_legacy(modlist[0]): yield info, mods, mod_addrs
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 calculate(self): if not has_distorm: debug.error("You must install distorm3") addr_space = utils.load_as(self._config) all_tasks = list(tasks.pslist(addr_space)) all_mods = list(modules.lsmod(addr_space)) # Operate in kernel mode if pid is not supplied if not self._config.PID: if not self._config.BASE: debug.error("You must specify --BASE") base_address = self._config.BASE size_to_read = self._config.SIZE # Get the size from the module list if its not supplied if not size_to_read: for module in all_mods: if module.DllBase == base_address: size_to_read = module.SizeOfImage break # Alternately, try the size from the PE header if not size_to_read: pefile = obj.Object("_IMAGE_DOS_HEADER", offset = base_address, vm = addr_space) try: nt_header = pefile.get_nt_header() size_to_read = nt_header.OptionalHeader.SizeOfImage except ValueError: pass if not size_to_read: debug.error("You must specify --SIZE") kernel_space = tasks.find_space(addr_space, all_tasks, base_address) if not kernel_space: debug.error("Cannot read supplied address") data = kernel_space.zread(base_address, size_to_read) apis = self.enum_apis(all_mods) addr_space = kernel_space else: # In process mode, we find the process by PID task = None for atask in all_tasks: if atask.UniqueProcessId == self._config.PID: task = atask break if not task: debug.error("You must supply an active PID") task_space = task.get_process_address_space() if not task_space: debug.error("Cannot acquire process AS") all_mods = list(task.get_load_modules()) # PEB is paged or no DLLs loaded if not all_mods: debug.error("Cannot load DLLs in process AS") # If an address is supplied with a size, try to get # the size from the vad node. If neither are supplied, # assume we should carve the main process executable. if self._config.BASE: base_address = self._config.BASE size_to_read = self._config.SIZE if not size_to_read: for vad in task.VadRoot.traverse(): if base_address >= vad.Start and base_address <= vad.End: size_to_read = vad.Length if not size_to_read: debug.error("You must specify --SIZE") else: # Its OK to blindly take the 0th element because the # executable is always the first module to load. base_address = all_mods[0].DllBase size_to_read = all_mods[0].SizeOfImage if not task_space.is_valid_address(base_address): debug.error("Address is not valid in process AS") data = task_space.zread(base_address, size_to_read) apis = self.enum_apis(all_mods) addr_space = task_space # This is a dictionary of confirmed API calls. calls_imported = dict( (iat, call) for (_, iat, call) in self.call_scan(addr_space, base_address, data) if call in apis ) # Scan forward self._vicinity_scan(addr_space, calls_imported, apis, base_address, len(data), forward = True) # Scan reverse self._vicinity_scan(addr_space, calls_imported, apis, base_address, len(data), forward = False) for iat, call in sorted(calls_imported.items()): yield iat, call, apis[call][0], apis[call][1]
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 = {} 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): # 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 list(checks.items()): sys.stdout.write("{0:<20} {1}\n".format( cls_name, pydoc.getdoc(cls))) return addr_space = utils.load_as(self._config) # Only show threads owned by particular processes if self._config.PID: pidlist = [int(p) for p in self._config.PID.split(',')] else: pidlist = [] # Get sorted list of kernel modules mods = dict((mod.DllBase, mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # Gather processes all_tasks = list(tasks.pslist(addr_space)) # 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 self.filter_tasks(all_tasks): 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 thread.obj_offset not in seen_threads: seen_threads[thread.obj_offset] = (True, thread) for _offset, (found_by_scanner, thread) in list(seen_threads.items()): # Skip processes the user doesn't want to see if pidlist and thread.Cid.UniqueProcess not in pidlist: continue # Replace the dummy class with an instance for cls_name, cls in list(checks.items()): instances = dict((cls_name, cls(thread, mods, mod_addrs, hooked_tables, found_by_scanner)) for cls_name, cls in list(checks.items())) yield thread, addr_space, mods, mod_addrs, instances, hooked_tables
def render_text(self, outfd, data): outfd.write("\n") outfd.write("------- driver IRP check -------- \n\n") 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', '') ]) drivers = dict() numberOfDrivers = 0 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)) #print driver_name numberOfDrivers += 1 drivers[driver_name] = {} #functions = [] # Write the address and owner of each IRP function for ii, function in enumerate(driver.MajorFunction): functions = [] function = driver.MajorFunction[ii] 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], fnction, module_name) currentFunction = MAJOR_FUNCTIONS[ii] currentFunctionNr = ii #print "1337 - " + str(ii) + " - " + str(currentFunction) 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) #])) nameFunction = currentFunction #outfd.write("instruksjon \n") #for o, i, h in malfind.Disassemble(data = data, start = function, bits = bits, stoponret = True): #outfd.write(i + "\n") #if "0x" in str(i): # i = "--" #i = re.sub('([0x])\w+', '0x000', i) #instructions.append(i) functions.append(module_name) drivers[driver_name][str(currentFunctionNr) + " - " + str(nameFunction)] = functions #outfd.write("instruksjon slutt \n") #functions[str(str(currentFunctionNr) + " - "+ currentFunction)].append(instructions) #print functions.keys() #drivers[driver_name].append(functions) outfd.write("# of drivers collected: " + str(numberOfDrivers) +"\n\n" ) locationString = str(conf.ConfObject.opts["location"]).rsplit('/',1)[1] + "_DriverList" outfd.write("Storing DriverList as \"" + locationString + "\"\n") #print drivers with open(locationString + '.p', 'wb') as fp: pickle.dump(drivers, fp)
def calculate(self): addr_space = utils.load_as(self._config) if not has_distorm3: debug.error("Install distorm3 code.google.com/p/distorm/") if not self._config.SKIP_PROCESS: for proc in self.filter_tasks(tasks.pslist(addr_space)): process_name = str(proc.ImageFileName).lower() if (self._config.QUICK and process_name not in self.critical_process): #debug.debug("Skipping non-critical process {0} ({1})".format( # process_name, proc.UniqueProcessId)) continue process_space = proc.get_process_address_space() if not process_space: #debug.debug("Cannot acquire process AS for {0} ({1})".format( # process_name, proc.UniqueProcessId)) continue module_group = ModuleGroup(proc.get_load_modules()) for dll in module_group.mods: if not process_space.is_valid_address(dll.DllBase): continue dll_name = str(dll.BaseDllName or '').lower() if (self._config.QUICK and dll_name not in self.critical_dlls and dll.DllBase != proc.Peb.ImageBaseAddress): #debug.debug("Skipping non-critical dll {0} at {1:#x}".format( # dll_name, dll.DllBase)) continue #debug.debug("Analyzing {0}!{1}".format(process_name, dll_name)) for hook in self.get_hooks(HOOK_MODE_USER, process_space, dll, module_group): if not self._config.NO_WHITELIST: if self.whitelist(hook.hook_mode | hook.hook_type, str(proc.ImageFileName), hook.VictimModule, hook.HookModule, hook.Function): continue yield proc, dll, hook if not self._config.SKIP_KERNEL: process_list = list(tasks.pslist(addr_space)) module_group = ModuleGroup(modules.lsmod(addr_space)) for mod in module_group.mods: #module_name = str(mod.BaseDllName or '') #debug.debug("Analyzing {0}".format(module_name)) kernel_space = tasks.find_space(addr_space, process_list, mod.DllBase) if not kernel_space: #debug.debug("No kernel AS for {0} at {1:#x}".format( # module_name, mod.DllBase)) continue for hook in self.get_hooks(HOOK_MODE_KERNEL, kernel_space, mod, module_group): if not self._config.NO_WHITELIST: if self.whitelist(hook.hook_mode | hook.hook_type, "", hook.VictimModule, hook.HookModule, hook.Function): continue yield None, mod, hook
def calculate(self): # 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) # Only show threads owned by particular processes if self._config.PID: pidlist = [int(p) for p in self._config.PID.split(',')] else: pidlist = [] # Get sorted list of kernel modules mods = dict((mod.DllBase, mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) # Gather processes all_tasks = list(tasks.pslist(addr_space)) # 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 self.filter_tasks(all_tasks): 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) for _offset, (found_by_scanner, thread) in seen_threads.items(): # Skip processes the user doesn't want to see if pidlist and thread.Cid.UniqueProcess not in pidlist: continue # Replace the dummy class with an instance for cls_name, cls in checks.items(): 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
def calculate(self): addr_space = utils.load_as(self._config) # we currently don't use this on x64 because for some reason the # x64 version actually doesn't create a DisplayVersion value memory_model = addr_space.profile.metadata.get('memory_model') if memory_model == '32bit': regapi = registryapi.RegistryApi(self._config) regapi.reset_current() regapi.set_current(hive_name = "software") x86key = "Microsoft\\Windows\\CurrentVersion\\Uninstall" x64key = "Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" for subkey in regapi.reg_get_all_subkeys(None, key = x86key): if str(subkey.Name) == "TrueCrypt": subpath = x86key + "\\" + subkey.Name version = regapi.reg_get_value("software", key = subpath, value = "DisplayVersion") if version: yield "Registry Version", "{0} Version {1}".format( str(subkey.Name), version) scanner = TrueCryptPassphrase(self._config) for offset, passphrase in scanner.calculate(): yield "Password", "{0} at offset {1:#x}".format( passphrase, offset) for proc in tasks.pslist(addr_space): if str(proc.ImageFileName).lower() == "truecrypt.exe": yield "Process", "{0} at {1:#x} pid {2}".format( proc.ImageFileName, proc.obj_offset, proc.UniqueProcessId) scanner = svcscan.SvcScan(self._config) for service in scanner.calculate(): name = str(service.ServiceName.dereference()) if name == "truecrypt": yield "Service", "{0} state {1}".format( name, service.State) for mod in modules.lsmod(addr_space): basename = str(mod.BaseDllName or '').lower() fullname = str(mod.FullDllName or '').lower() if (basename.endswith("truecrypt.sys") or fullname.endswith("truecrypt.sys")): yield "Kernel Module", "{0} at {1:#x} - {2:#x}".format( mod.BaseDllName, mod.DllBase, mod.DllBase + mod.SizeOfImage) scanner = filescan.SymLinkScan(self._config) for symlink in scanner.calculate(): object_header = symlink.get_object_header() if "TrueCryptVolume" in str(symlink.LinkTarget or ''): yield "Symbolic Link", "{0} -> {1} mounted {2}".format( str(object_header.NameInfo.Name or ''), str(symlink.LinkTarget or ''), str(symlink.CreationTime or '')) scanner = filescan.FileScan(self._config) for fileobj in scanner.calculate(): filename = str(fileobj.file_name_with_device() or '') if "TrueCryptVolume" in filename: yield "File Object", "{0} at {1:#x}".format( filename, fileobj.obj_offset) scanner = filescan.DriverScan(self._config) for driver in scanner.calculate(): object_header = driver.get_object_header() driverext = driver.DriverExtension drivername = str(driver.DriverName or '') servicekey = str(driverext.ServiceKeyName or '') if (drivername.endswith("truecrypt") or servicekey.endswith("truecrypt")): yield "Driver", "{0} at {1:#x} range {2:#x} - {3:#x}".format( drivername, driver.obj_offset, driver.DriverStart, driver.DriverStart + driver.DriverSize) for device in driver.devices(): header = device.get_object_header() devname = str(header.NameInfo.Name or '') type = devicetree.DEVICE_CODES.get(device.DeviceType.v()) yield "Device", "{0} at {1:#x} type {2}".format( devname or "<HIDDEN>", device.obj_offset, type or "UNKNOWN") if type == "FILE_DEVICE_DISK": data = addr_space.read(device.DeviceExtension, 2000) ## the file-hosted container path. no other fields in ## the struct are character based, so we should not ## hit false positives on this scan. offset = data.find("\\\x00?\x00?\x00\\\x00") if offset == -1: container = "<HIDDEN>" else: container = obj.Object("String", length = 255, offset = device.DeviceExtension + offset, encoding = "utf16", vm = addr_space) yield "Container", "Path: {0}".format(container)
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 calculate(self): addr_space = utils.load_as(self._config) if not has_distorm3: debug.error("Install distorm3 code.google.com/p/distorm/") if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") if not self._config.SKIP_PROCESS: for proc in self.filter_tasks(tasks.pslist(addr_space)): process_name = str(proc.ImageFileName).lower() if (self._config.QUICK and process_name not in self.critical_process): #debug.debug("Skipping non-critical process {0} ({1})".format( # process_name, proc.UniqueProcessId)) continue process_space = proc.get_process_address_space() if not process_space: #debug.debug("Cannot acquire process AS for {0} ({1})".format( # process_name, proc.UniqueProcessId)) continue module_group = ModuleGroup(proc.get_load_modules()) for dll in module_group.mods: if not process_space.is_valid_address(dll.DllBase): continue dll_name = str(dll.BaseDllName or '').lower() if (self._config.QUICK and dll_name not in self.critical_dlls and dll.DllBase != proc.Peb.ImageBaseAddress): #debug.debug("Skipping non-critical dll {0} at {1:#x}".format( # dll_name, dll.DllBase)) continue #debug.debug("Analyzing {0}!{1}".format(process_name, dll_name)) for hook in self.get_hooks(HOOK_MODE_USER, process_space, dll, module_group): yield proc, dll, hook if not self._config.SKIP_KERNEL: process_list = list(tasks.pslist(addr_space)) module_group = ModuleGroup(modules.lsmod(addr_space)) for mod in module_group.mods: #module_name = str(mod.BaseDllName or '') #debug.debug("Analyzing {0}".format(module_name)) kernel_space = tasks.find_space(addr_space, process_list, mod.DllBase) if not kernel_space: #debug.debug("No kernel AS for {0} at {1:#x}".format( # module_name, mod.DllBase)) continue for hook in self.get_hooks(HOOK_MODE_KERNEL, kernel_space, mod, module_group): yield None, mod, hook
def calculate(self): if not has_distorm: debug.error("You must install distorm3") addr_space = utils.load_as(self._config) all_tasks = list(tasks.pslist(addr_space)) all_mods = list(modules.lsmod(addr_space)) # Operate in kernel mode if pid is not supplied if not self._config.PID: if not self._config.BASE: debug.error("You must specify --BASE") base_address = self._config.BASE size_to_read = self._config.SIZE # Get the size from the module list if its not supplied if not size_to_read: for module in all_mods: if module.DllBase == base_address: size_to_read = module.SizeOfImage break # Alternately, try the size from the PE header if not size_to_read: pefile = obj.Object("_IMAGE_DOS_HEADER", offset=base_address, vm=addr_space) try: nt_header = pefile.get_nt_header() size_to_read = nt_header.OptionalHeader.SizeOfImage except ValueError: pass if not size_to_read: debug.error("You must specify --SIZE") kernel_space = tasks.find_space(addr_space, all_tasks, base_address) if not kernel_space: debug.error("Cannot read supplied address") data = kernel_space.zread(base_address, size_to_read) apis = self.enum_apis(all_mods) addr_space = kernel_space else: # In process mode, we find the process by PID task = None for atask in all_tasks: if atask.UniqueProcessId == self._config.PID: task = atask break if not task: debug.error("You must supply an active PID") task_space = task.get_process_address_space() if not task_space: debug.error("Cannot acquire process AS") all_mods = list(task.get_load_modules()) # PEB is paged or no DLLs loaded if not all_mods: debug.error("Cannot load DLLs in process AS") # If an address is supplied with a size, try to get # the size from the vad node. If neither are supplied, # assume we should carve the main process executable. if self._config.BASE: base_address = self._config.BASE size_to_read = self._config.SIZE if not size_to_read: for vad in task.VadRoot.traverse(): if base_address >= vad.Start and base_address <= vad.End: size_to_read = vad.Length if not size_to_read: debug.error("You must specify --SIZE") else: # Its OK to blindly take the 0th element because the # executable is always the first module to load. base_address = all_mods[0].DllBase size_to_read = all_mods[0].SizeOfImage data = task_space.zread(base_address, size_to_read) apis = self.enum_apis(all_mods) addr_space = task_space # This is a dictionary of confirmed API calls. calls_imported = dict( (iat, call) for (_, iat, call) in self.call_scan(addr_space, base_address, data) if call in apis) # Scan forward self._vicinity_scan(addr_space, calls_imported, apis, base_address, len(data), forward=True) # Scan reverse self._vicinity_scan(addr_space, calls_imported, apis, base_address, len(data), forward=False) for iat, call in sorted(calls_imported.items()): yield iat, call, apis[call][0], apis[call][1]
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