wenmo8 发布的文章

1. 下载dmp文件所有相关模块的symbols,缓存到共享路径,便于其它人快速下载
symchk.exe
/id c:\MyApplication.dmp /s
SRV*\\symbols_server\WinSymbols\*http://msdl.microsoft.com/download/symbols

2. 下载某个已运行进程所有相关模块的symbols,缓存到共享路径,便于其它人快速下载
symchk.exe /ie qq.exe /s SRV*\\symbols_server\WinSymbols\*http://msdl.microsoft.com/download/symbols

3. 下载某个exe/dll文件对应的symbols,例如user32.dll,输入命令行:
symchk.exe c:\windows\system32\user32.dll /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols

4. 下载整个目录下(例如system32)所有模块的symbols:
symchk.exe /r c:\windows\system32\ /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols

加载DLL 的时候断

  • sxe ld:[dll]

    比如:

    sxe ld:wininet.dll  (在wininet.dll 被装载的时候断点)

    这里DLL名字是支持通配符的

    比如:

    sxe ld:wini*.dll

  • 也可以在事件过滤器里设置

卸载DLL 的时候断

  • sxe ud:[dll]
  • 也可以在事件过滤器里设置

直接在DllMain下断

bu wininet!DllMain

低层次思考,我指的是从应用程序内部思考的重要性,有时是在机器代码级别。

大多数人认为,要知道如何调试应用程序,只需要学习如何使用调试器。但事实上,学习如何使用调试器只是解决复杂软件问题所需的一部分。因此,我觉得有必要解释在处理应用程序问题(如挂起、崩溃、内存泄漏、应用程序错误和性能问题)时,低层思考是多么重要。

硬件断点的原理

Intel 80306以上的CPU给我们提供了调试寄存器用于软件调试,硬件断点是通过设置调试寄存器实现的。

 

上图为Intel手册提供的32位操作系统下8个调试寄存器的图示(Intel手册卷3 17章第二节 Debug Registers,有兴趣的朋友可以查阅),根据介绍,DR0-DR3为设置断点的地址,DR4和DR5为保留,DR6为调试异常产生后显示的一些信息,DR7保存了断点是否启用、断点类型和长度等信息。

我们在使用硬件断点的时候,就是要设置调试寄存器,将断点的位置设置到DR0-DR3中,断点的长度设置到DR7的LEN0-LEN3中,将断点的类型设置到DR7的RW0-RW3中,将是否启用断点设置到DR7的L0-L3中。设置硬件断点需要的DR0-DR3很简单,就是下断点的地址,DR7寄存器很复杂,位段信息结构体如下:

typedef struct_DBG_REG7
{
/*// 局部断点(L0~3)与全局断点(G0~3)的标记位*/unsigned L0 :1; //对Dr0保存的地址启用 局部断点 unsigned G0 : 1; //对Dr0保存的地址启用 全局断点 unsigned L1 : 1; //对Dr1保存的地址启用 局部断点 unsigned G1 : 1; //对Dr1保存的地址启用 全局断点 unsigned L2 : 1; //对Dr2保存的地址启用 局部断点 unsigned G2 : 1; //对Dr2保存的地址启用 全局断点 unsigned L3 : 1; //对Dr3保存的地址启用 局部断点 unsigned G3 : 1; //对Dr3保存的地址启用 全局断点 /*// 【以弃用】用于降低CPU频率,以方便准确检测断点异常*/unsigned LE :1;
unsigned GE :
1;/*// 保留字段*/unsigned Reserve1 :3;/*// 保护调试寄存器标志位,如果此位为1,则有指令修改条是寄存器时会触发异常*/unsigned GD :1;/*// 保留字段*/unsigned Reserve2 :2;

unsigned RW0 :
2; //设定Dr0指向地址的断点类型 unsigned LEN0 : 2; //设定Dr0指向地址的断点长度 unsigned RW1 : 2; //设定Dr1指向地址的断点类型 unsigned LEN1 : 2; //设定Dr1指向地址的断点长度 unsigned RW2 : 2; //设定Dr2指向地址的断点类型 unsigned LEN2 : 2; //设定Dr2指向地址的断点长度 unsigned RW3 : 2; //设定Dr3指向地址的断点类型 unsigned LEN3 : 2; //设定Dr3指向地址的断点长度 }DBG_REG7, *PDBG_REG7;

如果用户模式应用程序已经在运行,调试器可以非侵入性地对其进行调试。对于非侵入性调试,您没有那么多的调试操作。但是,您可以最小化调试器对目标应用程序的干扰。如果目标应用程序已停止响应,则非侵入性调试非常有用。
在非侵入性调试中,调试器实际上并不附加到目标应用程序。调试器挂起目标的所有线程,并可以访问目标的内存、寄存器和其他此类信息。但是,调试器无法控制目标,因此g(Go)等命令不起作用。
如果尝试执行非侵入性调试期间不允许的命令,则会收到一条错误消息,指出“The debugger is not attached, so process execution cannot be monitored.(未附加调试器,因此无法监视进程执行。)”

选择要调试的进程

您可以通过进程ID(PID)或进程名指定目标应用程序。如果按名称指定应用程序,则应使用进程的完整名称,包括文件扩展名。如果两个进程具有相同的名称,则必须改用进程ID。

通过WinDbg命令行

要从WinDbg命令行无创地调试正在运行的进程,请使用以下语法指定-pv选项、-p选项和进程ID。

windbg -pv -p ProcessID

或者,要通过指定进程名来无创地调试正在运行的进程,请改用以下语法。

windbg -pv -pn ProcessName

通过WinDbg菜单

当WinDbg处于休眠模式时,通过单击“文件”菜单上的“附加到进程”或按F6键,可以无创地调试正在运行的进程。出现“附加到进程”对话框时,选中“非侵入性”复选框。然后,选择包含所需进程ID和名称的行。(也可以在“进程ID”框中输入进程ID。)最后,单击“确定”。