No theme, no regular posting.

© 2014-2020. Raphaël Rigo CC-BY-SA 4.0


WinDbg: setting up a cross-VM debugging, tips

Setting up WinDbg can be a real pain. This posts documents how to lessen the pain (or at least to make it less painful to do another setup).


Getting started with network KD

A few things to keep in mind:

The reference documentation is here but is not that practical.

Network setup

WinDbg setup, on the target

If you need more infos about the various options, see the documentation.

WinDbg setup, on the host:

Connecting things

Now, you can reboot your target, and you should get the following in your host’s WinDbg shell:

Connected to target on port 50000 on local IP
You can get the target MAC address by running .kdtargetmac command.
Connected to Windows 10 18362 x64 target at (Fri Mar 27 14:41:52.051 2020 (UTC + 1:00)), ptr64 TRUE
Kernel Debugger connection established.

As you can see, since we specified the nodhcp option in the target’s config, the source IP is in the “Automatic private IP” range. So if your host’s firewall is not completely open, make sure this range is allowed.

You can make sure things work correctly by disassembling some symbol:

0: kd> u ZwQueryInformationProcess
fffff803`697bec50 488bc4          mov     rax,rsp
fffff803`697bec53 fa              cli
fffff803`697bec54 4883ec10        sub     rsp,10h
fffff803`697bec58 50              push    rax
fffff803`697bec59 9c              pushfq
fffff803`697bec5a 6a10            push    10h
fffff803`697bec5c 488d055d750000  lea     rax,[nt!KiServiceLinkage (fffff803`697c61c0)]
fffff803`697bec63 50              push    rax

WinDbg gotchas

So, WinDbg is a weird beast, here are a few things to know:

Cheat “sheet”


.reload /f => force symbol reload 
.reload /unl module => force symbol reload for a module that's not loaded


u address => disassembly (ex: u ntdll+0x1000).
"u ." => eip
u . l4 => 4 lines from eip

breakpoints, running

bc nb => clear bp nb
bd nb => disable bp nb
bc/bd * => clear/disable all bps
bp addr => set bp
bp /1 addr => bp one-shot (deleted after first trig)
bl => list bp
ba => hardware bp
ba r 8 /p addr1 /t addr2 addr3
  => r==break RW access ; 
     8==size to monitor ; 
     /p EPROCESS address (process) ;
     /t thread addresse
     addr3 == actual ba adress
bp addr ".if {command1;command2} .else {command}"
p => single step
pct => continue til next call or ret
gu => go til next ret


da - dump ascii
db - dump bytes  => displays byte + ascii
dd - dump DWords
dp - dump pointer-sized values
dq - dump QWords
du - dump Unicode (16 bits characters)
dw - dump Words
deref => poi(address)
!da !db !dq addr => display mem at PHYSICAL address


ed addr value => set value at given address
eq => qword
a addr => assemble (x86 only) at this address (empty line to finish=)


dt nt!_EPROCESS addr => dump EPROCESS struct at addr

State, processes, etc

lm       => list modules
kb, kv   => callstack
!peb     => peb of current process
!teb     => teb of current thread
!process 0 0 => display all processes
!process my_process.exe => show info for "my_process.exe"
!sd addr => dump security descriptor


!object \Driver\
!drvobj Asgio2 => dump \Driver\Asgio2


!devobj Asgio2 => dump \Device\Asgio2


!address => dump address space
!pte VA => dump PTEs for VA


A lot of thanks to Fist0urs for the help and cheat sheet ;)