使用调试器脚本增强断点

摘要:
LONGWINAPIRegOpenKeyEx;2、创建调试器脚本脚本逻辑是直截了当的。每次调用RegOpenKeyEx()时,调试器脚本都会中断。由于RegOpenKeyEx()的第二个参数是通过esp+8传递的,因此我们的调试器命令程序将取消对esp+8的引用,并将其移到r$t0中。这相当于在调试器中键入'g'。如果在屏幕上发现了字符串,并且调试器中的字符串仍被打印出来。RegOpenKeyExW上设置一个断点指示它使用我们的脚本来评估SYSTEMSetup是否是在第二个参数处传入的键。

最近要求我在升级过程中跟踪一个问题。问题归结为在安装过程中捕获打开特定注册表服务项的Microsoft组件。像这样的问题经常需要实时调试来实时捕获注册表访问。我本可以在RegOpenKeyExW()上设置一个断点,并检查传递到函数中的每个请求的键,但是考虑到RegOpenKeyExW()是一个使用率很高的代码路径,所以这个方法非常耗时。此方法包括在函数上设置断点,等待插入,检查第二个参数(lpSubKey)是否与所需的注册表项(string)匹配,如果该项不匹配,则单击“g”。在找到包含我所需密钥的调用之前,我可以重复这些步骤100次。我想找个办法,只有在我的Key被碰过的时候才会设置“中断访问”。我们遇到了一个类似的问题,需要在可能有数百个文件正在使用时捕获文件系统函数处理特定文件。那么,如何实现这种类型的调试所需的自动化呢?答案是调试器脚本。

让我们来看看Windows的一个例子资源管理器使用这种方法。在这个场景中,我们将尝试捕捉资源管理器正在打开HKEY U LOCAL U MACHINESYSTEMSetup键。Windows资源管理器每秒打开多个键,因此重点是在将此特定键传递给RegOpenKeyEx()时“插入”,而不必手动遍历传递给函数的数百个可能的键。

1、确定有问题的函数

根据MSDN,RegOpenKeyEx定义如下,我们对第二个参数感兴趣,因为它包含键的名称。
LONG WINAPI RegOpenKeyEx(

  __in HKEY hKey,

  __in_opt LPCTSTR lpSubKey,

  __reserved DWORD ulOptions,

  __in REGSAM samDesired,

  __out PHKEY phkResult

);

2、创建调试器脚本

脚本逻辑是直截了当的。每次调用RegOpenKeyEx()时,调试器脚本都会中断。然后检查字符串SYSTEMSetup的第二个参数。如果找到匹配项,它将保持中断状态,否则将向运行线程返回命令。我们的剧本应该是这样的

r$t0=poi(esp+8)

.if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

.if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo _str }

r$t0被认为是一个伪寄存器,在这个脚本中用作变量。由于RegOpenKeyEx()的第二个参数是通过esp+8传递的,因此我们的调试器命令程序将取消对esp+8的引用,并将其移到r$t0中。现在保存lpSubKey内存地址到pseudo-register。程序的第二行简单地检查r$t0是否为NULL,如果r$t0不为NULL,则将在r$t0中保存的地址设置名为_str的别名。第三行使用MASM string运算符$spat查找与systemsetup匹配的字符串模式。如果找不到匹配项,它将打印字符串,并将命令返回给执行线程。这相当于在调试器中键入'g'。如果在屏幕上发现了字符串,并且调试器中的字符串仍被打印出来。然后我们可以在适当的上下文中调试底层问题。现在将它们保存到位于c:debuggersstrings.txt,所以我们可以从断点引用它。

3、设置断点

下一步,我们从内核调试器进入资源管理器进程

kd> !process 0 0Explorer.exe

PROCESS 8340d6a8 SessionId: 1 Cid: 0270Peb: 7ffd5000 ParentCid: 01b0

    DirBase: 2d48f000 ObjectTable: 90171348 HandleCount: 559.

    Image: explorer.exe

kd> !bpid 0270
Finding wininit.exe (1)...

Finding winlogon.exe (1)...

Waiting forwinlogon.exe to break. This can take a couple of minutes...

Break instruction exception - code 80000003(first chance)

Break into process 270 set. The next break should be inthe desired process.

Break instruction exception - code 80000003(first chance)

ntdll!DbgBreakPoint:

77f17dfe cc int 3

然后我们在ADVAPI32!RegOpenKeyExW上设置一个断点指示它使用我们的脚本来评估SYSTEMSetup是否是在第二个参数处传入的键。如果它找到一个匹配我们的键,它将保持中断状态,否则执行将被传递回正在运行的资源管理器线程。

kd> bp ADVAPI32!RegOpenKeyExW "$$<c:\debuggers\strings.txt"
kd>bl

0 e 76e8f09d 0001 (0001) ADVAPI32!RegOpenKeyExW "$$<c:debuggersstrings.txt"

下面是所有不匹配项的输出。

kd>g

kd> r$t0=poi(esp+8)

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SystemCurrentControlSetServicesDnsCacheParameters

kd> r$t0=poi(esp+8)

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SoftwarePoliciesMicrosoftWindows NTDnsClient

为了节省博客空间,这里删除了几个条目

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SystemCurrentControlSetServicesDnsCacheParameters

kd> r$t0=poi(esp+8)

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SoftwarePoliciesMicrosoftWindows NTDnsClient

kd> r$t0=poi(esp+8)

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SystemCurrentControlSetServicesDNS

kd> r$t0=poi(esp+8)

kd> .if (@$t0 != 0) { as /mu ${/v:_str} @$t0 } .else { ad /q ${/v:_str} }

kd> .if ($spat("${_str}x", "*systemSetup*") == 0) { .echo _str;g } .else { .echo_str }

SystemSetup

ADVAPI32!RegOpenKeyExW:

76e8f09d 8bff mov edi,edi

答对 了!它检测到SystemSetup传入的字符串,并保持中断状态,允许我们开始任何必要的调试。

kd>kv

ChildEBP RetAddr Args to Child

077aeae0 760dfb75 80000002 760dfb94 00000000 ADVAPI32!RegOpenKeyExW (FPO: [Non-Fpo])

WARNING: Frame IP not inany known module. Following frames may be wrong.

077aed18 760dfbb7 00000004 00000000 0000003a 0x760dfb75
077aee20 7678c1b2 00000000 00000000 00000000 0x760dfbb7
077aee24 00000000 00000000 00000000 00000000 kernel32!WaitForSingleObject+0x12 (FPO: [Non-Fpo])

kd>dc 760dfb94

760dfb94 00790053 00740073006d0065 0053005c S.y.s.t.e.m..S.

760dfba4 00740065 00700075ff530000 4ce81075 e.t.u.p...S.u..L

760dfbb4 8bffffff 0ffb3bf8 0032c284 89fb3b00 .....;....2..;..

760dfbc4 840ff47d 0000012b f875ff56 013ee857 }...+...V.u.W.>.

760dfbd4 f08b0000 840ff33b 000000f2 0000c3e9 ....;...........

760dfbe4 90909000ff8b9090 83ec8b55 458b1cec ........U......E

760dfbf4 db335308 fc458956 e8f45d89 fffff583 .S3.V.E..]......

760dfc04 ff18758b 1e891475 fff5a9e8 89c33bff .u..u........;..

调试器脚本是另一个很酷的工具,可以添加到调试库中。我个人已经多次从这种类型的脚本中受益。再次检查调试器帮助文件以获取有关可用命令的详细信息。

免责声明:文章转载自《使用调试器脚本增强断点》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇自古逢秋悲寂寥,奈何今秋热成雕?Python使用Pyecharts统计全国温度Top10并绘图缓存DataSet以提高性能下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

关于远程调试

1.为什么要用远程调试? 1.本地环境与远程环境为不一致,线上线下数据的不一致,导致有些问题没办法在本地复现。仅靠本地调试无法直接定位问题。 2.本地调试一般有三种方法,一是写测试用例,二是在swagger上测试,需要造数据,比较麻烦。三是通过前端请求打到后端,但这种方法请求会随机打到本机和Dev环境的机器,需要禁用Dev的机器,有可能影响其他人开发。尤...

掌握VS2010调试 -- 入门指南

Reference from : http://blog.csdn.net/kingzone_2008/article/details/8133048 1 导言 在软件开发周期中,测试和修正缺陷(defect,defect与bug的区别:Bug是缺陷的一种表现形式,而一个缺陷是可以引起多种Bug的)的时间远多于写代码的时间。通常,debug是指发现缺陷并改...

使用vs自带的性能诊断工具

visual studio是个强大的集成开发环境,内置了程序性能诊断工具。下面通过两段代码进行介绍。 static void Main( string[] args) { Test1(); Test2(); Console.ReadKey();...

python2/3中 将base64数据写成图片,并将图片数据转为16进制数据的方法、bytes/string的区别

1.python2将base64数据写成图片,并将数据转为16进制字符串的方法 import binascii img = u'R0lGODlhagAeAIcAAAAAAAAARAAAiAAAzABEAABERABEiABEzACIAACIRACIiACIzADMAADMRADMiADMzADd3REREQAAVQAAmQAA3QBVAABVVQ...

前端chrome浏览器调试总结

一、调试工具 1、Elements 先来看这张图最上头的一行是一个功能菜单,每一个菜单都有它相应的功能和使用方法,依次从左往右来看箭头按钮:用于在页面选择一个元素来审查和查看它的相关信息,当我们在Elements这个按钮页面下点击某个Dom元素时,箭头按钮会变成选择状态 设备图标:点击它可以切换到不同的终端进行开发模式,移动端和pc端的一个切换,可以选择不...

MySQL中随机生成固定长度字符串的方法

在MySQL中有时需要随机生成数字或字符串,随机生产数字可直接使用rand()函数,但是要随机生成字符串就比较麻烦。 要随机生成字符串代码如下: 在MySQL中定义一个随机串的方法,然后再SQL语句中调用此方法。 随机串函数定义方法: CREATE DEFINER=`root`@`localhost` FUNCTION `rand_string`(n I...