windbg - Getting Started with WinDBG - Part 2

2024-05-31 01:58
文章标签 part started windbg getting

本文主要是介绍windbg - Getting Started with WinDBG - Part 2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

This is a multipart series walking you through using WinDBG - we’ve gotten you off the ground with our last blog post, and now we’ll focus on it’s core functionality so that you can start debugging programs!

  • 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 an INT 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:

0:000> lmf m notepad
start    end        module name
006a0000 006d0000   notepad  notepad.exe

Next we’ll determine the program’s entry point by using !dh with the image load address:

0:000> !dh 006a0000File Type: EXECUTABLE IMAGE
FILE HEADER VALUES14C machine (i386)4 number of sections
4A5BC60F time date stamp Mon Jul 13 16:41:03 20090 file pointer to symbol table0 number of symbolsE0 size of optional header102 characteristicsExecutable32 bit word machineOPTIONAL HEADER VALUES10B magic #9.00 linker versionA800 size of code22400 size of initialized data0 size of uninitialized data3689 address of entry point1000 base of code----- new -----
006a0000 image base1000 section alignment200 file alignment2 subsystem (Windows GUI)6.01 operating system version6.01 image version6.01 subsystem version30000 size of image400 size of headers39741 checksum
00040000 size of stack reserve
00011000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit8140  DLL characteristicsDynamic baseNX compatibleTerminal server aware0 [       0] address [size] of Export DirectoryA048 [     12C] address [size] of Import DirectoryF000 [   1F160] address [size] of Resource Directory0 [       0] address [size] of Exception Directory0 [       0] address [size] of Security Directory2F000 [     E34] address [size] of Base Relocation DirectoryB62C [      38] address [size] of Debug Directory0 [       0] address [size] of Description Directory0 [       0] address [size] of Special Directory0 [       0] address [size] of Thread Storage Directory6D58 [      40] address [size] of Load Configuration Directory278 [     128] address [size] of Bound Import Directory1000 [     400] address [size] of Import Address Table Directory0 [       0] address [size] of Delay Import Directory0 [       0] address [size] of COR20 Header Directory0 [       0] address [size] of Reserved DirectorySECTION HEADER #1.text nameA68C virtual size1000 virtual addressA800 size of raw data400 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
60000020 flagsCode(no align specified)Execute ReadDebug Directories(2)Type       Size     Address  Pointercv           24        b668     aa68    Format: RSDS, guid, 2, notepad.pdb(    10)       4        b664     aa64SECTION HEADER #2.data name2164 virtual sizeC000 virtual address1000 size of raw dataAC00 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
C0000040 flagsInitialized Data(no align specified)Read WriteSECTION HEADER #3.rsrc name1F160 virtual sizeF000 virtual address1F200 size of raw dataBC00 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
40000040 flagsInitialized Data(no align specified)Read OnlySECTION HEADER #4.reloc nameE34 virtual size2F000 virtual address1000 size of raw data2AE00 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
42000040 flagsInitialized DataDiscardable(no align specified)Read Only

Now we’ll set a breakpoint at it’s entry point (load address + 0x3689):

0:000> bp 6a3689
0:000> bl0 e 006a3689     0001 (0001)  0:**** notepad+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:

1:001> g
ModLoad: 76f90000 76faf000   C:\Windows\system32\IMM32.DLL
ModLoad: 75900000 759cc000   C:\Windows\system32\MSCTF.dll
Breakpoint 0 hit
eax=77143c33 ebx=7ffdb000 ecx=00000000 edx=006a3689 esi=00000000 edi=00000000
eip=006a3689 esp=0011fac0 ebp=0011fac8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
notepad+0x3689:
006a3689 e8c5f9ffff      call    notepad+0x3053 (006a3053)

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> ba e 1 006a3689^ Unable to set breakpoint error
The system resets thread contexts after the process
breakpoint so hardware breakpoints cannot be set.
Go to the executable's entry point and set it then.'ba e 1 006a3689'

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 006a3689
ModLoad: 76f90000 76faf000   C:\Windows\system32\IMM32.DLL
ModLoad: 75900000 759cc000   C:\Windows\system32\MSCTF.dll
*** ERROR: Module load completed but symbols could not be loaded for notepad.exe
eax=77143c33 ebx=7ffdf000 ecx=00000000 edx=006a3689 esi=00000000 edi=00000000
eip=006a3689 esp=0013fbe0 ebp=0013fbe8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
notepad+0x3689:
006a3689 e8c5f9ffff      call    notepad+0x3053 (006a3053)
0:000> ba e 1 006a3689

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
dr0=00000000 dr1=00000000 dr2=00000000
dr3=00000000 dr6=00000000 dr7=00000000
notepad+0x3689:
006a3689 e8c5f9ffff      call    notepad+0x3053 (006a3053)

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 the bl (Breakpoint List) command.

0:000> bl0 e 006a3689 e 1 0001 (0001)  0:**** notepad+0x3689

Here we have one breakpoint defined, the entry is broken into a few columns:

  • 0 - Breakpoint ID
  • e - Breakpoint Status - Can be enabled or disabled.
  • 006a3689 - Memory Address
  • e 1 - Memory address access flags (execute) and size - For hardware breakpoints only
  • 0001 (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 breakpoint
  • notepad+0x3689 - The corresponding module and function offset associated with the memory address

Deleting Breakpoints

To remove a breakpoint, use the bc 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 of notepad.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 notepad
start    end        module name
006a0000 006d0000   notepad  notepad.exe 
0:000> bp 006a0000 + 3689
0:000> bl0 e 006a3689     0001 (0001)  0:**** notepad+0x3689

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 the u (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 006a0000 + 3689
notepad+0x3689:
006a3689 e8c5f9ffff      call    notepad+0x3053 (006a3053)
006a368e 6a58            push    58h
006a3690 68a0376a00      push    offset notepad+0x37a0 (006a37a0)
006a3695 e872040000      call    notepad+0x3b0c (006a3b0c)
006a369a 33db            xor     ebx,ebx
006a369c 895de4          mov     dword ptr [ebp-1Ch],ebx
006a369f 895dfc          mov     dword ptr [ebp-4],ebx
006a36a2 8d4598          lea     eax,[ebp-68h]

Now we know that notepad!WinMainCRTStartup is a friendly name for 006a0000 + 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 006a368e 
notepad!_initterm_e+0x61:
006a368e 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+0x5
notepad!_initterm_e+0x61:
006a368e 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+0x5
0:000> bl0 e 006a368e     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 the sxe 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 the dd 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!


References

http://blog.opensecurityresearch.com/2013/12/getting-started-with-windbg-part-2.html

这篇关于windbg - Getting Started with WinDBG - Part 2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017228

相关文章

VirtualKD 双机调试 Win10 无法弹出 Windbg 解决方法

虚拟机里 msconfig -> 引导 -> VirtualKD启动项 -> 高级选项 -> 调试端口,将 1394 改成 com1 感谢群友 @Neil_360 提供的解决方法   Windbg 无法接收打印的信息 进入注册表 在 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\ 路径下

zabbix出现active check configuration update from [127.0.0.1:10051] started to fail (cannot connect to

出现active check configuration update from [127.0.0.1:10051] started to fail (cannot connect to [[127.0.0.1]:10051]: [111] Connection refused),直接编辑zabbix_agentd.conf(vi /usr/local/zabbix/etc/zabbix_agen

SharePoint At Work----SharePoint Data View Web Part

添加DVWP(数据视图Web部件) 1. SharePoint Designer中打开页面,光标放置在要添加DVWP的地方。建议使用拆分模式。 2. 插入----数据视图----空白数据视图。         如果你选择了某个列表或库,你将得到一个XLV而不是DVWP。         你将看到页面上你的DVWP。现在你只有DVWP的外壳,它声明其主要特征。典型的外壳可能

使用Visual Studio 创建新的Web Part项目

使用Visual Studio 创建新的Web Part项目 Web Part是你将为SharePoint创建的最常见的对象之一。它是平台构建的核心基块。 1. 管理员身份打开Visual Studio,新建空白SharePoint项目。命名WroxSPProject,点击确定。部署为场解决方案,点击完成。 2. 右击选择添加新项目Web Part,命名SimpleWebPart,点

使用程序创建自定义Web部件Web Part

使用程序创建自定义Web部件Web Part 使用VS2010你可以通过程序创建自定义Web部件。 1. 以管理员身份打开VS2010.新建项目----空白SharePoint项目。命名MyFirstWebPart,点击确定。 2. 部署为场解决方案。 3. 右击项目添加新项目---Web Part。命名MyFirstWebPart。 4. 查看Web part代码文件,

计算机视觉实验二:基于支持向量机和随机森林的分类(Part two: 编程实现基于随机森林的泰坦尼克号人员生存与否分类)

目录 一、实验内容 二、实验目的 三、实验步骤 四、实验结果截图 五、实验完整代码 一、实验内容         编程实现基于随机森林的泰坦尼克号人员生存与否分类,基本功能包括:Titanic - Machine Learning from Disaster数据集的下载;数值型数据和文本型数据的筛查、舍弃、合并、补充;随机森林的人员生存与否分类。 二、实验目的

Part 6.2.3 欧拉函数

欧拉函数φ(x) 表示了小于x的数字中,与x互质的数字个数。 关于欧拉函数的基本知识>欧拉函数的求解< [SDOI2008] 仪仗队 题目描述 作为体育委员,C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N × N N \times N N×N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,

Part 4.3 区间动态规划

[NOI1995] 石子合并 题目描述 在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。 输入格式 数据的第 1 1 1 行是正整数 N N N,表示有 N N

【Hadoop】Flume NG Getting Started(Flume NG 新手入门指南)翻译

新手入门 Flume NG是什么? 有什么改变? 获得Flume NG 从源码构建 配置 flume-ng全局选项flume-ng agent选项flume-ng avro-client 选项 提供反馈 Flume NG是什么? Flume NG的目标是比Flume OG在简单性,大小和容易部署上有显著性地提高。为了实现这个目标,Flume NG将不会兼容Flume OG.我们目

计算机视觉实验二:基于支持向量机和随机森林的分类(Part one: 编程实现基于支持向量机的人脸识别分类 )

目录 一、实验内容 二、实验目的 三、实验步骤 四、实验结果截图 五、实验完整代码  六、报错及解决方案         PS:实验的运行速度受电脑性能影响,如遇运行卡顿请耐心等待。 一、实验内容          编程实现基于支持向量机的人脸识别分类,基本功能包括:Labeled Faces in the Wild数据集的下载;人脸图像的定位和降维;支持向量机的图像分类。