Kernel Modules
Kernel Drivers
Evasion Techniques
IDA and Modules
SSDT
Hooking
Callbacks
Recall Malware wants to hide itself.
Kernel modules allow malware to hide from PsActiveProcess
Also ability to
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
>>> 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
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;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT __Unused5;
PVOID SectionPointer;
ULONG CheckSum;
// ULONG padding on IA64
PVOID LoadedImports;
PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
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
Unlinked modules
Critial Interrupts (Page fault, breakpoint, ssdt)
System APIs
Signed drivers
Valid names and paths
Callbacks
Devices
Signatures
Service Control Manager (SCM)
NtLoadDriver
NtSetSystemInformation
status = ZwSetSystemInformation(SystemLoadAndCallImage, &MyDeviceDriver, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE));
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
);
_LIST_ENTRY of _KLDR_DATA_TABLE_ENTRY structures
Open lower pane (^L) on System
Another GUI app to list kernel modules
Shows all the metadata from _KLDR_DATA_TABLE_ENTRY
Modules
Modscan
Unloadedmodules
Moddump
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
[snip]
0x81f526d8 driver.sys 0xf8a32000 0x6000 \??\C:\bin\driver.sys
0x81ee42a0 kmixer.sys 0xb1564000 0x2b000 \SystemRoot\system32\drivers\kmixer.sys
Offset (V) is the KLDR_DATA_TABLE_ENTRY
Base is the PE header
NT module is first and then the HAL (hardware abstraction layter)
Several will always start
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
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!
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
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)
[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.
Rich
.text
h.rdata
H.data
INIT
.reloc
QhH3
Rh^3
DriverUnload ...
Ipr_Write ...
Hide succeeded on %d!
Hide failed on %d
Ipr_Nil ...
DriverEntry ...
RSDS
C:\Users\Topher\forIII\dkom\driver.pdb
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
[root&driverSys]#cat cleanDriver.py
#!/usr/bin/env python
import pefile
pe = pefile.PE("driver.sys", fast_load = True)
pe.OPTIONAL_HEADER.ImageBase = 0xf8a32000
pe.write("driver.sys")
[root&driverSys]#./cleanDriver.py
Also use impscan to generate IAT labels for IDA!
Scan for calls to imported functions
Need to give
- b <base address>
- s <size of memory>
- output=idc
- output-file=<filename>
[root&windows]#volatility -f Lab2.vmem --profile=WinXPSP2x86 impscan -b 0xf8a32000 -s 0x6000 --output=idc --output-file=driver.idc
[root&windows]#cat driver.idc
MakeDword(0xF8A34004);
MakeName(0xF8A34004, "RtlInitUnicodeString");
MakeDword(0xF8A34008);
MakeName(0xF8A34008, "DbgPrint");
MakeDword(0xF8A3400C);
MakeName(0xF8A3400C, "IofCompleteRequest");
MakeDword(0xF8A34010);
MakeName(0xF8A34010, "IoCreateDevice");
MakeDword(0xF8A34014);
MakeName(0xF8A34014, "IoCreateSymbolicLink");
MakeDword(0xF8A34018);
MakeName(0xF8A34018, "IoDeleteDevice");
MakeDword(0xF8A3401C);
MakeName(0xF8A3401C, "IoDeleteSymbolicLink");
MakeDword(0xF8A34020);
MakeName(0xF8A34020, "PsGetCurrentProcess");
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");
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
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.
Driver objects contain
Base address of kernel modules
Name of the driver
Table of IRP
>>> 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
Shows what operations a driver can handle
handled by a function in the owning driver or forwarded to another
Pool tag scanner for driver objects.
Shows physical offset of _DRIVER_OBJECT and start address of the driver in kernel memory.
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
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
To discover...
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
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
[snip]
14 IRP_MJ_DEVICE_CONTROL 0x89503c3d driver.sys
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
[snip]
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
Lots of drivers
Each with 28 IRP functions...
Have fun.
File Systems
IRP_MJ_READ
IRP_MJ_WRITE
Network drivers
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
The highest device in the stack gets the IRP first and lowest handles it last
Examples
>>> 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']]
Device tree
Outer edge drivers (DRV)
Devices (DEV)
Attached devices (ATT)
Focus on critical devices... network, keyboard, disk..
[root&windows]#volatility -f Win7.bin --profile=Win7SP0x86 devicetree
DRV 0x3f294950 \Driver\Tcpip
---| DEV 0x84caf648 eQoS FILE_DEVICE_NETWORK
---| DEV 0x84ca62f0 IPSECDOSP FILE_DEVICE_NETWORK
---| DEV 0x84cb6920 WfpAle FILE_DEVICE_NETWORK
---| DEV 0x84cb7208 WFP FILE_DEVICE_NETWORK
---| DEV 0x84cb5810 NXTIPSEC 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
System Service Descriptor Table
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
>>> dt("_SERVICE_DESCRIPTOR_TABLE")
'_SERVICE_DESCRIPTOR_TABLE' (64 bytes)
0x0 : Descriptors ['array', 4, ['_SERVICE_DESCRIPTOR_ENTRY']]
>>> dt("_SERVICE_DESCRIPTOR_ENTRY")
'_SERVICE_DESCRIPTOR_ENTRY' (16 bytes)
0x0 : KiServiceTable ['pointer', ['void']]
0x4 : CounterBaseTable ['pointer', ['unsigned long']]
0x8 : ServiceLimit ['unsigned long']
0xc : ArgumentTable ['pointer', ['unsigned char']]
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
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.
Pointer Replacement
Inline Hooking
Table Duplication
New security mitigations and architecture impose risk for SSDT hooking
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.
Monitors
SSDT
Interrupt Descriptor Table
Global Descriptor Table
System Call tables are not a per-CPU strucutre
Undocumented API functions
Duplicate entries from third party drivers and unpredictable behavior
System.exe | PID 4 owns Kernel theads.
System threads are easily indentified
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
);
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
Rootkits can adjust startAddress...
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!
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
Callbacks
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
Look for UNKNOWN modules and strange names
LoadImage is commonly infected.
Know API functions
Load Image
KeInitalizeTimer
Rootkits set timers to receive notifications when time elapses.
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']
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
[snip]
0x81dbeb78 0x00000131:0x2e896402 0 - 0xf83faf6f NDIS.sys
All of these plugins give an address to a function...
Search backwards in memory for PE header!
volshell
>>> 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!
Table of Contents | t |
---|---|
Exposé | ESC |
Full screen slides | e |
Presenter View | p |
Source Files | s |
Slide Numbers | n |
Toggle screen blanking | b |
Show/hide slide context | c |
Notes | 2 |
Help | h |