WINDBG // EXPLOIT-DEV CHEATSHEET

Commands you used — explained for real exploit-dev work

Focus: stepping, registers, stack args, deref pointers, dumping memory/strings, structures via symbols, and breakpoints (software + hardware).
all execution registers memory-dump strings structures breakpoints

Command Table

Command What it does Exploit-dev use (why you care) Example
g Go / resume execution Continue until the next breakpoint/exception. Typical loop: set breakpoint → g → inspect state → adjust.
fast loop crash triage
g
u Unassemble code at an address / symbol Confirm what a function really does (prologue/epilogue, args usage, calls). In exploit dev: verify where a buffer copy happens, where a conditional jump depends on flags, or where a pointer is dereferenced.
control-flow call sites
u kernel32!GetCurrentThread
u @eip L20
r Show/modify registers Core for exploit debugging: see if you control EIP/RIP, check stack pointer alignment, watch function return values (EAX/RAX), or patch state on-the-fly.
state view can change flow
r
r eax
r eax=41414141
db Dump bytes (hex + ASCII) Best for raw payload checking: see exact bytes of a buffer, spot bad chars (00, 0a, etc.), validate NOP sled, shellcode, or overwritten saved EIP bytes on stack.
badchars payload
db @esp L80
db 0019ff00
dw Dump WORDs (2 bytes) Useful when data is 16-bit values (some structures, Unicode code units, length fields). Helps avoid misreading when bytes are paired.
16-bit
dw @esp L20
dd Dump DWORDs (4 bytes) Your default in x86: stack arguments, saved return addresses, pointers. In exploit dev you often do: break at API → dd @esp to read arguments and return address.
x86 stack args
dd @esp L20
dq Dump QWORDs (8 bytes) Your default in x64: pointers are 8 bytes. Use for stack/pointers on 64-bit targets.
x64 pointers
dq @rsp L20
dc Dump DWORDs + ASCII (side-by-side) Perfect when you suspect “this memory is a mix of pointers + text”. Often reveals paths/format strings next to pointers in stack frames or heap chunks.
mixed view
dc @esp L20
dds Dump DWORD pointers and try symbol-resolve This is why it’s gold in exploit dev: it turns raw pointers into meaning. On stack: shows return address as module!function+offset, shows where execution will go next.
symbolize stack walk
dds @esp L10
poi() Pointer dereference helper Reads memory at “address stored in X”. Used constantly: stack arg is a pointer → deref it → dump data it points to. Also used in conditions.
deref watch invalid ptr
dd poi(@esp+8) L10
da poi(@esp+0xC)
da Dump ASCII string When the buffer is ANSI/ASCII (1 byte per char). In exploit dev: confirm which argument is a path, username, header, command line, etc.
ANSI
da 02cebd38
da poi(@esp+8)
du Dump Unicode (UTF-16LE) string Common on Windows APIs that use wide strings (W versions). 2 bytes per char. If da looks “broken”, try du.
UTF-16LE WinAPI wide
du poi(@rcx)
du 0019fe00
dt Display a typed structure (needs symbols) Lets you parse complex data safely: TEB/PEB, token structures, exception records, stack frames, and API structs. In exploit dev: validate what a pointer *claims* to be.
parse structs symbols
dt ntdll!_TEB
dt ntdll!_TEB @$teb
bp Software breakpoint (INT3) Stop at a function / address. Use when you want to inspect arguments, return value, or flow. If you patch code or have self-modifying code, it can be less reliable.
stop here
bp kernel32!WriteFile
ba Hardware breakpoint (e/r/w) on address Your “watchpoint”. Huge for exploit dev: break when a specific buffer is written (find who corrupts it), or when an address is executed. Limited (few slots).
watchpoint limited slots
ba w4 02cebdb8
ba e1 kernel32!WriteFile
.if / .printf Conditional logic + printing (used in conditional breakpoints) Used to break only when a condition matches (e.g., written bytes == 1). In exploit dev: filter noisy APIs, catch the *one* call that matters.
filter noise syntax sensitive
bp kernel32!WriteFile ".if (poi(@esp+0x10)==1) { .printf \"hit\\n\"; } .else { gc }"