The Shadow System Service Dispatch Table can be hooked into much like the IDT and the SSDT. The SSDT for the Windows Kernel, and the Shadow SSDT is designed for the Windows subsystem (win32k.sys). The SSDT and the Shadow SSDT both use the SST (System Service Table) data structure, which is part of a another data structure called the SDT (Service Descriptor Table).
The System Service Table takes the following format as a data structure:
The SSDT as said before, is a array of function pointers to important system service routines. This true for the Shadow SSDT too. We can view these two tables in WinDbg, using the dps command and the name of the associated table.
Here’s the Service Table used by the System Service Dispatch Table, this the array of function pointers to kernel routines.
Again, we can check the Shadow System Service Dispatch Table, and gather similar information. You can see the routines are all related to the Graphics Device Interface (GDI).
The Argument Table is the System Service Parameter Table (SSPT), which is used to hold all the arguments for the routines within the dispatch tables. In fact, as a side note, with OOP languages like C++, you can create a dispatch table or the compiler will create a Virtual Function Table if you create class objects which use Virtual Functions. Each virtual function call is dispatched through the vTable.
Threads contain a pointer to either the System Service Table data structure or the Shadow System Service Table data structures, depending if they require the graphics routines to be called. Using the _KTHREAD data structure we can find the pointer to the table.
You can use the !for_each_thread extension with a .echo command to print ServiceTable field of the _KTHREAD data structure for the active threads running on the system. Suspicious threads will contain unknown tables. This is a normal thread:
Use the dps command on any strange table, and then use the dds with the entries to find more information. Here’s an example from my normal thread:
The dds command dumps referenced memory with symbols, whereas, the dps command dumps pointers with symbol information. All the WinDbg command are fully documented within the WinDbg help section.
Another method is to check mismatched memory ranges in loaded modules, using the !chkimg extension with the -d parameter. This parameter searches the module address ranges for any mismatched regions, and then dumps these with the number of bytes, and the expected and found range.
I’ve taken a example from the WinDbg documentation, and will explain each part of the output.
The yellow highlighting shows the address range: start and end. The underling of the 2 bytes indicates the size of range, with the module name and function name with offset to start of the range. The brackets indicate the number of bytes since the last error.
The second line used with the red box, shows the expected byte values and then the found byte values associated with the image. The address range was greater than 8 bytes, then the byte values may be omitted to the first 8 bytes.
You can even use the !for_each_module extension with the !chkimg extension to use the extension on very loaded module in the system. The following format is used:
!for_each_module !chkimg @#ModuleName