Skip to content
This repository was archived by the owner on May 16, 2025. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions volatility/plugins/malware/timers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']],
Expand Down Expand Up @@ -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})

#--------------------------------------------------------------------------------
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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))
Expand Down