Usermode Application Debugging Using KD

Posted on Wed 24 September 2014 in Reverse Engineering

I have started the Windows kernel hacking section with a simple explaination of the setup and a quick analysis of the crackme, that we analysed here, using the kd.exe kernel debugger.

I chose to do this instead of any actual Windows kernel stuff because its a steep learning experience learning how to use KD so its probably best to look at something you have already seen.

Setting Up The Environment

For this post I will be using a total of 4 machines, 3 virtual machines using VMware Player (you probably could use Virtualbox for this also though) hosted on a reasonably powerful machine and a laptop.

You can however do all of this with just 1 physical machine, hosting 1 virtual machine and I will explain the differences in the setup afterwards but I'll first explain the setup I am using.

Here is a visual representation of the network:

So I have 3 virtual machines on my machine running VMware Player:

1 Kali Linux, 1 Windows XP Professional and 1 Windows 7 Home Edition. All 3 of these are 32bit, although it doesn't matter but to follow along you would probably want the debuggee (the Windows 7 machine in my setup) to be 32bit. In my 2 machine setup described below the host (and debugger) is a Windows 7 64bit machine.

The Kali machine has 2 network interfaces, 1 setup in Bridged mode (so that I can SSH directly to it):

And the other setup in Host-only mode (So that it has access to the other 2 machines):

The Windows XP machine has 1 network interface setup in Host-only mode:

And the same for the Windows 7 machine:

The Windows XP and Windows 7 machines are also connected via a virtual serial cable, this is for the debugger connection.

The Windows XP machine will be the client (or the debugger):

And the Windows 7 machine will be the server (or the debuggee):

The Windows 7 machine needs both Visual Studio Express 2013 for Windows Desktop and the Windows Driver Kit (WDK) installed on it. You can get them both here.

The Windows XP machine needs Microsoft Windows SDK for Windows 7 installed, which you can get here. To install this you need to install the full version of Microsoft .NET Framework 4, which you can get here (Bare in mind that you might need an internet connection while you install these so just change the network adaptor configuration to NAT and then once it is installed change it back to Host-only again).

If the debugger is a Windows 7 machine then you will need to install the same software as on the debuggee.

Once these are installed, its best to add the path to the kd.exe application to the PATH variable.

You do this by going in to the properties of My Computer and, on Windows 7 going to Advanced system settings->Environment Variables... or on Windows XP going to Advanced->Environment Variables... and scroll down the Path and click Edit.

The path on Windows 7 should be something like C:\Program Files\Windows Kits\8.1\Debuggers\x86 and on Windows XP C:\Program Files\Debugging Tools for Windows (x86).

For remote administration I've installed TightVNC on both of the Windows machines.

I set it up with access through a Kali machine so that I can setup SSH tunnels and get VNC access to the Windows machines without giving them access to the outside network.

After TightVNC is up and running on your Windows machines, you can setup the SSH tunnels like this (For this explaination we'll imagine that the Windows XP machine is on the VMware virutal network with an IP of, the Windows 7 machine is on and that our Kali machine is also on this network):

[email protected]:~# ssh -f [email protected] -L 5900: -N
[email protected]:~# ssh -f [email protected] -L 5901: -N

Now if you VNC to you will have access to the Windows XP machine and to you will have access to the Windows 7 machine.

1 VM Setup

You can also setup this up with 2 machines, the VMware host (running Windows, which will be the debugger) and the VMware guest (also running Windows, which will be the debuggee).

The serial port configuration for the debuggee in VMware in this setup should look like this:

Notice the different file path and name for Windows, the other end should be set to The other end is an application and Yeild CPU on poll should be checked.

The only other thing that is different is the command you will use to launch KD on the debugger (we haven't got to that but it is shown below for my 4 machine setup), you should instead use kd -k com:port=\\.\pipe\com_1,pipe.

Using KD

On Windows 7 (the debuggee) you will need to tell it to lanuch the debugger on boot, for this you need to run an Administrator command prompt and:

C:\Windows\system32>bcdedit /dbgsettings SERIAL DEBUGPORT:2 BAUDRATE:115200
The operation completed successfully.

C:\Windows\system32>bcdedit /debug on
The operation completed successfully.

The DEBUGPORT:2 option here is the port number of the COM port that you are going to use, for me it was COM2 hence the number 2.

Now we launch the kernel debugger on the Windows XP machine (this is the command that is different on the 2 machine setup):

C:\Documents and Settings\User>kd -k com:port=1,baud=115200

Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.

Opened \\.\com1
Waiting to reconnect...

Again the port=1 option here is the COM port that you are going to be using, I will be using COM1 on this machine hence the 1.

Then reboot the Windows 7 machine and watch the KD terminal on the Windows XP machine:

Connected to Windows 7 7601 x86 compatible target at (Fri Sep 26 14:43:59.625 20
14 (UTC + 1:00)), ptr64 FALSE
Kernel Debugger connection established.
Symbol search path is: SRV*C:\websymbols*
Executable search path is:
Windows 7 Kernel Version 7601 (Service Pack 1) MP (1 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS Personal
Built by: 7601.18409.x86fre.win7sp1_gdr.140303-2144
Machine Name:
Kernel base = 0x82814000 PsLoadedModuleList = 0x8295d5b0
Debug session time: Sun Dec 29 22:42:59.976 1985 (UTC + 1:00)
System Uptime: 0 days 0:02:14.490

Now run the crackme application on the debuggee (Windows 7):

Go back to the Windows XP machine and in the debugger terminal window press Control + C:

Break instruction exception - code 80000003 (first chance)
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run kd.exe) or,                                        *
*       CTRL+BREAK (if you run WinDBG),                                       *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
8288e7b8 cc              int     3

Now we have broken into the kernel, this means that anything we do will be in the context of the kernel, we can see this in the debugger:

kd> .process
Implicit process is now 844bdae8
kd> !process 0 0
PROCESS 844bdae8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 88401c78  HandleCount: 463.
    Image: System

PROCESS 85027020  SessionId: none  Cid: 00ec    Peb: 7ffd4000  ParentCid: 0004
    DirBase: 5f228020  ObjectTable: 89496538  HandleCount:  29.
    Image: smss.exe

PROCESS 85702030  SessionId: 0  Cid: 0140    Peb: 7ffd6000  ParentCid: 0134
    DirBase: 5f228060  ObjectTable: 91695508  HandleCount: 389.
    Image: csrss.exe

PROCESS 84520378  SessionId: 0  Cid: 0170    Peb: 7ffdf000  ParentCid: 0134
    DirBase: 5f2280a0  ObjectTable: 93023448  HandleCount:  87.
    Image: wininit.exe

PROCESS 850e7030  SessionId: 1  Cid: 0178    Peb: 7ffda000  ParentCid: 0168
    DirBase: 5f228040  ObjectTable: 885f5520  HandleCount: 176.
    Image: csrss.exe

PROCESS 8572f530  SessionId: 1  Cid: 0194    Peb: 7ffdb000  ParentCid: 0168
    DirBase: 5f2280c0  ObjectTable: 93020e70  HandleCount: 117.
    Image: winlogon.exe

PROCESS 857e2c48  SessionId: 0  Cid: 01dc    Peb: 7ffd6000  ParentCid: 0170
    DirBase: 5f228080  ObjectTable: 98040678  HandleCount: 245.
    Image: services.exe

PROCESS 857fb980  SessionId: 0  Cid: 01e4    Peb: 7ffdf000  ParentCid: 0170
    DirBase: 5f2280e0  ObjectTable: 9805ba38  HandleCount: 504.
    Image: lsass.exe

PROCESS 857fc678  SessionId: 0  Cid: 01ec    Peb: 7ffdf000  ParentCid: 0170
    DirBase: 5f228100  ObjectTable: 9805dcf0  HandleCount: 144.
    Image: lsm.exe

PROCESS 8582c858  SessionId: 0  Cid: 0258    Peb: 7ffd6000  ParentCid: 01dc
    DirBase: 5f228120  ObjectTable: 98168ef8  HandleCount: 352.
    Image: svchost.exe

PROCESS 85845848  SessionId: 0  Cid: 02a4    Peb: 7ffd3000  ParentCid: 01dc
    DirBase: 5f228140  ObjectTable: 93182530  HandleCount: 241.
    Image: svchost.exe

PROCESS 8585b568  SessionId: 0  Cid: 02e0    Peb: 7ffd7000  ParentCid: 01dc
    DirBase: 5f228160  ObjectTable: 980d5468  HandleCount: 383.
    Image: svchost.exe

PROCESS 85897628  SessionId: 0  Cid: 0350    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f2281a0  ObjectTable: 8ca18bc0  HandleCount: 268.
    Image: svchost.exe

PROCESS 858a7410  SessionId: 0  Cid: 037c    Peb: 7ffda000  ParentCid: 01dc
    DirBase: 5f2281c0  ObjectTable: 8ca8e818  HandleCount: 251.
    Image: svchost.exe

PROCESS 858bf818  SessionId: 0  Cid: 03b4    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f2281e0  ObjectTable: 8ca00b30  HandleCount: 806.
    Image: svchost.exe

PROCESS 858ce658  SessionId: 0  Cid: 03ec    Peb: 7ffd8000  ParentCid: 02e0
    DirBase: 5f228200  ObjectTable: 8cb845d0  HandleCount: 121.
    Image: audiodg.exe

PROCESS 858d37c0  SessionId: 0  Cid: 0400    Peb: 7ffde000  ParentCid: 01dc
    DirBase: 5f228220  ObjectTable: 8cb97f58  HandleCount: 104.
    Image: svchost.exe

PROCESS 858e8238  SessionId: 0  Cid: 0460    Peb: 7ffd6000  ParentCid: 01dc
    DirBase: 5f228240  ObjectTable: 8cbc3380  HandleCount: 351.
    Image: svchost.exe

PROCESS 85707d40  SessionId: 1  Cid: 050c    Peb: 7ffd9000  ParentCid: 0194
    DirBase: 5f228280  ObjectTable: 92cff7b0  HandleCount:  46.
    Image: userinit.exe

PROCESS 8593dd40  SessionId: 1  Cid: 051c    Peb: 7ffda000  ParentCid: 0350
    DirBase: 5f2282a0  ObjectTable: 92d040e0  HandleCount:  71.
    Image: dwm.exe

PROCESS 8594b738  SessionId: 1  Cid: 0538    Peb: 7ffde000  ParentCid: 050c
    DirBase: 5f2282c0  ObjectTable: 92d16c08  HandleCount: 684.
    Image: explorer.exe

PROCESS 8595d990  SessionId: 0  Cid: 055c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f2282e0  ObjectTable: 980413e8  HandleCount:  75.
    Image: spoolsv.exe

PROCESS 85975d40  SessionId: 1  Cid: 0574    Peb: 7ffdb000  ParentCid: 01dc
    DirBase: 5f228300  ObjectTable: 98087388  HandleCount: 180.
    Image: taskhost.exe

PROCESS 8597c480  SessionId: 0  Cid: 059c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228320  ObjectTable: 981644c0  HandleCount: 321.
    Image: svchost.exe

PROCESS 857b1030  SessionId: 0  Cid: 061c    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f228340  ObjectTable: 9361d7c0  HandleCount:  62.
    Image: armsvc.exe

PROCESS 8576a030  SessionId: 0  Cid: 066c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228360  ObjectTable: 98192530  HandleCount:  84.
    Image: sqlwriter.exe

PROCESS 857b99c0  SessionId: 0  Cid: 0694    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228380  ObjectTable: 9765fa30  HandleCount:  92.
    Image: tlntsvr.exe

PROCESS 85996d40  SessionId: 1  Cid: 06bc    Peb: 7ffdf000  ParentCid: 0538
    DirBase: 5f2283a0  ObjectTable: 976b6a40  HandleCount:  64.
    Image: tvnserver.exe

PROCESS 859d92f0  SessionId: 0  Cid: 0708    Peb: 7ffdc000  ParentCid: 01dc
    DirBase: 5f2283e0  ObjectTable: 8d600730  HandleCount: 184.
    Image: tvnserver.exe

PROCESS 859ec4f0  SessionId: 1  Cid: 075c    Peb: 7ffd3000  ParentCid: 06cc
    DirBase: 5f228400  ObjectTable: 9812e900  HandleCount:  48.
    Image: reader_sl.exe

PROCESS 859f7d40  SessionId: 0  Cid: 0220    Peb: 7ffdd000  ParentCid: 01dc
    DirBase: 5f2283c0  ObjectTable: 977880a0  HandleCount: 102.
    Image: svchost.exe

PROCESS 85a68d40  SessionId: 0  Cid: 03c4    Peb: 7ffd9000  ParentCid: 01dc
    DirBase: 5f228260  ObjectTable: 980eb688  HandleCount: 590.
    Image: SearchIndexer.exe

PROCESS 85a4cd40  SessionId: 0  Cid: 04dc    Peb: 7ffd5000  ParentCid: 03c4
    DirBase: 5f228420  ObjectTable: 94285460  HandleCount: 233.
    Image: SearchProtocolHost.exe

PROCESS 85a95d40  SessionId: 0  Cid: 0378    Peb: 7ffd5000  ParentCid: 03c4
    DirBase: 5f228440  ObjectTable: 931b48e8  HandleCount:  79.
    Image: SearchFilterHost.exe

PROCESS 85abfd40  SessionId: 1  Cid: 08e4    Peb: 7ffdf000  ParentCid: 0538
    DirBase: 5f228460  ObjectTable: 92c6b320  HandleCount:  35.
    Image: SomeCrypto~01.exe


On line 1 I run the .process command without any parameters and it tells us the process we are currently in (844bdae8 is the EPROCESS number).

On line 3 I run the !process extension with 0 0 as its arguments, this lists all of the running processes and some details about them, as you can see from lines 5-7, EPROCESS 844bdae8 is the System process, or the kernel.

What we want to do is change the context to our crackme application, which you can see from lines 141-143 has the EPROCESS of 85abfd40:

kd> .process /i /r /p 85abfd40
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
828c97b8 cc              int     3
kd> .process
Implicit process is now 85abfd40

On line 1 I use the .process command to change the context to our crackme application but before the context can be changed execution needs to be resumed (which is done on line 5).

Now we can set a breakpoint anywhere in the crackme's virtual memory address space, we want to break with them calls to GetDlgItemTextA that were responsible for getting the text in the textboxes of the application (If you are unsure about what I am talking about, please go back and review the previous post):

kd> bp USER32!GetDlgItemTextA
kd> bl
 0 e 76213d14     0001 (0001) user32!GetDlgItemTextA

Now that the breakpoint is set we can resume execution, wait for it to be hit and inspect the memory.

Remember that the prototype for GetDlgItemText is:

  _In_   HWND hDlg,
  _In_   int nIDDlgItem,
  _Out_  LPTSTR lpString,
  _In_   int nMaxCount
kd> g
Breakpoint 0 hit
001b:76213d14 8bff            mov     edi,edi
kd> dd esp L4
0012fb6c  0040127f 0002014e 000003e9 0012fc40
kd> da 12fc40
0012fc40  "Enter your name..."

On line 5 I use the dd command to display 4 double words on the top of the stack. The first dword will be the return address (as you will see in a minute), then we have the first 3 arguments.

The 3rd argument is the address where the buffer for the string is, on line 7 I use the da command to display the ascii value at that address.

Keep in mind that this is the start of the function so the value hasn't been fetched yet, we can see the returned value by tracing through until we are in the calling function using the ug command and checking again:

kd> gu
001b:0040127f 6a40            push    40h
kd> u
001b:0040127f 6a40            push    40h
001b:00401281 8d942484000000  lea     edx,[esp+84h]
001b:00401288 52              push    edx
001b:00401289 68ea030000      push    3EAh
001b:0040128e 56              push    esi
001b:0040128f ffd7            call    edi
001b:00401291 8d44240c        lea     eax,[esp+0Ch]
001b:00401295 50              push    eax
kd> da 12fc40
0012fc40  "Enter your name..."

As you can see the value is the same (because we haven't changed the text in the textbox), you can also see the address which it returned back to after executing GetDlgItemTextA was 0040127f, which was the top value on the stack.

Lastly let's resume and make sure it does the same with the other textbox:

kd> g
Breakpoint 0 hit
001b:76213d14 8bff            mov     edi,edi
kd> dd esp L4
0012fb6c  00401291 0002014e 000003ea 0012fc00
kd> da 12fc00
0012fc00  "Enter your serial..."
kd> gu
001b:00401291 8d44240c        lea     eax,[esp+0Ch]
kd> da 12fc00
0012fc00  "Enter your serial..."


This was only a simple tutorial to get the environment set up and get a basic grasp of kd.exe and some of its commands.

This was by no means an exhaustive list of commands and extensions, the debugger comes with many and has very good documentation.

Hopefully you now have a better understanding of how to debug using kd.exe and you now have the environment to do it in.

Further Reading

The Debugging and Automation chapter in Practical Reverse Engineering by Bruce Dang, Alexandre Gazet and Elias Bachaalany.

Also the kd.exe documentation that ships with the WDK or SDK.