- Introduction to Windows Debugger
- What is a Debugger?
- WinDbg Interface
- Understanding the Workspace
- Debugging Symbols
- Accessing and Manipulating Memory from WinDbg
- Reading from Memory
- Dumping Structures from Memory
- Writing to Memory
- Searching the Memory Space
- Inspecting and Editing CPU Registers in WinDbg
- Controlling the Program Execution in WinDbg
- Software Breakpoints
- Unresolved Function Breakpoint
- Breakpoint-Based Actions
- Hardware Breakpoints
- Stepping Through the Code
- Additional WinDbg Features
- Listing Modules and Symbols in WinDbg
- Using WinDbg as a Calculator
- Data Output Format
WinDbg (Windows Debugger) is Microsoft's flagship debugging tool, part of the Windows SDK. It's a powerful, command-line driven debugger capable of analyzing both user-mode applications and kernel-mode components. WinDbg is essential for system administrators, developers, and security researchers working with Windows systems.
timeline
title Windows Debugging Tools Evolution
1990s : Early Windows Debuggers
: Basic debugging capabilities
: Limited symbol support
2000s : WinDbg Classic
: Command-line interface
: Symbol server support
2010s : Enhanced WinDbg
: 64-bit support
: JavaScript scripting
2020s : WinDbg Preview
: Modern UI
: Time Travel Debugging
: Enhanced usability
| Feature Category | Capabilities | Use Cases |
|---|---|---|
| Process Analysis | Live process debugging, crash dump analysis | Application troubleshooting |
| Memory Analysis | Memory dumps, heap analysis, leak detection | Performance optimization |
| Kernel Debugging | System crash analysis, driver debugging | System administration |
| Security Analysis | Exploit analysis, malware investigation | Security research |
Debugger Comparison Matrix:
┌─────────────────────────────────────────────────────────────────┐
│ Feature Comparison │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Feature │ WinDbg │ Visual Studio │ GDB │ OllyDbg │
│ ─────────────────┼────────┼───────────────┼───────┼───────────┤
│ User Mode │ ✓ │ ✓ │ ✓ │ ✓ │
│ Kernel Mode │ ✓ │ ✗ │ ✗ │ ✗ │
│ Crash Dumps │ ✓ │ ✓ │ ✓ │ ✗ │
│ Remote Debug │ ✓ │ ✓ │ ✓ │ ✗ │
│ Scripting │ ✓ │ ✓ │ ✓ │ ✗ │
│ Symbol Support │ ✓ │ ✓ │ ✓ │ ✓ │
│ Learning Curve │ High │ Medium │ High │ Medium │
│ │
└─────────────────────────────────────────────────────────────────┘
| Role | WinDbg Usage | Key Benefits |
|---|---|---|
| Software Developer | Bug hunting, performance analysis | Deep system understanding |
| System Administrator | Crash analysis, troubleshooting | System stability |
| Security Researcher | Malware analysis, exploit development | Low-level system access |
| Quality Assurance | Test failure analysis, regression testing | Comprehensive debugging |
A debugger is a specialized software tool that allows developers and analysts to examine the execution of another program. It provides the ability to pause execution, inspect state, modify behavior, and understand program flow.
Debugger Classification:
┌─────────────────────────────────────────────────────────────────┐
│ Debugger Types │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ User Mode │ │ Kernel Mode │ │
│ │ Debuggers │ │ Debuggers │ │
│ │ │ │ │ │
│ │ • Application │ │ • System level │ │
│ │ debugging │ │ debugging │ │
│ │ • Process level │ │ • Driver debug │ │
│ │ • Limited scope │ │ • Full system │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Local │ │ Remote │ │
│ │ Debuggers │ │ Debuggers │ │
│ │ │ │ │ │
│ │ • Same machine │ │ • Network based │ │
│ │ • Direct access │ │ • Separate host │ │
│ │ • Fast response │ │ • Isolated env │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Core Debugging Operations:
┌─────────────────────────────────────────┐
│ Execution Control │
│ ┌─────────────────────────────────────┐ │
│ │ • Start/Stop execution │ │
│ │ • Step through instructions │ │
│ │ • Breakpoint management │ │
│ │ • Program flow control │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ State Inspection │
│ ┌─────────────────────────────────────┐ │
│ │ • Register examination │ │
│ │ • Memory content viewing │ │
│ │ • Variable value inspection │ │
│ │ • Call stack analysis │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ Modification │
│ ┌─────────────────────────────────────┐ │
│ │ • Memory content changes │ │
│ │ • Register value updates │ │
│ │ • Execution path alteration │ │
│ │ • Conditional execution │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
flowchart TD
A[Problem Identified] --> B[Attach Debugger]
B --> C[Load Symbols]
C --> D[Set Breakpoints]
D --> E[Execute Program]
E --> F{Breakpoint Hit?}
F -->|Yes| G[Examine State]
F -->|No| H[Check for Issues]
G --> I[Analyze Data]
I --> J{Problem Found?}
J -->|Yes| K[Document Solution]
J -->|No| L[Continue Debugging]
L --> E
H --> M[Program Complete]
K --> N[End Session]
M --> N
WinDbg comes in multiple versions, each with distinct interfaces and capabilities:
| Version | Interface Type | Key Features | Best For |
|---|---|---|---|
| WinDbg Classic | Command-line driven | Powerful commands, scripting | Advanced users, automation |
| WinDbg Preview | Modern GUI | Visual interface, TTD support | New users, interactive debugging |
| CDB | Console-only | Lightweight, scriptable | Automated testing, CI/CD |
| KD | Kernel debugging | Kernel-mode focus | System debugging |
WinDbg Classic Layout:
┌─────────────────────────────────────────────────────────────────┐
│ File Edit View Debug Options Window Help │ ← Menu Bar
├─────────────────────────────────────────────────────────────────┤
│ [Open] [Attach] [Go] [Break] [Step] [Trace] [Watch] [Memory] │ ← Toolbar
├─────────────────────────────────────────────────────────────────┤
│ │
│ Command Window │ Watch Window │
│ ───────────────── │ ────────────── │
│ Microsoft (R) Windows Debugger │ │
│ 0:000> !analyze -v │ Expression: eax │
│ ***************************** │ Value: 0x00000042 │
│ * Exception Analysis * │ │
│ ***************************** │ Expression: ebp+8 │
│ FAULTING_IP: │ Value: 0x0012ff40 │
│ myapp!main+0x23 │ │
│ 00401053 8b08 mov ecx,[eax] │ │
│ │ │
├─────────────────────────────────────┼───────────────────────────┤
│ Disassembly Window │ Registers Window │
│ ────────────────── │ ──────────────── │
│ myapp!main: │ eax=00000000 ebx=7ffdf000│
│ 00401030 55 push ebp │ ecx=00000001 edx=00322a70│
│ 00401031 8bec mov ebp,esp │ esi=00000000 edi=00000000│
│ 00401033 51 push ecx │ esp=0012ff80 ebp=0012ff94│
│ →00401034 8b4508 mov eax,[ebp+8] │ eip=00401034 efl=00000246│
│ 00401037 8945fc mov [ebp-4],eax │ │
│ │ cs=001b ss=0023 ds=0023 │
├─────────────────────────────────────┼───────────────────────────┤
│ Call Stack Window │ Memory Window │
│ ───────────────── │ ───────────── │
│ ChildEBP RetAddr │ 0012ff80 8b 4d 08 89 │
│ 0012ff80 004010b2 myapp!main+0x23 │ 0012ff84 45 fc 8b 45 │
│ 0012ff94 004011f6 myapp!wmain+0x42│ 0012ff88 08 89 45 f8 │
│ 0012ffc0 7c817067 myapp!__tmain+0x96│ 0012ff8c 8b 4d fc 8b │
│ │ 0012ff90 55 08 3b c1 │
└─────────────────────────────────────┴───────────────────────────┘
| Window | Purpose | Common Usage |
|---|---|---|
| Command Window | Primary interaction | Enter commands, view output |
| Disassembly Window | Assembly code view | Step through instructions |
| Registers Window | CPU register state | Monitor register changes |
| Memory Window | Raw memory content | Examine data structures |
| Call Stack Window | Function call hierarchy | Trace execution path |
| Watch Window | Expression evaluation | Monitor variables |
WinDbg Preview Layout:
┌─────────────────────────────────────────────────────────────────┐
│ ☰ File Debug View Window Help 🔍 Search │ ← Ribbon Menu
├─────────────────────────────────────────────────────────────────┤
│ 📁 Open dump 🔗 Attach ▶️ Go ⏸️ Break 👟 Step 🔄 Restart │ ← Quick Access
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ Command ──────────────────┐ ┌─ Source ─────────────────────┐ │
│ │ 0:000> !analyze -v │ │ 1: int main(int argc, char* │ │
│ │ FAULTING_IP: │ │ 2: { │ │
│ │ test!main+0x17 │ │ 3: int* ptr = nullptr; │ │
│ │ 00000001 8b08 mov ecx,[eax│ │ 4: ► return *ptr; │ │ ← Source highlighting
│ │ │ │ 5: } │ │
│ │ 0:000> │ │ │ │
│ └────────────────────────────┘ └─────────────────────────────┘ │
│ │
│ ┌─ Disassembly ──────────────┐ ┌─ Registers ─────────────────┐ │
│ │ test!main: │ │ 📍 General Registers │ │
│ │ 00000001 55 push rbp │ │ rax = 0000000000000000 │ │
│ │ 00000002 48 mov rbp, │ │ rbx = 00007ff7c2f01000 │ │
│ │ 00000004 48 sub rsp, │ │ rcx = 0000000000000001 │ │
│ │►00000008 c7 mov qword│ │ 📍 Flag Register │ │
│ │ 00000010 48 mov rax, │ │ IOPL: 0 of: 0 sf: 0 │ │
│ └────────────────────────────┘ └─────────────────────────────┘ │
│ │
│ ┌─ Memory ───────────────────┐ ┌─ Call Stack ────────────────┐ │
│ │ Address: 0x0012ff80 │ │ 🏠 test!main+0x17 │ │
│ │ 00000000: 8b 4d 08 89 45 │ │ kernel32!BaseThread... │ │
│ │ 00000004: fc 8b 45 08 89 │ │ ntdll!RtlUserThread... │ │
│ │ 00000008: 45 f8 8b 4d fc │ │ │ │
│ └────────────────────────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Function | Shortcut | Description |
|---|---|---|
| Break | Ctrl+Break |
Stop execution |
| Go | F5 |
Continue execution |
| Step Into | F11 |
Execute one instruction |
| Step Over | F10 |
Step over function calls |
| Run to Cursor | Ctrl+F10 |
Execute until cursor position |
| Toggle Breakpoint | F9 |
Set/clear breakpoint |
A WinDbg workspace consists of multiple interconnected windows that provide different views of the debugging target. Understanding how these components work together is crucial for effective debugging.
WinDbg Workspace Flow:
┌─────────────────────────────────────────────────────────────────┐
│ Target Process │
├─────────────────────────────────────────────────────────────────┤
│ ↕ │
│ Debugging Engine │
│ ↕ │
├─────────────────────────────────────────────────────────────────┤
│ WinDbg Interface │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Command │ │ Memory │ │ Registers │ │
│ │ Window │ │ Windows │ │ Window │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Disassembly │ │ Call Stack │ │ Watch │ │
│ │ Window │ │ Window │ │ Window │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
The Command Window is the heart of WinDbg interaction:
Command Window Features:
┌─────────────────────────────────────────┐
│ Microsoft (R) Windows Debugger │
│ Version 10.0.22621.2428 AMD64 │
│ Copyright (c) Microsoft Corporation. │
│ │
│ CommandLine: "C:\test\myapp.exe" │
│ Symbol search path is: SRV*C:\symbols* │
│ │
│ ModLoad: 00007ff6`12340000 ... │
│ ModLoad: 00007ffc`d5f10000 ... │
│ │
│ (1234.5678): Break instruction exc... │
│ Execute '.help' for information │
│ │
│ 0:000> █ │ ← Command prompt
└─────────────────────────────────────────┘
| Operation | Classic WinDbg | WinDbg Preview |
|---|---|---|
| Save Workspace | File > Save Workspace As |
Automatic with project |
| Load Workspace | File > Open Workspace |
Recent workspaces list |
| Default Workspace | Stored in registry | User profile folder |
Debugging symbols are metadata that provide a mapping between compiled binary code and the original source code. They contain information about function names, variable names, data types, and source line numbers.
| Format | Extension | Content | Use Case |
|---|---|---|---|
| Program Database | .pdb | Full debug information | Development debugging |
| Debug File | .dbg | Basic symbol information | Legacy support |
| Symbol File | .sym | Minimal symbol data | Distribution |
| Map File | .map | Address mappings | Basic debugging |
The symbol path tells WinDbg where to find symbol files:
Symbol Path Components:
┌─────────────────────────────────────────┐
│ Symbol Path Format: │
│ │
│ cache*localdir*srv*symbolserver │
│ │ │ │ │ │
│ │ │ │ └─ Symbol server URL
│ │ │ └───────── Server indicator
│ │ └────────────────── Local cache directory
│ └───────────────────────── Cache indicator
│ │
│ Example: │
│ cache*c:\symbols*srv* │
│ https://msdl.microsoft.com/download/symbols
└─────────────────────────────────────────┘
| Method | Command/Location | Scope |
|---|---|---|
| Environment Variable | _NT_SYMBOL_PATH |
System-wide |
| WinDbg Command | .sympath |
Session-specific |
| Command Line | -y parameter |
Launch-specific |
| Registry | WinDbg settings | User-specific |
flowchart TD
A[Module Loaded] --> B[Check Local Path]
B --> C{Symbol Found?}
C -->|Yes| D[Load Local Symbol]
C -->|No| E[Check Cache]
E --> F{Symbol Found?}
F -->|Yes| G[Load Cached Symbol]
F -->|No| H[Download from Server]
H --> I{Download Success?}
I -->|Yes| J[Cache Symbol]
I -->|No| K[Use Export Information]
J --> L[Load Symbol]
D --> M[Symbol Ready]
G --> M
L --> M
K --> N[Limited Information]
| Command | Purpose | Example |
|---|---|---|
.sympath |
Show/set symbol path | .sympath srv*c:\symbols*https://msdl.microsoft.com/download/symbols |
.reload |
Reload symbols | .reload /f kernel32 |
.symopt |
Symbol options | .symopt +0x40 |
ld |
Load symbols | ld kernel32 |
WinDbg provides comprehensive memory access capabilities, allowing examination and modification of target process memory in various formats and granularities.
Memory Address Types:
┌─────────────────────────────────────────────────────────────────┐
│ Virtual Addresses │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ User Mode (0x00000000 - 0x7FFFFFFF) │ │
│ │ • Application memory space │ │
│ │ • Process-specific addressing │ │
│ │ • Accessible in user-mode debugging │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Kernel Mode (0x80000000 - 0xFFFFFFFF) │ │
│ │ • System memory space │ │
│ │ • Shared across processes │ │
│ │ • Requires kernel debugging │ │
│ └─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Physical Addresses │
│ • Actual RAM locations │
│ • Hardware-level addressing │
│ • Kernel debugging required │
└─────────────────────────────────────────────────────────────────┘
| Command | Purpose | Syntax | Example |
|---|---|---|---|
| d | Display memory | d[type] address [length] |
dd 0x401000 L4 |
| e | Edit memory | e[type] address value |
ed 0x401000 12345678 |
| s | Search memory | s[type] range pattern |
s -a 0x401000 L1000 "hello" |
| f | Fill memory | f address L length value |
f 0x401000 L100 0x90 |
Memory reading is one of the most fundamental operations in WinDbg. Understanding the various display formats and options is crucial for effective debugging.
The d command family provides comprehensive memory display capabilities:
Display Command Syntax:
┌─────────────────────────────────────────┐
│ d[format] [address] [L length] │
│ │
│ Where: │
│ • format = b,w,d,q,a,u,c,f,D │
│ • address = memory location │
│ • length = number of elements │
│ │
│ Examples: │
│ db 401000 - bytes at 401000 │
│ dd 401000 L10 - 10 dwords at 401000 │
│ da @esp+4 - ASCII at ESP+4 │
└─────────────────────────────────────────┘
Byte Display Example:
0:000> db 0x401000 L20
00401000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ..............
00401010 b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00 ........@.......
Format breakdown:
• Address: 00401000
• Hex bytes: 4d 5a 90 00...
• ASCII: MZ..............
• Dash separator every 8 bytes
ASCII String Examples:
┌─────────────────────────────────────────┐
│ Single string: │
│ 0:000> da 0x402000 │
│ 00402000 "Hello World" │
│ │
│ Unicode display: │
│ 0:000> du 0x403000 │
│ 00403000 "Hello World" │
│ │
│ Raw Unicode bytes: │
│ 0:000> db 0x403000 L20 │
│ 00403000 48 00 65 00 6c 00 6c 00-6f 00 20 00 57 00...
│ H . e . l . l . o . . W .
└─────────────────────────────────────────┘
Structure dumping is a powerful feature that allows examination of complex data types using their symbolic information. This capability is essential for understanding object layouts, debugging data corruption, and analyzing program state.
The dt (display type) command is the primary tool for structure analysis:
dt Command Syntax:
┌─────────────────────────────────────────┐
│ dt [module!]type [address] [options] │
│ │
│ Parameters: │
│ • module = DLL/EXE name (optional) │
│ • type = structure/class name │
│ • address = memory location │
│ • options = formatting flags │
│ │
│ Examples: │
│ dt _PEB - show structure │
│ dt _PEB 0x7ffdf000 - dump at addr │
│ dt ntdll!_TEB @$teb - specific module│
└─────────────────────────────────────────┘
PEB Structure Analysis:
┌─────────────────────────────────────────┐
│ 0:000> dt _PEB 0x7ffdf000 │
│ ntdll!_PEB │
│ +0x000 InheritedAddressSpace : 0y0 │
│ +0x000 ReadImageFileExecOptions : 0y0│
│ +0x000 BeingDebugged : 0y1 │
│ +0x000 BitField : 0y00001│
│ +0x000 SpareBits : 0y00000│
│ +0x004 Mutant : 0xffffffff
│ +0x008 ImageBaseAddress : 0x00400000
│ +0x00c Ldr : 0x77f42000
│ +0x010 ProcessParameters : 0x00020000
│ +0x014 SubSystemData : (null) │
│ +0x018 ProcessHeap : 0x00080000
│ ... (additional fields) │
└─────────────────────────────────────────┘
WinDbg provides powerful capabilities for modifying memory contents during debugging sessions. This feature is essential for testing hypotheses, fixing values temporarily, and understanding program behavior under different conditions.
Edit Command Syntax:
┌─────────────────────────────────────────┐
│ e[type] address value [value2] [...] │
│ │
│ Type specifiers: │
│ • eb = edit bytes │
│ • ew = edit words (16-bit) │
│ • ed = edit dwords (32-bit) │
│ • eq = edit qwords (64-bit) │
│ • ea = edit ASCII string │
│ • eu = edit Unicode string │
│ │
│ Examples: │
│ ed 0x401000 12345678 │
│ ea 0x402000 "Hello World" │
│ eb 0x403000 90 90 90 │
└─────────────────────────────────────────┘
Byte Editing Examples:
┌─────────────────────────────────────────┐
│ Single byte modification: │
│ 0:000> eb 0x401000 90 │
│ │
│ Multiple bytes: │
│ 0:000> eb 0x401000 90 90 90 90 │
│ │
│ Before: │
│ 0:000> db 0x401000 L4 │
│ 00401000 55 8b ec 83 │
│ │
│ After: │
│ 0:000> db 0x401000 L4 │
│ 00401000 90 90 90 90 │
│ │
│ NOP instruction (0x90) inserted │
└─────────────────────────────────────────┘
Memory searching is a critical debugging capability that allows you to locate specific patterns, values, or structures within the target process memory space. WinDbg provides comprehensive search functionality through the s command family.
Search Command Format:
┌─────────────────────────────────────────┐
│ s[type] range pattern │
│ │
│ Type specifiers: │
│ • -b = byte search │
│ • -w = word search (16-bit) │
│ • -d = dword search (32-bit) │
│ • -q = qword search (64-bit) │
│ • -a = ASCII string search │
│ • -u = Unicode string search │
│ │
│ Range formats: │
│ • start_addr end_addr │
│ • start_addr L length │
│ • module_name │
└─────────────────────────────────────────┘
ASCII String Search Examples:
┌─────────────────────────────────────────┐
│ Search for exact string: │
│ 0:000> s -a 0x400000 L100000 "error" │
│ 00402104 "error message" │
│ 00403567 "file error" │
│ │
│ Case-sensitive search: │
│ 0:000> s -a 0x400000 L100000 "Error" │
│ 00402890 "Error: File not found" │
│ │
│ Search in specific module: │
│ 0:000> s -a myapp "password" │
└─────────────────────────────────────────┘
CPU registers are high-speed storage locations directly accessible to the processor. They are the fastest form of memory available and are essential for all CPU operations. Understanding registers is crucial for low-level programming, debugging, and performance optimization.
Register Display Commands:
┌─────────────────────────────────────────┐
│ Command │ Purpose │
├─────────────────────────────────────────┤
│ r │ Display all general registers │
│ r eax │ Display specific register │
│ rf │ Display floating point regs │
│ rm │ Display MMX registers │
│ rx │ Display SSE registers │
│ rM │ Display all register types │
└─────────────────────────────────────────┘
General Register Output:
┌─────────────────────────────────────────┐
│ 0:000> r │
│ eax=00000000 ebx=7ffdf000 ecx=00000001 │
│ edx=00322a70 esi=00000000 edi=00000000 │
│ eip=00401030 esp=0012ff80 ebp=0012ff94 │
│ iopl=0 nv up ei pl zr na pe nc │
│ cs=001b ss=0023 ds=0023 es=0023 │
│ fs=0053 gs=002b │
│ │
│ Register breakdown: │
│ • General Purpose: EAX, EBX, ECX, EDX │
│ • Index Registers: ESI, EDI │
│ • Stack Registers: ESP, EBP │
│ • Instruction Pointer: EIP │
│ • Flags Register: EFLAGS (decoded) │
│ • Segment Registers: CS, DS, ES, etc. │
└─────────────────────────────────────────┘
Register Modification Examples:
┌─────────────────────────────────────────┐
│ Set specific register: │
│ 0:000> r eax = 0x12345678 │
│ 0:000> r │
│ eax=12345678 ebx=7ffdf000 ... │
│ │
│ Set using expressions: │
│ 0:000> r eax = @ebx + 100 │
│ 0:000> r ecx = poi(@esp) │
│ 0:000> r edx = @eax * 2 │
│ │
│ Set multiple registers: │
│ 0:000> r eax=0; r ebx=1; r ecx=2 │
│ │
│ Set flags: │
│ 0:000> r zf = 1 │
│ 0:000> r cf = 0 │
└─────────────────────────────────────────┘
Program execution control is fundamental to effective debugging. WinDbg provides comprehensive commands for starting, stopping, and stepping through program execution with precise control over the debugging target.
Execution Control Commands:
┌─────────────────────────────────────────┐
│ Command │ Key │ Action │
├─────────────────────────────────────────┤
│ g │ F5 │ Go (continue execution) │
│ p │ F10 │ Step over │
│ t │ F11 │ Step into (trace) │
│ gu │ │ Go up (step out) │
│ pc │ │ Step to next call │
│ tc │ │ Trace to next call │
│ pt │ │ Step to next return │
│ tt │ │ Trace to next return │
│ pa │ │ Step to address │
│ ta │ │ Trace to address │
└─────────────────────────────────────────┘
Go Command Variations:
┌─────────────────────────────────────────┐
│ Simple continue: │
│ 0:000> g │
│ ; Continue until breakpoint │
│ │
│ Go to specific address: │
│ 0:000> g 0x401234 │
│ ; Continue until EIP = 401234 │
│ │
│ Go with temporary breakpoint: │
│ 0:000> g @eip+0x10 │
│ ; Continue for 16 bytes │
│ │
│ Go until return: │
│ 0:000> g @$ra │
│ ; Continue until function returns│
└─────────────────────────────────────────┘
Software breakpoints are the most common debugging tool, allowing you to pause program execution at specific locations. WinDbg implements software breakpoints by temporarily replacing instructions with interrupt instructions (INT 3, opcode 0xCC).
Breakpoint Command Overview:
┌─────────────────────────────────────────┐
│ Command │ Purpose │
├─────────────────────────────────────────┤
│ bp │ Set breakpoint │
│ bu │ Set unresolved breakpoint │
│ bl │ List breakpoints │
│ bc │ Clear breakpoint │
│ bd │ Disable breakpoint │
│ be │ Enable breakpoint │
│ br │ Rename breakpoint │
└─────────────────────────────────────────┘
Address Breakpoint Examples:
┌─────────────────────────────────────────┐
│ Set by absolute address: │
│ 0:000> bp 0x401234 │
│ │
│ Set by module + offset: │
│ 0:000> bp myapp+0x1234 │
│ │
│ Set by symbol name: │
│ 0:000> bp myapp!main │
│ 0:000> bp kernel32!CreateFileA │
│ │
│ Set by symbol + offset: │
│ 0:000> bp myapp!ProcessData+0x23 │
│ │
│ Set by register expression: │
│ 0:000> bp @eip+0x10 │
└─────────────────────────────────────────┘
Unresolved breakpoints are a special type of breakpoint that can be set on functions or symbols that haven't been loaded yet. They become active when the target module is loaded, making them essential for debugging DLL loading scenarios and delayed-load libraries.
bu Command Syntax:
┌─────────────────────────────────────────┐
│ bu [Options] Address [Commands] │
│ │
│ Key differences from bp: │
│ • Works with unloaded modules │
│ • Resolves when symbols become available│
│ • Useful for DLL entry points │
│ • Handles delayed loading │
│ │
│ Common usage: │
│ bu module!function │
│ bu /1 module!function │
│ bu module!function "commands" │
└─────────────────────────────────────────┘
DLL Breakpoint Examples:
┌─────────────────────────────────────────┐
│ Set breakpoint on DLL function: │
│ 0:000> bu user32!MessageBoxA │
│ │
│ Check breakpoint status: │
│ 0:000> bl │
│ 0 e u 0001 (0001) 0:**** user32!MessageBoxA
│ ^ │
│ └─ 'u' = unresolved │
│ │
│ After DLL loads: │
│ ModLoad: 77d40000 77dd0000 user32.dll │
│ 0:000> bl │
│ 0 e 77d4a567 0001 (0001) 0:**** user32!MessageBoxA
│ ^ │
│ └─ Now resolved │
└─────────────────────────────────────────┘
Breakpoint actions extend the functionality of breakpoints beyond simple execution stopping. They allow for automated data collection, conditional execution, logging, and complex debugging workflows without manual intervention.
Breakpoint Action Syntax:
┌─────────────────────────────────────────┐
│ bp address "action_commands" │
│ │
│ Action Command Categories: │
│ • Display commands (r, dd, da, dt) │
│ • Control flow (g, gc, p, t) │
│ • Conditional logic (.if, .while) │
│ • Logging (.echo, .printf) │
│ • File operations (.logopen, .writemem) │
│ • Script execution ($<, .script) │
│ │
│ Command separators: │
│ • ; = sequential execution │
│ • {} = command grouping │
└─────────────────────────────────────────┘
Data Collection Examples:
┌─────────────────────────────────────────┐
│ Log register state: │
│ 0:000> bp myapp!CriticalFunc "r; g" │
│ │
│ Log specific registers: │
│ 0:000> bp myapp!ProcessData "r eax, ebx, ecx; g"
│ │
│ Log memory contents: │
│ 0:000> bp myapp!ProcessBuffer "dd poi(@esp+4) L8; g"
│ ; Dump buffer parameter │
│ │
│ Log call parameters: │
│ 0:000> bp myapp!FileOperation "dd @esp L4; da poi(@esp+4); g"
│ ; Show stack and filename │
│ │
│ Log structure contents: │
│ 0:000> bp myapp!ProcessStruct "dt MyStruct poi(@esp+4); g"
└─────────────────────────────────────────┘
Hardware breakpoints utilize the CPU's built-in debugging facilities rather than modifying program code. They are implemented using the processor's debug registers and offer unique capabilities not available with software breakpoints.
| Feature | Software Breakpoints | Hardware Breakpoints |
|---|---|---|
| Implementation | Replaces instruction with INT 3 | Uses CPU debug registers |
| Quantity Limit | Unlimited (memory limited) | 4 breakpoints maximum |
| Detection | Can be detected by program | Invisible to target program |
| Memory Access | Execution only | Read, write, execute access |
| Code Modification | Modifies target code | No code modification |
| Performance | Minimal overhead | No runtime overhead |
ba Command Syntax:
┌─────────────────────────────────────────┐
│ ba access size address [options] │
│ │
│ Access types: │
│ • e = execute (instruction fetch) │
│ • r = read (memory read) │
│ • w = write (memory write) │
│ • i = I/O access (port access) │
│ │
│ Size specifiers: │
│ • 1 = 1 byte │
│ • 2 = 2 bytes (word) │
│ • 4 = 4 bytes (dword) │
│ • 8 = 8 bytes (qword, x64 only) │
│ │
│ Examples: │
│ ba w4 0x401000 ; Write 4 bytes │
│ ba r1 @eax ; Read 1 byte at EAX │
│ ba e1 0x401234 ; Execute at address │
└─────────────────────────────────────────┘
Write Access Examples:
┌─────────────────────────────────────────┐
│ Monitor variable modification: │
│ 0:000> ba w4 global_variable │
│ │
│ When variable is written: │
│ Hardware breakpoint 0 hit │
│ 00401234 mov [global_variable], eax │
│ 0:000> r eax │
│ eax=12345678 │ ← New value
│ │
│ Monitor buffer overflow: │
│ 0:000> ba w1 buffer_end │
│ │
│ Monitor structure field: │
│ 0:000> ba w4 mystruct+0x8 │ ← Specific field
└─────────────────────────────────────────┘
Single-step debugging allows precise execution control by executing one instruction at a time. This granular control is essential for understanding program flow, analyzing algorithms, and tracking down subtle bugs.
Stepping Command Reference:
┌─────────────────────────────────────────┐
│ Command │ Key │ Action │
├─────────────────────────────────────────┤
│ t │ F11 │ Trace into │
│ p │ F10 │ Step over │
│ gu │ - │ Go up (step out) │
│ tc │ - │ Trace to call │
│ pc │ - │ Step to call │
│ tt │ - │ Trace to return │
│ pt │ - │ Step to return │
│ ta │ - │ Trace to address │
│ pa │ - │ Step to address │
└─────────────────────────────────────────┘
Trace Into Examples:
┌─────────────────────────────────────────┐
│ Current instruction: │
│ 0:000> u @eip L3 │
│ 00401030 55 push ebp │ ← Current (EIP)
│ 00401031 8bec mov ebp,esp │
│ 00401033 83ec18 sub esp,18h │
│ │
│ Execute one instruction: │
│ 0:000> t │
│ 0:000> u @eip L3 │
│ 00401031 8bec mov ebp,esp │ ← Now here
│ 00401033 83ec18 sub esp,18h │
│ 00401036 c745f80000 mov dword ptr[...]│
│ │
│ Register state after step: │
│ 0:000> r esp, ebp │
│ esp=0012ff7c ebp=0012ff80 │ ← EBP saved
└─────────────────────────────────────────┘
Step Over Examples:
┌─────────────────────────────────────────┐
│ Before function call: │
│ 0:000> u @eip L3 │
│ 00401050 68001040 push offset str │
│ 00401055 e8a6ffffff call 00401000 │ ← Function call
│ 0040105a 83c404 add esp,4 │
│ │
│ Step over the call: │
│ 0:000> p │ ← Execute entire function
│ 0:000> u @eip L3 │
│ 0040105a 83c404 add esp,4 │ ← After function
│ 0040105d 85c0 test eax,eax │
│ 0040105f 7405 je 00401066 │
│ │
│ Function executed but not traced │
│ 0:000> r eax │
│ eax=00000001 │ ← Function return value
└─────────────────────────────────────────┘
Beyond basic debugging operations, WinDbg offers numerous advanced features that enhance debugging productivity and provide specialized analysis capabilities.
WinDbg Extension Categories:
┌─────────────────────────────────────────┐
│ Heap Analysis Extensions: │
│ • !heap - Heap analysis and validation │
│ • !gflag - Global flags manipulation │
│ • !locks - Lock analysis │
│ │
│ Process/Thread Extensions: │
│ • !process - Process information │
│ • !thread - Thread details │
│ • !handle - Handle enumeration │
│ │
│ Memory Extensions: │
│ • !address - Virtual memory info │
│ • !vprot - Memory protection │
│ • !pool - Pool memory analysis │
│ │
│ Analysis Extensions: │
│ • !analyze - Automated crash analysis │
│ • !stack - Stack analysis │
│ • !uniqstack - Unique stack traces │
└─────────────────────────────────────────┘
Heap Analysis Examples:
┌─────────────────────────────────────────┐
│ Show heap summary: │
│ 0:000> !heap -s │
│ Heap at 00080000 │
│ Group-by: TOTSIZE max-display: 20 │
│ size #blocks total (%) │
│ 4c0 - 1 4c0 ( 6.05) │
│ 2f8 - 2 5f0 ( 7.71) │
│ 50 - 32 1000 (20.25) │
│ │
│ Detailed heap analysis: │
│ 0:000> !heap -a 0x00080000 │
│ │
│ Find heap corruption: │
│ 0:000> !heap -x │
│ │
│ Heap entry details: │
│ 0:000> !heap -p -a 0x00081234 │
│ address 00081234 found in │
│ _HEAP @ 80000 │
│ HEAP_ENTRY Size Prev Flags UserPtr UserSize
│ 00081228 0008 0000 [00] 00081234 00000034
└─────────────────────────────────────────┘
Understanding loaded modules and their symbols is crucial for effective debugging. WinDbg provides comprehensive commands for examining module layouts, symbol status, and debugging information.
Module Command Reference:
┌─────────────────────────────────────────┐
│ Command │ Purpose │
├─────────────────────────────────────────┤
│ lm │ List modules (basic) │
│ lmf │ List modules (full info) │
│ lmv │ List modules (verbose) │
│ lmt │ List modules (terse) │
│ lma │ List modules (addresses) │
│ lmu │ List unloaded modules │
│ lmi │ Module information │
└─────────────────────────────────────────┘
Basic Module Listing:
┌─────────────────────────────────────────┐
│ 0:000> lm │
│ start end module name │
│ 00400000 0040f000 myapp (pdb symbols) c:\symbols\myapp.pdb
│ 77f50000 77feb000 ntdll (pdb symbols) c:\symbols\ntdll.pdb
│ 77e60000 77f46000 kernel32 (export symbols) kernel32.dll
│ 77dd0000 77e5e000 advapi32 (no symbols) │
│ 77c10000 77c68000 msvcrt (deferred) │
│ 76390000 763ad000 imm32 (deferred) │
│ │
│ Symbol Status Legend: │
│ • (pdb symbols) - Full debug info │
│ • (export symbols) - Exports only │
│ • (no symbols) - No symbol info │
│ • (deferred) - Not loaded yet │
└─────────────────────────────────────────┘
Symbol Search Examples:
┌─────────────────────────────────────────┐
│ List all symbols in module: │
│ 0:000> x myapp!* │
│ 00401000 myapp!main │
│ 00401234 myapp!ProcessData │
│ 00401567 myapp!CalculateSum │
│ 00401890 myapp!PrintResult │
│ │
│ Search for specific function: │
│ 0:000> x *!CreateFile* │
│ 77e612a4 kernel32!CreateFileA │
│ 77e61567 kernel32!CreateFileW │
│ 77e61890 kernelbase!CreateFileA │
│ │
│ Search with wildcards: │
│ 0:000> x myapp!Process* │
│ 00401234 myapp!ProcessData │
│ 00401567 myapp!ProcessFile │
│ 00401890 myapp!ProcessMessage │
└─────────────────────────────────────────┘
WinDbg includes a powerful expression evaluator that can perform complex calculations, making it an excellent debugging calculator for address arithmetic, size calculations, and data analysis.
Calculator Command Syntax:
┌─────────────────────────────────────────┐
│ ? expression - Evaluate expression│
│ ?? expression - C++ expression │
│ .expr - Expression options│
│ │
│ Basic operators: │
│ + - * / - Arithmetic │
│ % mod - Modulo │
│ << >> - Bit shifts │
│ & | ^ - Bitwise ops │
│ && || - Logical ops │
│ == != < > <= >= - Comparisons │
│ │
│ Number formats: │
│ 0x1234, 1234h - Hexadecimal │
│ 1234, 1234n - Decimal │
│ 1234y - Binary │
│ 1234t - Octal │
└─────────────────────────────────────────┘
Basic Arithmetic Examples:
┌─────────────────────────────────────────┐
│ Simple addition: │
│ 0:000> ? 0x1000 + 0x234 │
│ Evaluate expression: 4660 = 00001234 │
│ │
│ Mixed number formats: │
│ 0:000> ? 100 + 0x64 │
│ Evaluate expression: 200 = 000000c8 │
│ │
│ Address arithmetic: │
│ 0:000> ? @eip + 0x10 │
│ Evaluate expression: 4198448 = 00401030 │
│ │
│ Size calculations: │
│ 0:000> ? 1024 * 1024 │
│ Evaluate expression: 1048576 = 00100000 │
│ │
│ Percentage calculations: │
│ 0:000> ? (50 * 100) / 200 │
│ Evaluate expression: 25 = 00000019 │
└─────────────────────────────────────────┘
WinDbg provides extensive control over how data is displayed, allowing customization of numeric formats, string representations, and structured data presentation. Understanding these formatting options is crucial for effective data analysis.
Numeric Format Specifiers:
┌─────────────────────────────────────────┐
│ Format │ Description │ Example │
├─────────────────────────────────────────┤
│ %d │ Signed decimal │ -123 │
│ %u │ Unsigned decimal │ 4294967173│
│ %x │ Hexadecimal (lower)│ 7b │
│ %X │ Hexadecimal (upper)│ 7B │
│ %o │ Octal │ 173 │
│ %c │ Character │ A │
│ %s │ String │ "hello" │
│ %p │ Pointer │ 0x401000 │
│ %f │ Float │ 3.14159 │
│ %e │ Scientific notation│ 3.14e+00 │
│ %g │ Compact float │ 3.14159 │
└─────────────────────────────────────────┘