def get_hooked_tables(self, addr_space): """This function finds SSDTs in an address space, checks if there are any hooked functions in the SSDTs, and returns a dictionary where SSDT base addresses are the keys and the values are lists of hooked function names. @param addr_space: a kernel address space. """ # Names of the legit executive modules for SSDT tables executive_modules = [ # SSDT 0 ["ntoskrnl.exe", "ntkrnlpa.exe", "ntkrnlmp.exe", "ntkrpamp.exe"], # SSDT 1 ["win32k.sys"], # SSDT 2 ["spud.sys"], # SSDT 3 [] ] syscalls = addr_space.profile.syscalls hooked_tables = {} for info in ssdt.SSDT(self._config).calculate(): idx, table, n, vm, mods, mod_addrs = info # This is straight out of ssdt.py. Too bad there's no better way # to not duplicate code? for i in range(n): if self.bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs # relative to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module(mods, mod_addrs, syscall_addr) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" if str(syscall_modname).lower() not in executive_modules[idx]: fields = (i, syscall_name, syscall_addr, syscall_modname) if table in hooked_tables: hooked_tables[table].append(fields) else: hooked_tables[table] = [(fields)] return hooked_tables
def execute(self, config): addr_space = utils.load_as(config) syscalls = addr_space.profile.syscalls bits32 = addr_space.profile.metadata.get('memory_model', '32bit') == '32bit' data = SSDTS.SSDT(config).calculate() sdtObjectList = datastructs.rootType() # Print out the entries for each table for idx, table, n, vm, mods, mod_addrs in data: sdtObject = sdtObjectList.SSDTs.SSDT.add() sdtObject.VirtAddr = table sdtEntries = sdtObject.SSDTEntries sdtEntries.count = n for i in range(n): if bits32: # These are absolute function addresses in kernel memory. syscall_addr = obj.Object('address', table + (i * 4), vm).v() else: # These must be signed long for x64 because they are RVAs relative # to the base of the table and can be negative. offset = obj.Object('long', table + (i * 4), vm).v() # The offset is the top 20 bits of the 32 bit number. syscall_addr = table + (offset >> 4) try: syscall_name = syscalls[idx][i] except IndexError: syscall_name = "UNKNOWN" syscall_mod = tasks.find_module( mods, mod_addrs, addr_space.address_mask(syscall_addr)) if syscall_mod: syscall_modname = syscall_mod.BaseDllName else: syscall_modname = "UNKNOWN" sdtEntry = sdtEntries.SSDTEntry.add() sdtEntry.FunctionName = adutils.SmartUnicode(syscall_name) sdtEntry.ModuleName = adutils.SmartUnicode(syscall_modname) sdtEntry.VirtAddr = int(syscall_addr) sdtsfile = open(config.OUTPUT_PATH + "sdts.xml", "w") #sdtsfile.write(sdtObjectList.SerializeToString()) sdtsfile.write(proto2xml(sdtObjectList, indent=0)) logging.debug("Completed exporting the sdts on the system")