Kernel Forensics and Rootkits

Presenter Notes


Kernel Modules

Kernel Drivers

Evasion Techniques

IDA and Modules




Presenter Notes


Recall Malware wants to hide itself.

Kernel modules allow malware to hide from PsActiveProcess

Also ability to

  • Manipulate call tables
  • Hook functions
  • overwrite metadata structures / pool tags, etc

Presenter Notes


Doubly linked list of KLDR_DATA_TABLE_ENTRY structure in a _LIST_ENTRY.

Metadata about each kernel module

  • Base address

  • Size

  • Full path on disk

Rootkits can overwrite this metadata

Presenter Notes


>>> dt("_KDDEBUGGER_DATA64")
 '_KDDEBUGGER_DATA64' (832 bytes)
0x0   : Header                         ['_DBGKD_DEBUG_DATA_HEADER64']
0x18  : KernBase                       ['unsigned long long']
0x20  : BreakpointWithStatus           ['unsigned long long']
0x28  : SavedContext                   ['unsigned long long']
0x30  : ThCallbackStack                ['unsigned short']
0x32  : NextCallback                   ['unsigned short']
0x34  : FramePointer                   ['unsigned short']
0x38  : KiCallUserMode                 ['unsigned long long']
0x40  : KeUserCallbackDispatcher       ['unsigned long long']
0x48  : PsLoadedModuleList             ['pointer', ['_LIST_ENTRY']]
0x50  : PsActiveProcessHead            ['pointer', ['_LIST_ENTRY']]
0x58  : PspCidTable                    ['pointer', ['pointer', ['_PSP_CID_TABLE']]]

_KDDEBUGGER_DATA64 -> PsLoadedModuleList

Presenter Notes


typedef struct _KLDR_DATA_TABLE_ENTRY 
    LIST_ENTRY InLoadOrderLinks;
    PVOID ExceptionTable;
    ULONG ExceptionTableSize;
    // ULONG padding on IA64
    PVOID GpValue;
    PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    ULONG Flags;
    USHORT LoadCount;
    USHORT __Unused5;
    PVOID SectionPointer;
    ULONG CheckSum;
    // ULONG padding on IA64
    PVOID LoadedImports;
    PVOID PatchInformation;

Presenter Notes

Other sources

PE header not needed after OS loader.... Rootkits can 0 over all of it.

Main code must remain in memory

Threads can point to addresses within a module

System Service Dispatcher Table (SSDT) can be hooked and pointed to malicious module

Presenter Notes


Finding metadata

Presenter Notes

What to look for?

Unlinked modules

Critial Interrupts (Page fault, breakpoint, ssdt)

System APIs

  • User mode -> Kernel mode uses SSDT to resolve functions
  • Pointers can be overwritten

Signed drivers

  • 64 bit windows needs signed kernel modules

Valid names and paths




Presenter Notes

Loading Modules

Service Control Manager (SCM)

  • Loads modules by creating a SERVICE_KERNEL_DRIVER serice and starting it.
  • OSRLOADER does it this way
  • Recall malware can just use the API calls


  • Bypass SCM and use API pure.
  • Still requires registry keys


  • Cannot unload modules with this method
  • System call to SystemLoadAndCallImage

Presenter Notes

Module Loading

status = ZwSetSystemInformation(SystemLoadAndCallImage, &MyDeviceDriver, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE));

Presenter Notes

Live System

System.exe - PID 4 - Is container for Kernel threads and modules

Windows API EnumDeviceDrivers can get load address for each module.

BOOL WINAPI EnumDeviceDrivers(
  _Out_  LPVOID *lpImageBase,
  _In_   DWORD cb,
  _Out_  LPDWORD lpcbNeeded

NtQuerySystemInformation is called by EnumDeviceDrivers

NTSTATUS WINAPI NtQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength


Presenter Notes

Process Explorer

Open lower pane (^L) on System

Process Explorer Drivers

Presenter Notes

Nirsoft DriverView

Another GUI app to list kernel modules

Shows all the metadata from _KLDR_DATA_TABLE_ENTRY


Presenter Notes



  • Walk PsLoadedModuleList
  • Order in which modules were loaded


  • Pool tag scanning for MmLd tag


  • Modules recently unloaded with timestamps of when they were unloaded


  • Dump a kernel module to disk from a name or base address
  • Must have a valid PE header, which rootkits can destory

Presenter Notes


  • Walk PsLoadedModuleList

  • Order in which modules were loaded

[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 modules
Volatility Foundation Volatility Framework 2.4
Offset(V)  Name                 Base             Size File
---------- -------------------- ---------- ---------- ----
0x823fc398 ntoskrnl.exe         0x804d7000   0x1f9680 \WINDOWS\system32\ntkrnlpa.exe
0x823fc330 hal.dll              0x806d1000    0x20380 \WINDOWS\system32\hal.dll
0x823fc2c8 kdcom.dll            0xf8b9a000     0x2000 \WINDOWS\system32\KDCOM.DLL
0x823fc258 BOOTVID.dll          0xf8aaa000     0x3000 \WINDOWS\system32\BOOTVID.dll
0x823fc1f0 ACPI.sys             0xf856b000    0x2e000 ACPI.sys
0x81f526d8 driver.sys           0xf8a32000     0x6000 \??\C:\bin\driver.sys
0x81ee42a0 kmixer.sys           0xb1564000    0x2b000 \SystemRoot\system32\drivers\kmixer.sys

Presenter Notes



Base is the PE header

Load Order

NT module is first and then the HAL (hardware abstraction layter)

Several will always start

  • Boot into safe mode and watch what modules load

Presenter Notes

Pooltag Approach with Modscan

Displayed in order when they were found, not load order.

Offset is now physical

Audits free and deallocated memory like other pool tag scanners

[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 modscan
Volatility Foundation Volatility Framework 2.4
Offset(P)          Name                 Base             Size File
------------------ -------------------- ---------- ---------- ----
0x0000000001712820 kbdclass.sys         0xf8952000     0x6000 \SystemRoot\system32\DRIVERS\kbdclass.sys
0x0000000001bdd230 Dxapi.sys            0xf813d000     0x3000 \SystemRoot\System32\drivers\Dxapi.sys
0x0000000001bdd570 Fips.SYS             0xf88aa000     0xb000 \SystemRoot\System32\Drivers\Fips.SYS
0x0000000001bdd6d0 ndisuio.sys          0xb221c000     0x4000 \SystemRoot\system32\DRIVERS\ndisuio.sys
0x0000000001bdd740 rdbss.sys            0xb248c000    0x2b000 \SystemRoot\system32\DRIVERS\rdbss.sys
0x0000000001bddcc0 afd.sys              0xb24dc000    0x22000 \SystemRoot\System32\drivers\afd.sys
0x0000000002065628 termdd.sys           0xf882a000     0xa000 \SystemRoot\system32\DRIVERS\termdd.sys
0x00000000020691f0 mouclass.sys         0xf895a000     0x6000 \SystemRoot\system32\DRIVERS\mouclass.sys
0x000000000206a628 dump_atapi.sys       0xb233c000    0x18000 \SystemRoot\System32\Drivers\dump_atapi.sys

Presenter Notes


Rootkits can change all metadata

PE and pool tags not needed by OS

Learn Volatility signatures for pool tag scanners and wreak them with a rootkit!

Presenter Notes

Unloaded modules

Kernel maintains unloaded modules for debugging purposes

Helps developers find bugs, dangling pointers, etc... prevent blue screens!

Some rootkits get in and get out!

[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 unloadedmodules
Volatility Foundation Volatility Framework 2.4
Name                 StartAddress EndAddress Time
-------------------- ------------ ---------- ----
Sfloppy.SYS          0x00f8393000 0xf8396000 2015-04-04 00:08:35
Cdaudio.SYS          0x00f89b2000 0xf89b7000 2015-04-04 00:08:35
DumpDrv.SYS          0x00f8b46000 0xf8b49000 2015-04-04 00:08:35
splitter.sys         0x00f8bb2000 0xf8bb4000 2015-04-04 00:09:19
aec.sys              0x00b1f94000 0xb1fb7000 2015-04-04 00:09:19
swmidi.sys           0x00f821d000 0xf822b000 2015-04-04 00:09:19
DMusic.sys           0x00f820d000 0xf821a000 2015-04-04 00:09:19
drmkaud.sys          0x00f8c78000 0xf8c79000 2015-04-04 00:09:19

Presenter Notes

Extracting Kernel Modules

Moddump - Dump a kernel driver to an executable file sample

  -n NAME, --name=NAME  Operate on these process names (regex)
  -D DUMP_DIR, --dump-dir=DUMP_DIR
                        Directory in which to dump executable files
  -u, --unsafe          Bypasses certain sanity checks when creating image
  -m, --memory          Carve as a memory sample rather than exe/disk
  -x, --fix             Modify the image base of the dump to the im-memory
                        base address
  -r REGEX, --regex=REGEX
                        Dump modules matching REGEX
  -i, --ignore-case     Ignore case in pattern match
  -b BASE, --base=BASE  Dump driver with BASE address (in hex)

Presenter Notes

Full Picture

[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 modscan | grep driver.sys
Volatility Foundation Volatility Framework 2.4
0x00000000021526d8 driver.sys           0xf8a32000     0x6000 \??\C:\bin\driver.sys

[root&windows]#mkdir driverSys
/bin/mkdir: created directory `driverSys'
[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 moddump -b 0xf8a32000 -D driverSys/
Volatility Foundation Volatility Framework 2.4
Module Base Module Name          Result
----------- -------------------- ------
0x0f8a32000 driver.sys           OK: driver.f8a32000.sys

[root&driverSys]#strings -a driverSys\driver.f8a32000.sys
!This program cannot be run in DOS mode.
DriverUnload ...
Ipr_Write ...
Hide succeeded on %d!
Hide failed on %d
Ipr_Nil ...
DriverEntry ...

Presenter Notes

With IDA

IDA requires a proper ImageBase address to display function calls, jumps and strings...

Use ImageBase from one of the mod plugins.

Can clean up with a hex editor or with a python script

[root&driverSys]#mv driver.f8a32000.sys driver.sys
[root&driverSys]#pip install pefile 
#!/usr/bin/env python
import pefile
pe = pefile.PE("driver.sys", fast_load = True)
pe.OPTIONAL_HEADER.ImageBase = 0xf8a32000


Also use impscan to generate IAT labels for IDA!

Presenter Notes


Scan for calls to imported functions

Need to give

- b <base address>

- s <size of memory>

- output=idc

- output-file=<filename>

Presenter Notes

[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 impscan -b 0xf8a32000 -s 0x6000 --output=idc  --output-file=driver.idc
[root&windows]#cat driver.idc
MakeName(0xF8A34004, "RtlInitUnicodeString");
MakeName(0xF8A34008, "DbgPrint");
MakeName(0xF8A3400C, "IofCompleteRequest");
MakeName(0xF8A34010, "IoCreateDevice");
MakeName(0xF8A34014, "IoCreateSymbolicLink");
MakeName(0xF8A34018, "IoDeleteDevice");
MakeName(0xF8A3401C, "IoDeleteSymbolicLink");
MakeName(0xF8A34020, "PsGetCurrentProcess");

Presenter Notes


Open driver.sys as you would a binary or dll

ImageBase address was adjusted by pefile

Run or add our IDC file


This will add new Names to the names window

MakeDword(0xF8A34020); MakeName(0xF8A34020, "PsGetCurrentProcess");


Presenter Notes

Driver Objects

When a module loads it creates KLDR_DATA_TABLE_ENTRY and a _DRIVER_OBJECT.

Drivers contain a pointer to a list of handler functions

Helpful to find destroyed or unlinked metadata structures

Driver Communication

User mode talks to kernel drivers with I/O Request Pakcets (IRP).

IRP includes the desired operation (create, read, write, etc) and buffers for data that will be operated on by the driver.

This table is known as the IRP Function or Major Function table.

The table contains 28 pointers.

Presenter Notes

More IRP

Driver objects contain

  • Base address of kernel modules

  • Name of the driver

  • Table of IRP

Presenter Notes


>>> dt("_DRIVER_OBJECT")
 '_DRIVER_OBJECT' (168 bytes)
0x0   : Type                           ['short']
0x2   : Size                           ['short']
0x4   : DeviceObject                   ['pointer', ['_DEVICE_OBJECT']]     #first device created by the driver or a linked list. 
0x8   : Flags                          ['unsigned long']
0xc   : DriverStart                    ['pointer', ['void']]               #kernel modules base addr
0x10  : DriverSize                     ['unsigned long']                   #kernel module size
0x14  : DriverSection                  ['pointer', ['void']]
0x18  : DriverExtension                ['pointer', ['_DRIVER_EXTENSION']]  #registry path
0x1c  : DriverName                     ['_UNICODE_STRING']                 #name
0x24  : HardwareDatabase               ['pointer', ['_UNICODE_STRING']]
0x28  : FastIoDispatch                 ['pointer', ['_FAST_IO_DISPATCH']]
0x2c  : DriverInit                     ['pointer', ['void']]                #init()
0x30  : DriverStartIo                  ['pointer', ['void']]
0x34  : DriverUnload                   ['pointer', ['void']]                #unload function 
0x38  : MajorFunction                  ['array', 28, ['pointer', ['void']]] #IRP Function Table

Presenter Notes

IRP Table

Shows what operations a driver can handle

handled by a function in the owning driver or forwarded to another

Presenter Notes


Pool tag scanner for driver objects.

Shows physical offset of _DRIVER_OBJECT and start address of the driver in kernel memory.

  • Should be same as from modscan or modules plugins.

If KLDR_DATA_TABLE_ENTRY is overwritten, this may still be intact.

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 driverscan
Volatility Foundation Volatility Framework 2.4
Offset(P)              #Ptr     #Hnd Start            Size Service Key          Name         Driver Name
------------------ -------- -------- ---------- ---------- -------------------- ------------ -----------
0x000000003dc29398        2        0 0x95aa9000     0x6000 mmdrv                mmdrv        \Driver\mmdrv
0x000000003de0b988        4        0 0x92403000    0x85000 HTTP                 HTTP         \Driver\HTTP
0x000000003e010518        2        0 0x8725c000    0x1b000 luafv                luafv        \FileSystem\luafv
0x000000003e016868        2        0 0x8728a000     0xd000 tcpipreg             tcpipreg     \Driver\tcpipreg
0x000000003e019ed0        3        0 0x95a50000    0x52000 srv                  srv          \FileSystem\srv
0x000000003e021f38        3        0 0x95a00000    0x50000 srv2                 srv2         \FileSystem\srv2
0x000000003e02f030        3        0 0x92488000    0x19000 bowser               bowser       \FileSystem\bowser

Presenter Notes


Rootkits can hook entries in a drivers IRP/Major Function table. Address of 28 pointers to functions.

Overwrite function address and hook into itself.

Rootkits like to hook

  • Network buffers
  • File I/O
  • Network connections

To discover...

  • Read 28 values in IRP table
  • Determine where reach function points and if it is malicious

Presenter Notes


Shows IRP functions for a module

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 driverirp -r tcpip
DriverName: Tcpip
DriverStart: 0x8700c000
DriverSize: 0x14c000
DriverStartIo: 0x0
   0 IRP_MJ_CREATE                        0x8701b669 tcpip.sys
   1 IRP_MJ_CREATE_NAMED_PIPE             0x828b90e5 ntoskrnl.exe
   2 IRP_MJ_CLOSE                         0x8701b669 tcpip.sys
   3 IRP_MJ_READ                          0x828b90e5 ntoskrnl.exe
   4 IRP_MJ_WRITE                         0x828b90e5 ntoskrnl.exe
   5 IRP_MJ_QUERY_INFORMATION             0x828b90e5 ntoskrnl.exe
   6 IRP_MJ_SET_INFORMATION               0x828b90e5 ntoskrnl.exe
   7 IRP_MJ_QUERY_EA                      0x828b90e5 ntoskrnl.exe
   8 IRP_MJ_SET_EA                        0x828b90e5 ntoskrnl.exe
   9 IRP_MJ_FLUSH_BUFFERS                 0x828b90e5 ntoskrnl.exe
  10 IRP_MJ_QUERY_VOLUME_INFORMATION      0x828b90e5 ntoskrnl.exe
  11 IRP_MJ_SET_VOLUME_INFORMATION        0x828b90e5 ntoskrnl.exe
  12 IRP_MJ_DIRECTORY_CONTROL             0x828b90e5 ntoskrnl.exe
  13 IRP_MJ_FILE_SYSTEM_CONTROL           0x828b90e5 ntoskrnl.exe
  14 IRP_MJ_DEVICE_CONTROL                0x87056c3d tcpip.sys
  15 IRP_MJ_INTERNAL_DEVICE_CONTROL       0x8701b669 tcpip.sys
  16 IRP_MJ_SHUTDOWN                      0x828b90e5 ntoskrnl.exe
  17 IRP_MJ_LOCK_CONTROL                  0x828b90e5 ntoskrnl.exe
  18 IRP_MJ_CLEANUP                       0x8701b669 tcpip.sys
  19 IRP_MJ_CREATE_MAILSLOT               0x828b90e5 ntoskrnl.exe
  20 IRP_MJ_QUERY_SECURITY                0x828b90e5 ntoskrnl.exe
  21 IRP_MJ_SET_SECURITY                  0x828b90e5 ntoskrnl.exe
  22 IRP_MJ_POWER                         0x828b90e5 ntoskrnl.exe
  23 IRP_MJ_SYSTEM_CONTROL                0x828b90e5 ntoskrnl.exe
  24 IRP_MJ_DEVICE_CHANGE                 0x828b90e5 ntoskrnl.exe
  25 IRP_MJ_QUERY_QUOTA                   0x828b90e5 ntoskrnl.exe
  26 IRP_MJ_SET_QUOTA                     0x828b90e5 ntoskrnl.exe
  27 IRP_MJ_PNP                           0x828b90e5 ntoskrnl.exe

Presenter Notes

Hooked function calls

Would look something like.

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 driverirp -r tcpip
DriverName: Tcpip
DriverStart: 0x8700c000
DriverSize: 0x14c000
DriverStartIo: 0x0
   0 IRP_MJ_CREATE                        0x8701b669 tcpip.sys
   1 IRP_MJ_CREATE_NAMED_PIPE             0x828b90e5 ntoskrnl.exe
   2 IRP_MJ_CLOSE                         0x8701b669 tcpip.sys
   3 IRP_MJ_READ                          0x828b90e5 ntoskrnl.exe
   4 IRP_MJ_WRITE                         0x828b90e5 ntoskrnl.exe
  14 IRP_MJ_DEVICE_CONTROL                0x89503c3d driver.sys

Presenter Notes

Stealthy Hooks

Put a hooking stub in the main driver and call/jmp into malicious code

Driverirp with --verbose will disassemble handler functions

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 driverirp -r tcpip --verbose

DriverName: Tcpip
DriverStart: 0x8700c000
DriverSize: 0x14c000
DriverStartIo: 0x0
  14 IRP_MJ_DEVICE_CONTROL                0x87056c3d tcpip.sys
0x87056c3d 8bff             MOV EDI, EDI
0x87056c3f 55               PUSH EBP
0x87056c40 8bec             MOV EBP, ESP
0x87056c42 8b4d08           MOV ECX, [EBP+0x8]
0x87056c45 33c0             XOR EAX, EAX
0x87056c47 3b0cc5e09b1087   CMP ECX, [EAX*8-0x78ef6420]
0x87056c4e 741e             JZ 0x87056c6e
0x87056c50 40               INC EAX
0x87056c51 83f805           CMP EAX, 0x5
0x87056c54 7cf1             JL 0x87056c47
0x87056c56 ff750c           PUSH DWORD [EBP+0xc]
0x87056c59 6a00             PUSH 0x0
0x87056c5b 68010000c0       PUSH DWORD 0xc0000001
0x87056c60 e8204afcff       CALL 0x8701b685
0x87056c65 b8010000c0       MOV EAX, 0xc0000001
0x87056c6a 5d               POP EBP

Presenter Notes

TDL3 Rootkit


Presenter Notes


Lots of drivers

Each with 28 IRP functions...

Have fun.

Presenter Notes

High Value Targets

File Systems



Network drivers


Presenter Notes

Device Trees

Multiple drivers can handle the same IRP.

Windows uses a stacked approach to handling I/O.

A rootkit can insert or attach to a device's stack/tree.

Allows rootkit to avoid IRP and receive a copy of it through device stack

  • \Deive\Kbdclass = keystrokes
  • \FileSystem\NTFS = files

Presenter Notes

Device Trees

The highest device in the stack gets the IRP first and lowest handles it last


  • Firewalls can be onto the stack of network connections
  • File system stacks to support encryption
  • Malware controls operations

Presenter Notes

TDL3 Stack


Presenter Notes

Device Tree Structures

>>> dt("_DEVICE_OBJECT")
 '_DEVICE_OBJECT' (184 bytes)
0x0   : Type                           ['short']
0x2   : Size                           ['unsigned short']
0x4   : ReferenceCount                 ['long']
0x8   : DriverObject                   ['pointer', ['_DRIVER_OBJECT']]  #Pointer to actual driver 
0xc   : NextDevice                     ['pointer', ['_DEVICE_OBJECT']]
0x10  : AttachedDevice                 ['pointer', ['_DEVICE_OBJECT']]  #Devices on the stack
0x14  : CurrentIrp                     ['pointer', ['_IRP']]            #IRP being processed
0x18  : Timer                          ['pointer', ['_IO_TIMER']]
0x1c  : Flags                          ['unsigned long']
0x20  : Characteristics                ['unsigned long']
0x24  : Vpb                            ['pointer', ['_VPB']]
0x28  : DeviceExtension                ['pointer', ['void']]
0x2c  : DeviceType                     ['unsigned long']                 #Type of device... FILE, NETWORK, DISK...
0x30  : StackSize                      ['unsigned char']
0x34  : Queue                          ['__unnamed_1340']
0x5c  : AlignmentRequirement           ['unsigned long']
0x60  : DeviceQueue                    ['_KDEVICE_QUEUE']
0x74  : Dpc                            ['_KDPC']
0x94  : ActiveThreadCount              ['unsigned long']
0x98  : SecurityDescriptor             ['pointer', ['void']]
0x9c  : DeviceLock                     ['_KEVENT']
0xac  : SectorSize                     ['unsigned short']
0xae  : Spare1                         ['unsigned short']
0xb0  : DeviceObjectExtension          ['pointer', ['_DEVOBJ_EXTENSION']] #Custom data structs 
0xb4  : Reserved                       ['pointer', ['void']]

Presenter Notes

Auditing Device Trees

Device tree

  • Outer edge drivers (DRV)

  • Devices (DEV)

  • Attached devices (ATT)

Focus on critical devices... network, keyboard, disk..

Presenter Notes


[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 devicetree 
DRV 0x3f294950 \Driver\Tcpip
---| DEV 0x84caf648 eQoS FILE_DEVICE_NETWORK
---| DEV 0x84cb6920 WfpAle FILE_DEVICE_NETWORK
---| DEV 0x84c94560  FILE_DEVICE_NETWORK

DRV 0x3fc221b8 \Driver\volmgr
---| DEV 0x84d11e20 HarddiskVolume1 FILE_DEVICE_DISK
------| ATT 0x84d115e0  - \Driver\fvevol FILE_DEVICE_DISK
---------| ATT 0x84d04db8  - \Driver\rdyboost FILE_DEVICE_DISK
------------| ATT 0x84d04358  - \Driver\volsnap FILE_DEVICE_DISK
---| DEV 0x84ac6638 VolMgrControl FILE_DEVICE_NETWORK

Presenter Notes


System Service Descriptor Table

  • Pointers to kernel mode functions

Interrupts to kernel mode

KiSystemService looks up addresses in SSDT once in Kernel mode.

Order and number of functions differ across OS and SP.

More than one call table on systems..

Primary and Secondary/shadow tables

Shadow SSDT has GUI functions from win32k

Primary is ntoskrnl.exe

Presenter Notes



Presenter Notes


0x0   : Descriptors                    ['array', 4, ['_SERVICE_DESCRIPTOR_ENTRY']]

0x0   : KiServiceTable                 ['pointer', ['void']]
0x4   : CounterBaseTable               ['pointer', ['unsigned long']]
0x8   : ServiceLimit                   ['unsigned long']
0xc   : ArgumentTable                  ['pointer', ['unsigned char']]

Presenter Notes

SSDT Enumeration

32 bit os uses _ETHREAD.Tcb.ServiceTable

64 bit os uses nt!KeAddSystemServiceTable and get RVA for the KeServiceDescriptorTable

SSDT plugin

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 ssdt
Volatility Foundation Volatility Framework 2.4
[x86] Gathering all referenced SSDTs from KTHREADs...
Finding appropriate address space for tables...
SSDT[0] at 8288243c with 401 entries
  Entry 0x0000: 0x82a7df97 (NtAcceptConnectPort) owned by ntoskrnl.exe
  Entry 0x0001: 0x828c5855 (NtAccessCheck) owned by ntoskrnl.exe
  Entry 0x0002: 0x82a0dd35 (NtAccessCheckAndAuditAlarm) owned by ntoskrnl.exe
  Entry 0x0003: 0x82829897 (NtAccessCheckByType) owned by ntoskrnl.exe
  Entry 0x0004: 0x82a7f86d (NtAccessCheckByTypeAndAuditAlarm) owned by ntoskrnl.exe
  Entry 0x0005: 0x82902112 (NtAccessCheckByTypeResultList) owned by ntoskrnl.exe
  Entry 0x0006: 0x82af0127 (NtAccessCheckByTypeResultListAndAuditAlarm) owned by ntoskrnl.exe
  Entry 0x0007: 0x82af0170 (NtAccessCheckByTypeResultListAndAuditAlarmByHandle) owned by ntoskrnl.exe
  Entry 0x0008: 0x82a02551 (NtAddAtom) owned by ntoskrnl.exe
  Entry 0x0009: 0x82b09992 (NtAddBootEntry) owned by ntoskrnl.exe
  Entry 0x000a: 0x82b0abe7 (NtAddDriverEntry) owned by ntoskrnl.exe
  Entry 0x000b: 0x829f8d29 (NtAdjustGroupsToken) owned by ntoskrnl.exe
  Entry 0x000c: 0x82a89eab (NtAdjustPrivilegesToken) owned by ntoskrnl.exe
  Entry 0x000d: 0x82ae2df3 (NtAlertResumeThread) owned by ntoskrnl.exe
  Entry 0x000e: 0x82a35cb7 (NtAlertThread) owned by ntoskrnl.exe

Presenter Notes

SSDT Enumeration

0x31ff (12799) entries on my image

SSDT[0] = First descreitpr table... native NT

SSDT[1] = GUI subsystems

SSDT[2-3] = Optional... typically server tables such as IIS.

Presenter Notes

SSDT Attacks

Pointer Replacement

  • Replace individual function pointers
  • GUI -> win32k.sys
  • Native NT -> ntoskrnl.exe

Inline Hooking

  • Hide a stub in a module and call into it
  • Mov eax, value; jmp eax;

Table Duplication

  • _EHTREAD.Tcb.ServiceTable points to the SSDT a thread uses
    • Overwrite it on x86 systems

Presenter Notes

SSDT is Error Prone

New security mitigations and architecture impose risk for SSDT hooking

Patchguard / Kernel Patch Protection on x64

Kernel monitors key resources used by the kernel and if code is modified the system will shut down.

Prevents code patching and protects the kernel.


  • SSDT

  • Interrupt Descriptor Table

  • Global Descriptor Table

Presenter Notes

Other disadvantages

System Call tables are not a per-CPU strucutre

Undocumented API functions

Duplicate entries from third party drivers and unpredictable behavior

Presenter Notes

Kernel Threads

System.exe | PID 4 owns Kernel theads.

System threads are easily indentified

  • _ETHREAD.SystemThread == 1
  • Owning Process is 4 / System.exe

PsCreateSystemThread is used after allocating code into a kernel pool to start a thread.

NTSTATUS PsCreateSystemThread(
  _Out_      PHANDLE            ThreadHandle,
  _In_       ULONG              DesiredAccess,
  _In_opt_   POBJECT_ATTRIBUTES ObjectAttributes,
  _In_opt_   HANDLE             ProcessHandle,
  _Out_opt_  PCLIENT_ID         ClientId,
  _In_       PKSTART_ROUTINE    StartRoutine,
  _In_opt_   PVOID              StartContext

Presenter Notes

Orphan Threads

Detached or hidden threads

Threads plugin walks _LIST_ENTRY for threads of loaded modules

Checks startAddress for each system thad and matches it to the owning driver.

If an Orphan Thread exists

  • OrphanThread Tag and an UNKNOWN start address
  • Start address if of the function, not PE space.

Rootkits can adjust startAddress...

Presenter Notes

Kernel Callbacks

API Hooking Method to allow a function to execute given some condition

Register a function to be called by the system! An event triggers this function to get called.

Work on x64, are documented, are safe for multicore machines and common. . . Attackers wet dream!

What to callback on?

  • Process Creation
  • Thread Creation
  • Image Load
  • System Shutdown
  • File System Registration
  • Debug Message
  • Registry Modification
  • Plug and play
  • BugChecks

Presenter Notes

API Functions

Windows API provides a way to register callbacks


PsSetCreateProcessNotifyRoutine adds a callback for whenever a process is created or deleted.

NTSTATUS PsSetCreateProcessNotifyRoutine(
  _In_  PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,   #entry point
  _In_  BOOLEAN                        Remove           #remove to add

Typically used with security software to monitor new processes

PspCreateProcessNotifyRoutine is a linked list of pointers that have a callback

  • Erase it with rootkit!

Presenter Notes

Callbacks in Memory


Shows address of the function that is invoked when an event occurs.

Module column shows kernel module that the function resides in

[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 callbacks
Volatility Foundation Volatility Framework 2.4
Type                                 Callback   Module               Details
------------------------------------ ---------- -------------------- -------
GenericKernelCallback                0x925421d9 peauth.sys           -
EventCategoryDeviceInterfaceChange   0x9134dbec win32k.sys           Win32k
EventCategoryTargetDeviceChange      0x828f5764 ntoskrnl.exe         mouclass
EventCategoryDeviceInterfaceChange   0x9134dbec win32k.sys           Win32k
EventCategoryDeviceInterfaceChange   0x9134dbec win32k.sys           Win32k
EventCategoryTargetDeviceChange      0x914ae629 win32k.sys           Win32k
EventCategoryTargetDeviceChange      0x914ae629 win32k.sys           Win32k
EventCategoryTargetDeviceChange      0x914ae629 win32k.sys           Win32k
EventCategoryDeviceInterfaceChange   0x8b89a74f dxgkrnl.sys          DXGKrnl
EventCategoryTargetDeviceChange      0x8b8e3c26 dxgkrnl.sys          DXGKrnl

Presenter Notes

Malicious Callbacks in Memory

Look for UNKNOWN modules and strange names

LoadImage is commonly infected.

  • TLD4, Mebroot, BlackEnergy,

Know API functions

Load Image

  • PspLoadImageNotifyRoutine, PspCreateProcessNotifyRoutine, PspCreateThreadNotifyRoutine

Presenter Notes

Kernel Timers


Rootkits set timers to receive notifications when time elapses.

  • Did X get resolved?
  • Did Y occur?

Timers can set up Deferred Procedure Calls (DPC) in a _KTIMER strucutre.

>>> dt("_KTIMER")
 '_KTIMER' (40 bytes)
0x0   : Header                         ['_DISPATCHER_HEADER']
0x10  : DueTime                        ['_ULARGE_INTEGER']
0x18  : TimerListEntry                 ['_LIST_ENTRY']
0x20  : Dpc                            ['pointer', ['_KDPC']]
0x24  : Period                         ['unsigned long']

Presenter Notes

Finding Kernel Timers

Timers - Print kernel timers and associated module DPCs

Shows module that owns the timer

[root&windows]#volatility -f zeroaccess2.vmem timers
Volatility Foundation Volatility Framework 2.1_alpha
Offset DueTime Period(ms) Signaled Routine Module
0x805598e0 0x00000084:0xce8b961c 1000 Yes 0x80523dee ntoskrnl.exe
0x820a1e08 0x00000084:0xdf3c0c1c 30000 Yes 0xb2d2a385 afd.sys
0x81ebf0b8 0x00000084:0xce951f84 0 - 0xf89c23f0 TDI.SYS
0x81dbeb78 0x00000131:0x2e896402 0 - 0xf83faf6f NDIS.sys

Presenter Notes

Extracting PE out of memory

All of these plugins give an address to a function...

Search backwards in memory for PE header!

>>> start = 0x81b99db0 - 0x100000
>>> end = 0x81b93690
>>> while start < end:
... if addrspace().zread(start, 4) == "MZ\x90\x00":
... print hex(start)
... break
... start += 1

If one is found, try extracting it with moddump and play with it in IDA!

  • Fix base address
  • Recover IAT

Presenter Notes


Presenter Notes