MindshaRE is our weekly look at some simple reverse engineering tips and tricks. The goal is to keep things small and discuss every day aspects of reversing. You can view previous entries here by going through our blog history.
The debugger is used to control a process, that much is obvious. The key to being effective while debugging is to know what your ultimate goal is. When you clearly understand what task you are trying to achieve you can issue the appropriate commands to get there. Most people lose focus because they are caught up in how to move around inside of their favorite debugger. The confusion normally occurs when trying to figure out how to do certain tasks, or their debugger UI may not be optimal.
You must have a comfortable UI layout. This allows you to easily see all the information you may need like registers, disassembly, memory, etc. I seem to differ from everyone else. In my WinDbg UI I only have the command window. Here, look how plain it is.
The norm seems to be several windows open with register views, memory views, disassembly, etc. I purposely do not do this so I can stay focused. I realized when I had multiple windows up that I was not paying attention to what I needed to do. With one window I can keep my mind on track. Through the command line window I can access information, view registers, search memory, and anything else I may need. It makes me consciously ask "ok I need x information, lets get that". This has proved successful for myself, but like I stated, its all preference.
Spending a few minutes, or even hours, finding your sweet spot can help you in the long run. All of the debuggers can save settings, and window layouts for future debugging sessions. Once you get a comfortable layout you can move on.
This post is only focused on WinDbg, but each section has equivalent commands in other debuggers. If you prefer one of those others try and find the equivalent commands and learn them. I am obviously not going to cover everything WinDbg can do. For that check out the .hlp that comes with the package, or check out the book "Advanced Windows Debugging" if you are looking for something more challenging.
We need to start somewhere, so lets look at a few of the commands to attach and load.
F6 - Attach to a process, dialog can be sorted
by pid or name
Ctrl-E - Load an executableBe mindful when opening an executable, the arguments are in the same window as the browse dialog. On many occasions I go to fast and forget to set my arguments. When you first attach or start a process you will hit the initial breakpoint. This BP allows you to set up any additional breakpoints, or other exception handling.
In WinDbg we can control several events we may be interested in.
sxe - Enable an event breakpoint
sxd - Disable an event breakpoint
sxe ld - Enable break on module load
sxe ct - Enable break on thread creationSetting event breakpoints is very helpful when you have a library loading dynamically, or a specific thread that may be of interest. When doing malware analysis breaking on thread creation and library loading is extremely useful.
On of the most common things we will do is set up breakpoints. WinDbg provides a myriad of options for breaking into a process, here are a few.
Ctrl-Brk - Break into target process
bp - Set a breakpoint at specified address
bp <condition> - Set a breakpoint at specified address when
it satisfies a condition
bl - List breakpoints
bd - Disable a breakpoint
bc - Clear a breakpoint, or all breakpoints
be - Enable a breakpoint
ba - Break on memory access (r/w/e)
bu - Set a breakpoint on an unresolved address
bm - Set a breakpoint by symbol name, also useful
for setting wild card bps
So we can break anywhere in the process. Here are some ways to execute after you have hit a breakpoint.
g - Go, or continue the current process
gu - Go up, continue until return
t - Trace, stepping into calls
p - Step, stepping over calls
ta - Trace to address, display all executed
instructions until address
pa - Step to address, skipping all calls
pc - Step to next call
tc - Trace to next call
ph - Step to next branch (call, j**, ret)Using the execute until commands is always helpful when you want to skip code. For instance when you step into a function and want to quickly move to the return. Having multiple commands to jump around a process helps us stay focused cutting away any cruft that may not be of interest.
Lastly lets look at inspecting and changing data. The most common of these is your register state. If your WinDbg is set up like mine the registers will be printed at each step, or breakpoint. They are ordered like so.
(8a8.8f4): Break instruction exception - code 80000003 (first chance)
eax=7ffdd000 ebx=00000001 ecx=00000002 edx=00000003 esi=00000004 edi=00000005
eip=7c90120e esp=0092ffcc ebp=0092fff4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
ntdll!DbgBreakPoint:
7c90120e cc int 3You can easily modify registers using the same command to list them.
r - Display registers and EIP disassembly
r eax=0x10 - Write value into specified registerThe ordered listing of registers in WinDbg may appear convoluted but you quickly get accustomed. As you can see we also see the current disassembly at EIP. Here are a few commands to do this on any address.
u - Unassemble current EIP or specified
address
uf - Unassemble function, displays allAnd finally we can dump and edit memory locations with ease.
instructions in function
db - Dump data at address in bytes
dd - Dump data at address in dwords
dc - Dump data at address in dwords and ascii
da - Dump data at address in ascii
s - Search memory for specified data type
eb - Edit address as byte
ed - Edit address as dwordWell there you go, a few (there are hundreds) of WinDbg commands to get you going. Hopefully you can learn these to aide in your next debugging adventure. One of the best things about WinDbg is its extensive command support. Take a look at the .hlp and various other resources on the net.
-Cody

