CreateFileA
at ❶. The filename pushed onto the stack is stored in EDI at ❷. (Not pictured is the EDI being loaded with the string \\.\FileWriterDevice
, which is the name of the object created by the driver for the user-space application to access.)The driver object is stored at address 0x827e3698
at ❶. Once we have the address for the driver object, we can look at its structure using the dt
command, as shown in .
u
command. In this case they do, but if they did not, it could mean that we made an error in the address calculation.ZwCreateFile
and ZwWriteFile
to write to a file from kernel space.The Windows kernel uses a UNICODE_STRING
structure, which is different from the wide character strings in user space. The RtlInitUnicodeString
function at ❶ is used to create kernel strings. The second parameter to the function is a NULL-terminated wide character string of the UNICODE_STRING
being created.
DeviceIoControl
is not the only function that can send data from user space to kernel drivers. CreateFile
, ReadFile
, WriteFile
, and other functions can also do this. For example, if a user-mode application calls ReadFile
on a handle to a device, the IRP_MJ_READ
function is called. In our example, we found the function for DeviceIoControl
by adding 0xe*4
to the beginning of the major function table because IRP_MJ_DEVICE_CONTROL
has a value of 0xe
. To find the function for read requests, we add 0x3*4
to the beginning of the major function table instead of 0xe*4
because the value of IRP_MJ_READ
is 0x3
.
kd> !devobj FileWriterDevice Device object (826eb030) is for: Rootkit \Driver\FileWriter DriverObject 827e3698 Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000040 Dacl e13deedc DevExt 00000000 DevObjExt 828eb0e8 ExtensionFlags (0000000000) Device queue is not busy.
The device object provides a pointer to the driver object, and once you have the address for the driver object, you can find the major function table.
After you’ve identified the malicious driver, you might still need to figure out which application is using it. One of the outputs of the !devobj
command that we just ran is a handle for the device object. You can use that handle with the !devhandles
command to obtain a list of all user-space applications that have a handle to that device. This command iterates through every handle table for every process, which takes a long time. The following is the abbreviated output for the !devhandles
command, which reveals that the FileWriterApp.exe application was using the malicious driver in this case.
kd>!devhandles 826eb030 ... Checking handle table for process 0x829001f0 Handle table at e1d09000 with 32 Entries in use Checking handle table for process 0x8258d548 Handle table at e1cfa000 with 114 Entries in use Checking handle table for process 0x82752da0 Handle table at e1045000 with 18 Entries in use PROCESS 82752da0 SessionId: 0 Cid: 0410 Peb: 7ffd5000 ParentCid: 075c DirBase: 09180240 ObjectTable: e1da0180 HandleCount: 18. Image: FileWriterApp.exe 07b8: Object: 826eb0e8 GrantedAccess: 0012019f
Now that we know which application is affected, we can find it in user space and analyze it using the techniques discussed throughout this book.