Debugging the Debugger - Reversing kldbgdrv.sys and Potential Usages

Rating: 2 votes, 2.50 average.
After various articles on malware analysis I decided to talk about a little different topic, due to the fact that I'm involved into Kernel Mode Coding the Windows Internals Research become a truly important aspect of my Research. As the title suggests, this time I'm going to Study and Reverse a particular component used by the Windows Debugging System, more precisely a Device Driver involved into Local Kernel Debugging.

Not many people is aware that is possible to perform Local Kernel Debugging, one of the most used Debugging Configurations is the Remote Debugging. Local Kernel Debugging can offer many important vantages, like valuable informations on the Status of the Kernel and Inspect Kmode Components. LKD (Local Kernel Debugging) can be acheived by booting in Debug Mode, both kd and windbg fully supports LKD.

The essential question now is, How the Debugging Engine, let's consider for example Windbg, is able to obtain informations about the kernel by running from usermode?

The reply to this question not only will uncover the problem itself but also will open new interesting questions and possibilities, such as:

#1 - "It's possible to develop an application that can use the same
technology ?"

#2 - "How to access the involved components and what are parameter to
have access?"

To begin the study of this problem, we have in first instance to reproduce the environement necessary to start a Local Debugging Session.

I've used for these tests Windows 7 32-Bits Ultimate Edition and Windbg.

First step is to enable debug mode by running:

bcdedit -debug on then reboot.

At this point we have literally to debug our debugger to be able to reveal the mechanism and component involved in communication between the Debug Engine and Kernel.

In the past Windows Editions, the function used was NtSystemDebugControl, but from Windows Vista to Higher Versions this function is not immediately available.

To trace windbg activities I've used a great tool for professional API Tracing, called Blade API Monitor.

The hypothesis was, if windbg runs at usermode and accesses a kernel component it's obvious that will be used a Device Driver, by assuming true this statement, every application that deals directly with Device Drivers will use:

* CreateFile -> For Driver Opening
* ReadFile / WriteFile -> Device Driver Communication
* DeviceIoControl -> Data exchange between Driver and umode application
* NtSystemDebugControl

After setting the proper filter for these functions, let's run a Local Kernel Debugging Session and watch the results from API Monitor.

When debugger is loaded, we can launch some command, like:


From API Log emerges an important result, we have two threads:

#- First Thread

CreateFileW(wchar_t* lpFileName = C:\Windows\Fonts\staticcache.dat,...)

#- Second Thread

CreateFileW( wchar_t* lpFileName = C:\Windows\system32\kldbgdrv.sys )
return value -> void* return = 0x00000128

WriteFile(void* hFile = 0x00000128, .., unsigned long nNumberOfBytesToWrite = 0x000031F0 )

CreateFileW(wchar_t* lpFileName = \\.\kldbgdrv)
return value -> void* return = 0x00000170

DeviceIoControl(void* hDevice = 0x00000170)
IOCTL -> unsigned long dwIoControlCode = 0x0022C007
As you can see, from the second thread we obtain a valuable amount of informations.

WinDbg creates a driver called kldbgdrv.sys placed in %\system32\ this file is 0x31F0 long.

Successively this driver is openened and windbg starts to send IOCTL to this driver.

The IO Control Code used is 0x0022C007.

When debugging session finishes, kldbgdrv.sys it's deleted.

To reverse this driver we have obviously to dump it, so the first operation is to locate where is placed and successively carve out this.

The most probable location where can be located are the resources of windbg or kd executables, so let's explore their PE.

Between resources of windbg.exe we can see that the last one called "17476" which contains another subdir called "30583" by opening also this last directory finally appears our wldbgdrv.sys (can be easly detected by watching between strings)

From the starting address of this resource if we add the len of bytes ( nNumberOfBytesToWrite = 0x000031F0) we can easly into a new file kldbgdrv.sys

Now let's reverse this driver.

INIT:00010D1F push offset aKdsystemdebugc ; "KdSystemDebugControl"
INIT:00010D24 lea eax, [ebp+DestinationString]
INIT:00010D27 push eax ; DestinationString
INIT:00010D28 call ds:RtlInitUnicodeString
INIT:00010D2E lea ecx, [ebp+DestinationString]
INIT:00010D31 push ecx ; SystemRoutineName
INIT:00010D32 call ds:MmGetSystemRoutineAddress
INIT:00010D38 mov [ebp+var_1C], eax
INIT:00010D3B cmp [ebp+var_1C], 0
INIT:00010D3F jnz short loc_10D4B
INIT:00010D46 jmp loc_10DF5

this is a really interesting piece of code, here the driver attempts to obtain the Routine Address of the function KdSystemDebugControl()

INIT:00010D4B mov edx, [ebp+DriverObject]
INIT:00010D4E mov dword ptr [edx+34h], offset sub_10A10 ;DriverUnload
INIT:00010D55 mov eax, [ebp+DriverObject]
INIT:00010D58 mov dword ptr [eax+38h], offset sub_10A50 ;DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_10A50
INIT:00010D5F mov ecx, [ebp+DriverObject]
INIT:00010D62 mov dword ptr [ecx+40h], offset sub_10A50 ;DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_10A50
INIT:00010D69 mov edx, [ebp+DriverObject]
INIT:00010D6C mov dword ptr [edx+70h], offset sub_10A80 ;DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_10A80
INIT:00010D73 push offset aDeviceKldbgdrv ; "\\Device\\kldbgdrv"
INIT:00010D78 lea eax, [ebp+DeviceName]
INIT:00010D7B push eax ; DestinationString
INIT:00010D7C call ds:RtlInitUnicodeString
INIT:00010D96 call ds:IoCreateDevice

Here the device it's created \\Device\\kldbgdrv and

There are also four MajorFunctions associations:

DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_10A10;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_10A50; // IofCompleteRequest(Irp, 0)
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_10A50; // IofCompleteRequest(Irp, 0)
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_10A80; // Suddenly Reversed
Let's check the latest Dispatch Routine:

PAGE:00010AEE push edx
PAGE:00010AEF push eax ; PrivilegeValue
PAGE:00010AF0 call ds:SeSinglePrivilegeCheck
PAGE:00010AF6 movzx ecx, al
PAGE:00010AF9 test ecx, ecx
PAGE:00010AFB jnz short loc_10B09
PAGE:00010AFD mov [ebp+var_3C], STATUS_ACCESS_DENIED
PAGE:00010B04 jmp loc_10C5B
PAGE:00010B09 mov [ebp+var_4], 0
PAGE:00010B10 mov edx, [ebp+var_30]
PAGE:00010B13 mov [ebp+var_48], edx
PAGE:00010B16 cmp [ebp+var_48], 22C007h ; IOCTL = 22C007h
PAGE:00010B1D jz short loc_10B24
PAGE:00010B1F jmp loc_10C2B

When the IOCTL = 22C007h it's sent the first operation is to check if the action has the proper privileges "SeSinglePrivilegeCheck", successively this dispatch routine validates and sanitizes parameters sent with the IOCTL, by using MmUserProbeAddress and ProbeForWrite.

Finally we can say that kldbgdrv.sys works as wrapper for KdSystemDebugControl.

This function belongs to NtSystemDebugControl but can be accessed only at kernel mode.

Here it's prototipe:

PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG ReturnLength,
_SYSDBG_COMMAND it's an enum, let's suppose we want SysDbgReadVirtual we have the corresponding struct:

typedef struct _SYSDBG_VIRTUAL
PVOID Address;
PVOID Buffer;
ULONG Request;
At this point we have all elements to use with success kldbgdrv.sys, that means the possibility to have access to the kernel from an user mode application.

A little resume here:

=> Systems need to be in Debug Mode
=> SeDebugPrivilege Enabled
=> Access to \\Device\\kldbgdrv
=> SYSDBD Commands can be sent via DeviceIoControl by using IOCTL 0x22C007

Thanks goes to:

Ivanlef0u that produced a great blog post on how KdSystemDebugControl can be used.

Deroko for his support

See you to the next post..
Giuseppe 'Evilcry' Bonfa

Submit "Debugging the Debugger - Reversing kldbgdrv.sys and Potential Usages" to Digg Submit "Debugging the Debugger - Reversing kldbgdrv.sys and Potential Usages" to del.icio.us Submit "Debugging the Debugger - Reversing kldbgdrv.sys and Potential Usages" to StumbleUpon Submit "Debugging the Debugger - Reversing kldbgdrv.sys and Potential Usages" to Google