diff --git a/volatility/plugins/malware/timers.py b/volatility/plugins/malware/timers.py index 8829ae08c..5b5977cae 100644 --- a/volatility/plugins/malware/timers.py +++ b/volatility/plugins/malware/timers.py @@ -28,15 +28,20 @@ import volatility.plugins.overlays.windows.win8_kdbg as win8_kdbg from volatility.renderers import TreeGrid from volatility.renderers.basic import Address +import struct #-------------------------------------------------------------------------------- # vtypes #-------------------------------------------------------------------------------- -# This type is defined in Win2K3SP0x86 and VistaSP2x86, but -# it applies to many other profiles in which it is not defined -# in the public PDBs. -timer_types = { +# These times are defined in most Windows versions, but not all. They are applied +# as an overlay only on Windows versions that require them. +timer_types_64 = { + '_KTIMER_TABLE_ENTRY' : [ 0x18, { + 'Entry' : [ 0x0, ['_LIST_ENTRY']], + 'Time' : [ 0x10, ['_ULARGE_INTEGER']], + }]} +timer_types_32 = { '_KTIMER_TABLE_ENTRY' : [ 0x10, { 'Entry' : [ 0x0, ['_LIST_ENTRY']], 'Time' : [ 0x8, ['_ULARGE_INTEGER']], @@ -93,8 +98,14 @@ class TimerVTypes(obj.ProfileModification): before = ['WindowsOverlay'] conditions = {'os': lambda x: x == 'windows'} def modification(self, profile): - if profile.metadata.get("memory_model", "32bit") == "32bit": - profile.vtypes.update(timer_types) + # Apply our extra definitions only on Windows versions which require it. + version = (profile.metadata.get('major', 0), + profile.metadata.get('minor', 0)) + if version < (6, 1): + if profile.metadata.get("memory_model", "32bit") == "32bit": + profile.vtypes.update(timer_types_32) + else: + profile.vtypes.update(timer_types_64) profile.object_classes.update({'_KTIMER': _KTIMER}) #-------------------------------------------------------------------------------- @@ -129,7 +140,7 @@ def find_list_head(self, nt_mod, func, sig): func_addr = func_rva + nt_mod.DllBase # Read enough of the function prolog - data = nt_mod.obj_vm.zread(func_addr, 200) + data = nt_mod.obj_vm.zread(func_addr, 300) # Scan for the byte signature n = data.find(sig) @@ -138,6 +149,16 @@ def find_list_head(self, nt_mod, func, sig): return obj.Object('address', func_addr + n + len(sig), nt_mod.obj_vm) + def find_list_head_offset(self, nt_mod, func, sig): + offset = self.find_list_head(nt_mod, func, sig) + if offset == None: + return None + + ptr = nt_mod.obj_vm.zread( int(offset.obj_offset), 4 ) + ptr = struct.unpack("I", ptr)[0] + + return ptr + int(offset.obj_offset) + 4 + def calculate(self): addr_space = utils.load_as(self._config) @@ -190,9 +211,19 @@ def calculate(self): if self._config.LISTHEAD: KiTimerTableListHead = self._config.LISTHEAD else: - KiTimerTableListHead = self.find_list_head(modlist[0], - "KeCancelTimer", - "\xC1\xE7\x04\x81\xC7") + if addr_space.profile.metadata.get("memory_model") == "32bit": + sigData = [ (False, "KeCancelTimer", "\xC1\xE7\x04\x81\xC7"), + (True, "KeUpdateSystemTime", "\x48\xB9\x00\x00\x00\x00\x80\xF7\xFF\xFF\x4C\x8D\x1D") ] + else: + sigData = [ (True, "KeCancelTimer", "\x48\x8D\x4C\x6D\x00\x48\x8D\x05"), + (True, "KeUpdateSystemTime", "\x48\xB9\x00\x00\x00\x00\x80\xF7\xFF\xFF\x4C\x8D\x1D") ] + for sig in sigData: + if sig[0]: + KiTimerTableListHead = self.find_list_head_offset(modlist[0], sig[1], sig[2]) + else: + KiTimerTableListHead = self.find_list_head(modlist[0], sig[1], sig[2]) + if KiTimerTableListHead: + break if not KiTimerTableListHead: debug.warning("Cannot find KiTimerTableListHead") @@ -222,9 +253,10 @@ def calculate(self): 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 + # We would like to ignore timers without DPCs, but validating the DPC is difficult on + # certain Windows versions. + #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))