首页 > 代码库 > windbg
windbg
http://blog.opensecurityresearch.com/2013/12/getting-started-with-windbg-part-1.html
http://blog.opensecurityresearch.com/2013/12/getting-started-with-windbg-part-2.html
http://blog.opensecurityresearch.com/2013/12/getting-started-with-windbg-part-3.html
Open Security Research
Sponsored by Foundstone
Tuesday, December 17, 2013
Getting Started with WinDBG - Part 1
This is part one of a multipart series, here‘s our outline of whats in store:
- Part 1 - Installation, Interface, Symbols, Remote/Local Debugging, Help, Modules, and Registers
- Part 2 - Breakpoints
- Part 3 - Inspecting Memory, Stepping Through Programs, and General Tips and Tricks
Installation
Microsoft has changed things slightly in WinDBG‘s installation from Windows 7 to Windows 8. In this section we‘ll walk through the install on both.Windows 8
This is basically a thin installer that needs to download WinDBG after you walk through a few screens. The install will ask you if you‘d like to install locally or download the development kit for another computer. The later will be the equivalent of an offline installer, which is my preference so that you can install on other systems easily in the future.
From there just Next your way to the features page and deselect everything but "Debugging Tools for Windows" and click "Download".
Once the installer completes you can navigate to your download directory, which is
c:\Users\Username\Downloads\Windows Kits\8.1\StandaloneSDK
by default, and then next through that install. Then you‘re all ready to go!Windows 7 and Below
For Windows 7 and below, Microsoft offers WinDBG as part of the "Debugging Tools for Windows" package that is included within the Windows SDK and .Net Framework. This requires you to download the online/offline installer, then specifically choose the "Debugging Tools for Windows" install option.My preference is to check the "Debugging Tools" option under "Redistributable Packages" and create a standalone installer which makes future debugging efforts a heck of lot easier. That‘s what I‘ll do here.
Once the installation completes, you‘ll should have the redistributable for various platforms (x86/x64) in the
c:\Program Files\Microsoft SDKs\Windows\v7.1\Redist\Debugging Tools for Windows\
directory.From there the installation is pretty simple, just copy the appropriate redistributable to the system you‘re debugging and then click through the installation.
Interface
The most basic thing about the interface you should know is the Command window. It‘s the default window opened once you‘re attached to a process. The Command window is mostly an output only window, with a small input field on the bottom which you‘ll enter commands into to control WinDBG.
Symbols
WinDBG doesn‘t really need much of a configuration, most things work right out of the box. The one important thing to do is set up Symbols. Symbols are basically special files that are generated with the program binary at compile time that provide debugging information such as function and variable names. This can really help demystify a lot of the functionality of an application when debugging or disassembling. Many Microsoft components are compiled with Symbols which are distributed via the Microsoft Symbol Server. For non-Microsoft binaries, you‘re usually out of luck - sometimes you‘ll find them laying around somewhere but mostly all companies keep that stuff protected.To configure WinDBG to use the Microsoft Symbol server go to
File:Symbol File Path
and set the path appropriately to the one below. The syntax is a little weird, asterisks are the delimiter, so in the value below, we‘ll download symbols to the C:\Symbols
directory. SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
WinDBG will automatically load Symbols for binaries that it has them for when needed. To add a file containing symbols you can just append it to the path:
SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;c:\SomeOtherSymbolFolder
Adding Symbols during Debugging
If you do run into a situation where you have Symbols and would like to import them while the debugging, you can do so via the.sympath
command option within the command window (this requires you to be attached to a process). For instance to append c:\SomeOtherSymbolFolder
you can:0:025> .sympath+ c:\SomeOtherSymbolFolderSymbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;c:\SomeOtherSymbolFolderExpanded Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols;c:\someothersymbolfolder
It‘s always good to reload the symbols after you make changes to the path:
0:025> .reloadReloading current modules...............................................................................................................
Checking Symbols
To view what modules have symbols loaded, you can use thex*!
command. However, WinDBG doesn‘t load Symbols until it needs them so x*!
will show most of the module symbols are deferred. We can force WinDBG to load symbols, with the ld *
command (which may take a little time, you can stop it by going to Debug:Break
):Now we can view the symbols for each for the modules:
Debugging a Local Process
You have a couple options when debugging a local process. You can start the process then attach to it, or have WinDBG launch the process for you. I‘m really sure of all the advantages/disadvantages of each - I know that when you launch a program with WinDBG, it enables some special debugging options (e.g. debug heap) that the program may not like, and it will crash. Additionally, those debugging options alters the code paths in which the programs takes which modifies how things are arranges in memory. That being said, there are also programs that will crash when you attach the debugger, so ymmv. Some applications (malware in particular) will look for the presence of the debugger at launch and may not later on, which would be a reason why you‘d attach. And sometimes you‘re debugging a service that is controlled by Windows which sets up a variety of things during its launch, so to simplify things, you‘d attach rather then launch via the debugger. Some people say there is a significant performance impact when launching a process via the debugger. Test it out yourself, and see what works best for you. If you have any particular reasons why you‘d do one over the other, please let me know the comments!Starting a Process
If you‘re debugging a self contained application that just runs locally and doesn‘t communicate via the network, you may want to have WinDBG start the application. However, that‘s not to say you can‘t attach to these programs after they‘ve been launched.Starting a process is pretty straight forward, go to "File:Open Executable". From there, select the executable you‘d like to debug. You can also provide command line arguments and define the start directory:
Attaching to a Process
Attaching to an already running process is just as simple. Note, that in some cases, you‘ll need to need to spend a little time identifying the true process you‘re looking to target. For instance, some web browsers will create one parent process, then an additional process for each tab. So depending on the crash you‘re debugging, you might want to attach to the tab process rather than the parent.To attach to an already existing process, go to "File:Attach to a Process" then select the PID or process name to attach to. Keep in mind you‘ll also need the appropriate rights to attach to your target process.
If the program has stopped responding, you can noninvasively by using the "Noninvaise" checkbox.
Debugging a Remote Process
Now there may be times where you have to debug a process on a remote system. For instance, it may just be more convenient to use a local debugger rather than one within a VM or via RDP. Or perhaps you are debuggingLoginUI.exe
- which is only available while the system is locked. In these situations you can have a local WinDBG instance running then remotely connect to it. There are a couple ways to do this as well - we‘ll cover two of the most common ways.Existing Debugging Sessions
If you‘ve already started to debug the program locally (via attaching or launching mentioned above) you can use the command input field to have WinDBG launch a listener that a remote debugger can connect to. This is done with the.server
command:.server tcp:port=5005
You‘ll likely get a security alert that you should allow:
Then a positive message within WinDBG telling you the server has started:
0:005> .server tcp:port=5005Server started. Client can connect with any of these command lines0: <debugger> -remote tcp:Port=5005,Server=USER-PC
Then from the remote host, you can connect to the existing debugging session via "File:Connect to a Remote Session":
tcp:Port=5005,Server=192.168.127.138
Once connected you‘ll get a confirmation on remote client:
Microsoft (R) Windows Debugger Version 6.12.0002.633 X86Copyright (c) Microsoft Corporation. All rights reserved.Server started. Client can connect with any of these command lines0: <debugger> -remote tcp:Port=5005,Server=USER-PCMACHINENAME\User (tcp 192.168.127.138:13334) connected at Mon Dec 16 09:03:03 2013
and the locally debugging instance:
MACHINENAME\User (tcp 192.168.127.138:13334) connected at Mon Dec 16 09:03:03 2013
Remote Server
You can also have a standalone WinDBG server running on a system, remotely connect to it, then have the ability to select what process to attach to. This can be done using thedbgsrv.exe
executable on the system where the process is (or will be) running:
dbgsrv.exe -t tcp:port=5005
And you‘ll likely get a Windows Firewall notice, which you should allow:
From the remote system, you can connect by going to "File: Connect to Remote Stub" and defining the server:
tcp:Port=5005,Server=192.168.127.138
You won‘t get any obvious indicator that you‘re connected, but when you go to "File:Attach to a Process", you‘ll see the process list of the system you‘re running
dbgsrv.exe
on. Now you can attach to a process as you normally would as if the process was local.Help
WinDBG‘s help system is awesome. As with all new things, you should become familiar with how to get help on a specific command or concept. From the command input you can use the.hh
command to access WinDBG‘s help:windbg> .hh
You can also use
.hh
on a specific command. For instance, to get more information on the .reload
command, you can use:windbg> .hh .reload
Or just go to "Help:Contents".
Modules
As program runs it pulls in a number of modules that provide functionality - thus if you‘re able to gain insight into what modules are imported by the application, it can help identify what the application does and how it may work. In many scenarios, you‘ll be debugging a particular module loaded by a program, rather than the program executable itself.When you attach to process, WinDBG will automatically list the loaded modules, for instance, here‘s what WinDBG‘s output when I attached to
calc.exe
:Microsoft (R) Windows Debugger Version 6.12.0002.633 X86Copyright (c) Microsoft Corporation. All rights reserved.*** wait with pending attachSymbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbolsExecutable search path is: ModLoad: 00a70000 00b30000 C:\Windows\system32\calc.exeModLoad: 77630000 7776c000 C:\Windows\SYSTEM32\ntdll.dllModLoad: 77550000 77624000 C:\Windows\system32\kernel32.dllModLoad: 75920000 7596a000 C:\Windows\system32\KERNELBASE.dllModLoad: 76410000 77059000 C:\Windows\system32\SHELL32.dllModLoad: 77240000 772ec000 C:\Windows\system32\msvcrt.dllModLoad: 76300000 76357000 C:\Windows\system32\SHLWAPI.dllModLoad: 75cd0000 75d1e000 C:\Windows\system32\GDI32.dllModLoad: 75fa0000 76069000 C:\Windows\system32\USER32.dllModLoad: 777b0000 777ba000 C:\Windows\system32\LPK.dllModLoad: 774b0000 7754d000 C:\Windows\system32\USP10.dllModLoad: 73110000 732a0000 C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7600.16385_none_72fc7cbf861225ca\gdiplus.dllModLoad: 75a80000 75bdc000 C:\Windows\system32\ole32.dllModLoad: 76360000 76401000 C:\Windows\system32\RPCRT4.dllModLoad: 777c0000 77860000 C:\Windows\system32\ADVAPI32.dllModLoad: 75be0000 75bf9000 C:\Windows\SYSTEM32\sechost.dllModLoad: 76270000 762ff000 C:\Windows\system32\OLEAUT32.dllModLoad: 74590000 745d0000 C:\Windows\system32\UxTheme.dllModLoad: 74710000 748ae000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7600.16385_none_421189da2b7fabfc\COMCTL32.dllModLoad: 703d0000 70402000 C:\Windows\system32\WINMM.dllModLoad: 74c80000 74c89000 C:\Windows\system32\VERSION.dllModLoad: 77770000 7778f000 C:\Windows\system32\IMM32.DLLModLoad: 75c00000 75ccc000 C:\Windows\system32\MSCTF.dllModLoad: 74130000 7422b000 C:\Windows\system32\WindowsCodecs.dllModLoad: 74260000 74273000 C:\Windows\system32\dwmapi.dllModLoad: 756d0000 756dc000 C:\Windows\system32\CRYPTBASE.dllModLoad: 75e60000 75ee3000 C:\Windows\system32\CLBCatQ.DLLModLoad: 6ef10000 6ef4c000 C:\Windows\system32\oleacc.dll
Later on in a debugging session you can reproduce these results with the
lmf
command:0:005> lmfstart end module name00a70000 00b30000 calc C:\Windows\system32\calc.exe6ef10000 6ef4c000 oleacc C:\Windows\system32\oleacc.dll703d0000 70402000 WINMM C:\Windows\system32\WINMM.dll73110000 732a0000 gdiplus C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7600.16385_none_72fc7cbf861225ca\gdiplus.dll74130000 7422b000 WindowsCodecs C:\Windows\system32\WindowsCodecs.dll74260000 74273000 dwmapi C:\Windows\system32\dwmapi.dll74590000 745d0000 UxTheme C:\Windows\system32\UxTheme.dll74710000 748ae000 COMCTL32 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7600.16385_none_421189da2b7fabfc\COMCTL32.dll74c80000 74c89000 VERSION C:\Windows\system32\VERSION.dll756d0000 756dc000 CRYPTBASE C:\Windows\system32\CRYPTBASE.dll75920000 7596a000 KERNELBASE C:\Windows\system32\KERNELBASE.dll75a80000 75bdc000 ole32 C:\Windows\system32\ole32.dll75be0000 75bf9000 sechost C:\Windows\SYSTEM32\sechost.dll75c00000 75ccc000 MSCTF C:\Windows\system32\MSCTF.dll75cd0000 75d1e000 GDI32 C:\Windows\system32\GDI32.dll75e60000 75ee3000 CLBCatQ C:\Windows\system32\CLBCatQ.DLL75fa0000 76069000 USER32 C:\Windows\system32\USER32.dll76270000 762ff000 OLEAUT32 C:\Windows\system32\OLEAUT32.dll76300000 76357000 SHLWAPI C:\Windows\system32\SHLWAPI.dll76360000 76401000 RPCRT4 C:\Windows\system32\RPCRT4.dll76410000 77059000 SHELL32 C:\Windows\system32\SHELL32.dll77240000 772ec000 msvcrt C:\Windows\system32\msvcrt.dll774b0000 7754d000 USP10 C:\Windows\system32\USP10.dll77550000 77624000 kernel32 C:\Windows\system32\kernel32.dll77630000 7776c000 ntdll C:\Windows\SYSTEM32\ntdll.dll77770000 7778f000 IMM32 C:\Windows\system32\IMM32.DLL777b0000 777ba000 LPK C:\Windows\system32\LPK.dll777c0000 77860000 ADVAPI32 C:\Windows\system32\ADVAPI32.dll
And you can get the load address for a specific module using the "lmf m" command:
0:005> lmf m kernel32start end module name77550000 77624000 kernel32 C:\Windows\system32\kernel32.dll
To get the image header information you can use the
!dh
extension (the exclamation mark denotes an extension) on a particular module. 0:005> !dh kernel32File Type: DLLFILE HEADER VALUES 14C machine (i386) 4 number of sections4A5BDAAD time date stamp Mon Jul 13 21:09:01 2009 0 file pointer to symbol table 0 number of symbols E0 size of optional header 2102 characteristics Executable 32 bit word machine DLLOPTIONAL HEADER VALUES 10B magic # 9.00 linker version C4600 size of code C800 size of initialized data 0 size of uninitialized data 510C5 address of entry point 1000 base of code ----- new -----77550000 image base 1000 section alignment 200 file alignment 3 subsystem (Windows CUI) 6.01 operating system version 6.01 image version 6.01 subsystem version D4000 size of image 800 size of headers D5597 checksum00040000 size of stack reserve00001000 size of stack commit00100000 size of heap reserve00001000 size of heap commit 140 DLL characteristics Dynamic base NX compatible B4DA8 [ A915] address [size] of Export Directory BF6C0 [ 1F4] address [size] of Import Directory C7000 [ 520] address [size] of Resource Directory 0 [ 0] address [size] of Exception Directory 0 [ 0] address [size] of Security Directory C8000 [ B098] address [size] of Base Relocation Directory C5460 [ 38] address [size] of Debug Directory 0 [ 0] address [size] of Description Directory 0 [ 0] address [size] of Special Directory 0 [ 0] address [size] of Thread Storage Directory 816B8 [ 40] address [size] of Load Configuration Directory 278 [ 408] address [size] of Bound Import Directory 1000 [ DE8] address [size] of Import Address Table Directory 0 [ 0] address [size] of Delay Import Directory 0 [ 0] address [size] of COR20 Header Directory 0 [ 0] address [size] of Reserved DirectorySECTION HEADER #1 .text name C44C1 virtual size 1000 virtual address C4600 size of raw data 800 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers60000020 flags Code (no align specified) Execute ReadDebug Directories(2) Type Size Address Pointer cv 25 c549c c4c9c Format: RSDS, guid, 2, kernel32.pdb ( 10) 4 c5498 c4c98SECTION HEADER #2 .data name FEC virtual size C6000 virtual address E00 size of raw data C4E00 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbersC0000040 flags Initialized Data (no align specified) Read WriteSECTION HEADER #3 .rsrc name 520 virtual size C7000 virtual address 600 size of raw data C5C00 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers40000040 flags Initialized Data (no align specified) Read OnlySECTION HEADER #4 .reloc name B098 virtual size C8000 virtual address B200 size of raw data C6200 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers42000040 flags Initialized Data Discardable (no align specified) Read Only
Messages/Exceptions
When you attach to a process, the modules are displayed first, then WinDBG displays any applicable messages. When we attached tocalc.exe
, WinDBG automatically sets a breakpoint (which is just a marker that tells the debugger uses to pause the execution of a program). So our message is:(da8.b44): Break instruction exception - code 80000003 (first chance)
This particular message is an exception, specifically a first chance exception. An exception is basically some special condition that occurred during the program‘s operation. The first chance means that the progam was paused right after the exception occurred. A second chance exception is when an exception has occurred, some programming logic to handle exception was executed, and the program has paused.
Registers
After the messages/exceptions, the debugger will output the state of the CPU‘s registers. Registers are basically special variables within the CPU that store a small amount of data or keep track of where something is in memory. The CPU can process the data in these registers very quickly, so its faster for the CPU to perform operations on the values in its registers rather then pulling information all the way down the bus from RAM.WinDBG automatically outputted the following registers after we attached to
calc.exe
:eax=7ffd9000 ebx=00000000 ecx=00000000 edx=776cd23d esi=00000000 edi=00000000eip=77663540 esp=02affd9c ebp=02affdc8 iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
Later on down the line, we can reproduce this with the
r
command:0:005> reax=7ffd9000 ebx=00000000 ecx=00000000 edx=776cd23d esi=00000000 edi=00000000eip=77663540 esp=02affd9c ebp=02affdc8 iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246ntdll!DbgBreakPoint:77663540 cc int 3
And if we wanted to just retrieve a value of a specific register, we could by appending the register name:
0:005> r eaxeax=7ffd9000
and multiple registers:
0:005> r eax,ebpeax=7ffd9000 ebp=02affdc8
Instruction Pointer
The final line is instruction to be executed. This is outputted as part of ther
command and is what the EIP register contains. EIP is the instruction pointer, which is the register that contains the location of the next instruction for the CPU to execute. WinDBG‘s output is equivalent of the u eip L1
command that basically tells WinDBG to go to the memory location pointed to by EIP, treat that memory as assembly, and print out one line. ntdll!DbgBreakPoint:77663540 cc int 3
Stay Tuned
In the next blog post we‘ll cover actually using WinDBG :) - breakpoints, stepping, and looking at memory - stay tuned!2 comments:
- AnonymousDecember 20, 2013 at 3:46 AM
Thanks! Love this kind of educational posts!
ReplyDelete - AnonymousDecember 25, 2013 at 12:11 PM
as @Anonymous said i agree about his statement
ReplyDelete
I hope this tut will guide into a deep research
Our Regular Authors
Tony Lee
Gursev Singh Kalra
Robert Portvliet
Melissa Augustine
Paul Ambrosini
Tushar Dalvi
Popular Posts
- Getting Started with GNU Radio and RTL-SDR (on Backtrack)
- Deconstructing a Credit Card‘s Data
- Using Mimikatz to Dump Passwords!
- Windows DLL Injection Basics
- Deobfuscating Potentially Malicious URLs - Part 1
- Comcast and DOCSIS 3.0 - Worth the upgrade?
- Hacking KeyLoggers
- Setting up a Password Cracking Server
- Identifying Malware Traffic with Bro and the Collective Intelligence Framework (CIF)
- Top 10 Oracle Steps to a Secure Oracle Database Server
Blog Archive
- ? 2014(27)
- ? November(1)
- ? September(2)
- ? August(2)
- ? July(2)
- ? June(4)
- ? May(2)
- ? April(4)
- ? March(3)
- ? February(3)
- ? January(4)
- ? 2012(60)
- ? December(3)
- ? November(3)
- ? October(7)
- ? September(4)
- ? August(5)
- ? July(6)
- ? June(4)
- ? May(6)
- ? April(5)
- ? March(5)
- ? February(4)
- ? January(8)
- ? 2011(15)
- ? December(4)
- ? November(7)
- ? October(4)
All content provided here is purely for educational purposes only. Review state and local laws before partaking in any activity. The views and statements here have not been reviewed, approved, or endorsed by Foundstone, McAfee, or Intel.
Open Security Research
Sponsored by Foundstone
Tuesday, December 24, 2013
Getting Started with WinDBG - Part 2
- Part 1 - Installation, Interface, Symbols, Remote/Local Debugging, Help, Modules, and Registers
- Part 2 - Breakpoints
- Part 3 - Inspecting Memory, Stepping Through Programs, and General Tips and Tricks
Breakpoints
Breakpoints are markers associated with a particular memory address that tell the CPU to pause the program. Because programs can contain millions of assembly instructions, manually stepping through each of those instructions would take an incredibly long time. Breakpoints help speed up debugging time by allowing you to set a marker at a specific function which allows the CPU to automatically execute all the code leading up to that point. Once the breakpoint is reached, the program is paused and the debugging can commence.Breakpoints can be set in software and within the CPU (hardware), let‘s take a look at both:
Software Breakpoints
Programs get loaded into memory and executed - which allows us to temporarily modify the memory associated with a program without affecting the actual executable. This is how software breakpoints work. The debugger records the assembly instruction where the breakpoint should be inserted, then silently replaces it with anINT 3
assembly instruction (0xcc
) that tells the CPU to pause execution. When the breakpoint is reached, the debugger looks at the current memory address, fetches the recorded instruction, and presents it to the user. To the user it appears that the program paused on that instruction however the CPU actually had no idea it ever existed. Software breakpoints are set within WinDBG using the
bp
, bm
, or bu
commands. bp
(for Break Point) is arguably the most used breakpoint command. In its most basic use, its only argument is the address at which a breakpoint should be set:0:001> bp 00e61018
With
bp
, the address should be a memory location where executable code exists. While bp
works on locations where data is stored, it can cause issues since the debugger is overwriting the data at that address. To be safe Microsoft suggests that if you want to break on a memory location where data is stored, you should use a different breakpoint command (ba
, discussed below).Let‘s take a look at setting a software breakpoint. Here we‘ll launch
notepad.exe
with WinDBG. By default, when the program is launched with WinDBG, it will insert a breakpoint before the entry point of the program is executed and pause the program. First we‘ll get the location in memory where notepad.exe
is loaded:Next we‘ll determine the program‘s entry point by using
!dh
with the image load address:Now we‘ll set a breakpoint at it‘s entry point (load address + 0x3689):
Finally we‘ll tell the program to run until it encounters a breakpoint using the
g
command (more on this later), when the breakpoint is hit, we‘ll get a notice:Most of your debugging will likely use software breakpoints, however there are certain scenarios (read-only memory locations, breaking on data access, etc..) where you need to use hardware breakpoints.
Hardware Breakpoints
Within most CPUs there are special debug registers that can be used to store the addresses of breakpoints and specific conditions on which the breakpoint should triggered (e.g. read, write, execute). Breakpoints stored here are called hardware (or processor) breakpoints. There is a very finite number of registers (usually 4) which limits the number of total hardware breakpoints that can be set. When the CPU reaches a memory address defined within the debug register and the access conditions are met, the program will pause execution.Hardware breakpoints are set within WinDBG using the
ba
(Break on Access) command. In its most basic usage, it takes 3 attributes:0:001> ba e 1 00453689
This command would (we‘ll see soon why it doesn‘t) accomplish the same thing as the previous
bp
example, however now we‘re setting a hardware breakpoint. The first argument, e
, is the type of memory access to break on (execute), while the second is the size (always 1 for execute access). The final is the address. Let‘s take a look at setting a hardware breakpoint, keep in mind our load addresses are different because of the whole ASLR thing.Due to the way Windows resets thread contexts and the place where WinDBG breaks after spawning a process, we wont be able to set a breakpoint in the same way we did in our earlier example. Previously we set our breakpoint on the program‘s entry point, however if we try to do that with WinDBG we get an error:
0:000> lmf m notepadstart end module name00e60000 00e90000 notepad notepad.exe 0:000> ba e 1 00e63689 ^ Unable to set breakpoint errorThe system resets thread contexts after the processbreakpoint so hardware breakpoints cannot be set.Go to the executable‘s entry point and set it then. ‘ba e 1 00e63689‘
So in order to get around this, we‘ll need to use that
g
command and tell it to run the program until it reaches a specific memory address. This is sort of like setting a software breakpoint in behavior but isn‘t exactly the same. So we‘ll tell WinDBG to execute until we enter the program‘s initial thread context, which will then allow us to set hardware breakpoints.0:000> g 00e63689ModLoad: 76be0000 76bff000 C:\Windows\system32\IMM32.DLLModLoad: 76c00000 76ccc000 C:\Windows\system32\MSCTF.dlleax=77081162 ebx=7ffd7000 ecx=00000000 edx=00e63689 esi=00000000 edi=00000000eip=00e63689 esp=0022fbb4 ebp=0022fbbc iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246notepad!WinMainCRTStartup:00e63689 e8c5f9ffff call notepad!__security_init_cookie (00e63053)
Now we can set our hardware breakpoint:
To confirm we actually set the breakpoint in CPU‘s registers, we can use the
r
command (discussed later). We‘ll use the M
attribute to apply a register mask of 0x20
:0:000> rM 20
You‘ll notice something doesn‘t look right here, all of the registers contain
0
! This is because WinDBG hasn‘t actually set them yet. You can single step (discussed below) with the p
command. Once we do, the dr0
register will have our breakpoint defined:In this specific example, we probably will never hit our breakpoint because it is in the entry point of the program that we‘ve already reached. However if our breakpoint was on a function that was called a variety of times in the life of the program, or on a memory address where an often used variable was stored, we‘d get a "Breakpoint Hit" message when the memory was accessed just as we would with a software breakpoint.
Common Commands
Now that you have the basics of setting breakpoints, there are a handful of other breakpoint related commands that will be useful. Let‘s look at a couple:Viewing Set Breakpoints
To view each of the breakpoints that have been set, you can use thebl
(Breakpoint List) command.0:000> bl 0 e 00523689 e 1 0001 (0001) 0:**** notepad!WinMainCRTStartup
Here we have one breakpoint defined, the entry is broken into a few columns:
0
- Breakpoint IDe
- Breakpoint Status - Can bee
nabled ord
isabled.00523689
- Memory Addresse 1
- Memory address access flags (execute) and size - For hardware breakpoints only0001 (0001)
- Number of times the breakpoint is hit until it becomes active with the total passes in parentheses (this is for a special use case)0:****
- Thread and process information, this defines it is not a thread-specific breakpointnotepad!WinMainCRTStartup
- The corresponding module and function offset associated with the memory address
Deleting Breakpoints
To remove a breakpoint, use thebc
command:0:000> bc 0
The only attribute to
bc
is the Breakpoint ID (learned from bl
). Optionally you can provide *
to delete all breakpoints.Breakpoint Tips
There are a couple simple tips that I commonly use when setting breakpoints. Here are a few of them, please share any you have in the comments below!Calculated Addresses
The simplest breakpoint tip, is just something that you‘ll learn when dealing with memory addresses within WinDBG. You can have WinDBG evaluate expressions to calculate address. For instance, in the above examples, we knew the module load address ofnotepad.exe
and the entry point was at offset 0x3689
. Rather than calculating that address ourselves, we can have WinDBG do it for us:0:000> lmf m notepadstart end module name00770000 007a0000 notepad notepad.exe 0:000> bp 00770000 + 36890:000> bl 0 e 00773689 0001 (0001) 0:**** notepad!WinMainCRTStartup
Name and Offset Addresses
One of the great things about Symbols (covered in part 1 of this post) is that they give us the locations of known functions. So we can use the offsets to those known functions as addresses in our breakpoints. To figure out the offset, we can use theu
(Unassemble) command within WinDBG. u
will take a memory address and interpret the data at that memory address as assembly and display the corresponding mnemonics. As part of its output, u
will also provide the offset to the nearest symbol:0:000> u 00770000 + 3689notepad!WinMainCRTStartup:00773689 e8c5f9ffff call notepad!__security_init_cookie (00773053)0077368e 6a58 push 58h
Now we know that
notepad!WinMainCRTStartup
is a friendly name for 00770000 + 3689
. Since there isn‘t a numeric offset at the end of this friendly name, we can also infer that Symbols exist for this function. Look what happens when we check out the second instruction in this function:0:000> u 0077368e notepad!_initterm_e+0x61:0077368e 6a58 push 58h
This time we got a function name,
notepad!_initterm_e
, plus an offset (+0x61
). I‘m not entirely sure why WinDBG gave the offset to notepad!_initterm_e
instead of notepad!WinMainCRTStartup
, probably a symbol search order thing - nonetheless, we could have used a notepad!WinMainCRTStartup
offset to reference the same location:0:000> u notepad!WinMainCRTStartup+0x5notepad!_initterm_e+0x61:0077368e 6a58 push 58h
The point is that now we can use this offset as a breakpoint and those offsets are always valid even if ASLR is enabled - so we don‘t have to waste time calculating addresses at every launch.
0:000> bp notepad!WinMainCRTStartup+0x50:000> bl 0 e 0077368e 0001 (0001) 0:**** notepad!_initterm_e+0x61
Breaking On Module Load
There may be some occasions when you‘d like to set a breakpoint when a module is being loaded. Unfortunately, there doesn‘t appear to be an obvious way within the standard breakpoint commands to do this (let know if you know of a way in the comments). Instead a sort of "hacky" way to do this is by defining that an exception be raised when a particular module is loaded using thesxe
command:0:000> sxe ld IMM32.DLL
Here we‘ve set up a first chance exception (
sxe
) when a module is loaded (ld
) and defined IMM32.DLL
as the specific module which triggers the exception. We can use
sx
(Set Exceptions) to view the configured exceptions. If we look under the Load Module list, we‘ll see that we have a break on IMM32.DLL
. To clear it we can use the
sxi
(Set Exception Ignore) command:0:000> sxi ld IMM32.DLL
Executing Commands
There may be certain commands that we execute every time a breakpoint is reached. For instance, say we‘re always interested at what values are on the stack. We can automate this with WinDBG by building a list of commands and appending it to our breakpoint. In our example, we‘ll print out some information, and use thedd
command (discussed later) to show the stack. Notice how our command is referenced in the bl
output as well:0:000> bp notepad!WinMainCRTStartup ".echo \"Here are the values on the stack:\n\"; dd esp;"0:000> bl 0 e 00ae3689 0001 (0001) 0:**** notepad!WinMainCRTStartup ".echo \"Here are the values on the stack:\n\"; dd esp;"
Let‘s see what happens when we hit our breakpoint:
As expected, the commands were executed, showing the "
Here are the values on the stack
" message and the stack. Commands are chained together with a semi-colon, and be sure to escape quotes within the outer-most quotes that contain the entire command. You can even append the g
command to have the commands be executed and the program to just continue. This allows you to inspect the state of the program as it runs rather than manually interrupting it every time a breakpoint is hit. Stay Tuned
In our next blog post we‘ll cover inspecting memory and stepping through the program!2 comments:
- vpcea23ennDecember 24, 2013 at 3:52 PM
Thanks a lot for this meaningful insight. Its money!
ReplyDelete
Crisp and very very clear. - AnonymousJanuary 2, 2014 at 9:47 PM
i was really waiting for such tutorialas, i find no execuse to not learn WinDBG by your tutorials, the way you explaining it was amazingly helpful
ReplyDelete
Our Regular Authors
Tony Lee
Gursev Singh Kalra
Robert Portvliet
Melissa Augustine
Paul Ambrosini
Tushar Dalvi
Popular Posts
- Getting Started with GNU Radio and RTL-SDR (on Backtrack)
- Deconstructing a Credit Card‘s Data
- Using Mimikatz to Dump Passwords!
- Windows DLL Injection Basics
- Deobfuscating Potentially Malicious URLs - Part 1
- Comcast and DOCSIS 3.0 - Worth the upgrade?
- Hacking KeyLoggers
- Setting up a Password Cracking Server
- Identifying Malware Traffic with Bro and the Collective Intelligence Framework (CIF)
- Top 10 Oracle Steps to a Secure Oracle Database Server
Blog Archive
- ? 2014(27)
- ? November(1)
- ? September(2)
- ? August(2)
- ? July(2)
- ? June(4)
- ? May(2)
- ? April(4)
- ? March(3)
- ? February(3)
- ? January(4)
- ? 2012(60)
- ? December(3)
- ? November(3)
- ? October(7)
- ? September(4)
- ? August(5)
- ? July(6)
- ? June(4)
- ? May(6)
- ? April(5)
- ? March(5)
- ? February(4)
- ? January(8)
- ? 2011(15)
- ? December(4)
- ? November(7)
- ? October(4)
All content provided here is purely for educational purposes only. Review state and local laws before partaking in any activity. The views and statements here have not been reviewed, approved, or endorsed by Foundstone, McAfee, or Intel.
windbg