Getting started with WinDbg

I’m anxious of unknowns. Seriously. Whenever I’m faced with something that is new and unknown, especially if it’s work related, my brain will try running away screaming in anxiety. Like so:

My brain when faced with an unknown and scary thing

Suffice to say, WinDbg was absolutely one of those things that I’ve never, ever in my life even considered opening. No sir. Nope. I’ll stick to my fancy pants IDEs and I’ll leave those old and scary things for … you know … old and crazy people? Except, the problem is, I guess I qualified to become one of those “old” and possibly crazy, so … yeah.

The thing is, I actually used to imagine WinDbg looking like this:

Scary, right? And definitely not user-friendly. So I avoided it. Because, for one, it was scary. And for two, I had no idea how to use it. And on top of that, the commands look sketchy and scary. Just look at this one: dx -r1 (nt!_EPROCESS*)((nt!PsGetCurrentProcess()) + 0x2F8) and tell me you’ll sleep calmly tonight. Right …

The truth is, WinDbg actually looks like this:

Much cooler and friendlier, right?

Now that we got the scary looking UI out of the way, the obvious next step is getting it down to your computer.

Downloading WinDbg

The simplest way is to just get it from Microsoft’s official page – Install the Windows debugger.

Alternatively, you might want to explore the Debugging Tools for Windows, as it has number of useful tools and resources listed there. BTW, don’t get scared if you’re unfamiliar with terms like KD, NTKD, CBD, Symbols and PDB files. It’s actually quite simple and I’ll cover those later as well.

Basic interactions

When it comes to myself, pretty much everything becomes way less scary when I see someone else doing it. So I’ll assume you are like me, and I’ll show you how to interact with commonly used features.

Probably the simplest thing you could do is to launch Notepad and then attach to it. Here’s how that works:

And after you double-click on Notepad.exe, you’ll see something like this:

Exciting as it looks, I understand that this might scare people off. But scared be not, it’s actually really cool (and powerful!) once you get used to it.

WinDbg is more chatty

WinDbg is basically made with one purpose – to be a debugger. A good one. And although I’m not the best person to judge, I did hear that it’s absolutely THE BEST Windows debugger out there.

Good news is that if you have your source files, it can definitely give you that look and feel of your day-to-day IDE:

Screenshot of debugging an app that I have source files for

It shows source code without issues and if you observe the upper left corner, there are your typical “Step Into”, “Step over”, “Go”, “Break”, etc. And if you click around various tabs, like “View”, “Breakpoints”, “Time travel” (amazing feature btw!), etc. you’ll find quite some cool stuff there. But again, it is my personal impression that the true power of WinDbg lies in the commands that you can execute, so I’ll focus on those.

For starters, WinDbg likes to share way more than your typical IDE. Just observe the “Command window”, the one you will get well acquainted with, and you’ll see it shows tons of stuff; quite powerful stuff, actually.

Anyway, let’s discuss some basic commands now.

The basic commands

Yeah, I know. If you were used to fancy IDEs, you might find WinDbg’s command cryptic at first. Hell, there are like four different commands to set a breakpont: bp, bu, bm, ba. The truth is – they are EXTREMELY POWERFUL but we’ll get to that.

One cool thing is that each command basically is abbreviation of what it does. Let me go over the breakpoint-related ones:

  • bp –> shorthand for “break point”. You give it an address and it ensures you get debugger break once you hit it. E.g.: bp MyApp!main would set a breakpoint on, you know, main function in MyApp module.
  • bu –> shorthand for “break on unresolved” is a cool one. Basically it lets you set a breakpoint on something that might have not been loaded yet. E.g. bu ModuleToBeLoadedLaterOn!FunctionName.
  • bm –> shorthand for “breakpoint on symbol” is another cool one that lets you use wildcards. E.g.: bm MyApp!* would basically break on every function in MyApp. It’s cool!
  • ba –> shorthand for “break on access” allows you to break into debugger whenever a specific memory address is accessed. It even allows you to specify a memory range (up to 4 bytes I think), so that can be useful as wel!

As you can see, anything starting with “b” is for breakpoints. And this general rule follows all commands basically. Here are some other useful ones from top of my head:

  • lm –> display list of Loaded Modules. Useful in combination with “x”.
  • x –> shorthand for “Examine Symbols” although I prefer to think of it as “eXports”. Probably one of the coolest commands I’ve interacted with. I’ll share some examples below.
  • g –> shorthand for “Go”. Resumes execution of all threads (same as clicking the green “Go” button in the top of the window).
  • p –> execute a single Step (i.e. execute single instruction)
  • n –> increases Suspend Counter for current thread. This is useful if you want to, say, suspend just one thread but let all others work.
  • m –> decreases Suspend Counter for current thread.
  • wt –> Trace and Watch data. Allows you to execute specific function and have WinDbg log all inner-functions that it executes. Pretty useful!
  • .cls –> Clear the Screen. You definitely want to remember this one.

Finally, there are bunch of “d” commands, where “d” stands for “display”. E.g. “db” would display bytes from specific location, whereas “dt” is for “Display Type” and “dv” for “Display Value”. There’s literally TONS of them so you’ll eventually get familiar.

Anyway, there are lots of commands really and I just listed the basic and likely most commonly used ones. The cool thing is that all commands are shorthand for what they do, so even though they might look scary, they are actually quite useful.

Here are some first-hand examples:

“lm” shows list of loaded modules, along with the addresses where they are located
“x” shows list of all symbols in specific module. You can use wildcards as well which is VERY useful.
“bp” sets a breakpoint at specific address, whereas “bl” lists the breakpoints
You can also see the breakpoint in the source code as well
Executing “wt -l 2” will show all the functions (up to depth of 2) that were executed as part of it. In this case you can see bunch of stuff being executed when GetAddrInfo() is executed

“dv [variableName]” will display the value contained in it, whereas “k” shows a Call Stack

Anyway, you get the idea I hope 🙂

Few words about Symbols and PDB files

Your EXE and DLL files generally expose only the bare minimum of information, mostly because it makes them smaller. Embedding additional data that would help with debugging only makes sense if you want to, you know, debug stuff.

Without going into too many details (which you can read here if you’re interested), in order to make any sense out of the code stored in your EXE/DLL, you usually need Symbol files (i.e. PDB files). PDB files (shorthand for Program Database) are created during compilation time and they store the mappings between machine code and functions, variables, source files, etc. Simply put, Symbol files allow you to see actual function names, observe variables and basically do anything useful aside from looking at disassembled instructions.

Cool thing is that Microsoft has tons of publicly available symbols. They don’t go into the depth and variable names, but they are pretty sufficient to be able to navigate around pretty much anything. Here’s an example from notepad.exe again. I basically launched it through WinDbg and here’s what you can observe:

As you can see, WinDbg pulled PDBs for “notepad” and “ntdll”. Let’s examine them:

There are LOTS of functions, all coming from https://msdl.microsoft.com/download/symbols. And WinDbg knows how to read stuff from there, so you’re pretty well equipped to start exploring your favorite apps and see how they interact.

As for the apps that you are developing locally, WinDbg usually knows how to find the symbols and source files, so you’re covered there:

Observe that it says “private” pdb symbols next to GetAddrInfo, which is an app that I was testing something with
Executing “x GetAddrInfo!*main*” shows some methods as clickable. Clicking on them would lead me to source code

“Stop debugging” vs “Detach”

This is a short one but worth mentioning because it generally tends to confuse newcomers. If you click on “Stop debugging” you will effectively stop the process as well. However, if you want to disconnect the Debugger without stopping the debuggee, what you want to click is “Detach” (or type “.detach” in Command window).

cdb, kd, ntkd and ntsd

As if things weren’t scary enough with WinDbg alone, now you get to learn about these crypting other debuggers, all part of the same package. Truth is, it’s actually way simpler than it sounds, but I guess I’ve been saying that way too often now.

My understanding (so far at least) is that you have a SINGLE debugging engine (which I believe is stored in DbgEng.dll) and then various debuggers built around it. But the core is the same. And that’s important for this, because, what these fellas stand for are:

  • cdb stands for “console debugger”. It’s basically a WinDbg made for Console. Quite useful if you don’t have UI (e.g. in Containers)
  • kd stands for “Kernel Debugger”. Even though WinDbg can work both as User-mode and Kernel-mode debugger, kd is made specifically for debugging kernel. Given that it’s probably topic on its own, I’ll leave you at that.
  • ntkad and ntsd are, at least per official documentation, exect same things as “cdb” and “kd”, except that they just spawn a new window when they start.

But the gist of it is that they are more or less the same thing, with same command set, built for different purposes. Learn to use one and you’ll know how to use all of them 🙂

Where to learn more

One of the best resources I found is the official Microsoft docs at: https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/standard-debugging-techniques. There are tons of articles on both Standard and Advanced Debugging Techniques, so I’d suggest checking those out.

Another literal gem is Tim Misiak’s “Writing a Debugger From Scratch” series at https://www.timdbg.com/. Tim worked in WinDbg team for years and has quite a few things to say on the topic of debuggers.

Here’s also a list of blog posts I came accross and that I found useful so you might be interested in checking them as well:

One thought on “Getting started with WinDbg

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top