windbg 学习

常用的 windbg 命令

  • .ecxr 用来切换到异常发生时的上下文,主要用在分析静态 dump 文件的时候。当我们使用 .reload 命令去强制加载库的 pdb 文件后,需要执行 .ecxr 命令,重新切换到异常上下文
  • kn/kv/kp 用来查看当前线程的函数调用堆栈。如果要查看当前进程的所有线程的函数调用堆栈,可以使用 ~*kn 命令
  • lm 用来查看库的信息,比如库的路径、时间戳、库的加载地址等。一般使用模糊匹配的模式,比如:lm vm codec*
  • .reload 用来加载pdb文件,一般用来强制加载某个 pdb 文件,比如:.reload  /f  kdcodec.dll。注意这个命令中的名称要使用完整的文件名称
  • !anallyze -v 输出当前异常的详细分析信息
  • g 在中断模式下,跳过中断,继续运行,主要用于实时调试的场景
  • bp/bl/bc 添加、查看、删除断点,主要用于实时调试的场景
  • ~ns 切换到 n 号线程中,在 GUI 应用程序中,UI 线程为 0 号线程,是 GUI 程序的主线程
  • .dump 创建一个用户模式或内核模式的转储文件,比如 .dump /ma C:\1125.dmp
  • r 显示当前线程所有寄存器的值
  • .cls 清除当前屏幕显示
  • ~0s 切换到 UI 线程
  • ~ 打印出当前问题进程的所有线程
  • bp 添加断点
  • bc 清除断点
  • bl 列出断点
  • ba 设置数据断点

也可以在 windbg 的 help 选项卡下选择 index 查看命令


程序崩溃的情况有时是程序访问了 0x00000000 内存地址。

在 Windows 系统中小于 64 kb 的内存是禁止访问的。这块禁止访问的内存地址,是 Windows 系统故意预留的一块小地址内存区域,是为了方便程序员定位问题使用的。一旦访问到该内存区就会触发内存访问违例,

系统就会将进程强制结束掉。

在 Windows 核心编程一书中内存管理的章节,有专门的描述,

空指针赋值分区

这一分区是进程地址空间中从 0x00000000 到 0x0000FFFF 的闭区间,保留该分区的目的是为了帮助程序员捕获对空指针的赋值。如果进程中的线程试图读取或写入位于这一分区内的内存地址,就会引发访问违规。

在 C/C++ 程序中,错误检查经常执行的不够彻底。例如,下面的代码就没有执行错误检查:

int* pnSomeInteger = (int*)malloc(sizeof(int));
*pnSomeInteger = 5;

如果 malloc 无法分配足够的内存,那么它会返回 NULL。但是,前面的代码并没有检查这种可能性--------它想当然地认为分配一定会成功并访问位于地址 0x00000000 处的内存。因为地址空间中的这一分区是禁止访问的。

所以会引发内存访问违规并导致进程被终止。这一特性可以帮助开发人员发现应用程序中的缺陷。值得注意的是,没有任何办法可以让我们分配到位于这一地址区间的虚拟内存,即便是使用 win32 api 也不例外。


 调试步骤:

假设现在我们有一段崩溃代码,

// 添加的一段测试代码
SHELLEXECUTEINFO *pShExeInfo = NULL;
int nVal = pShExeInfo->cbSize; // 通过空指针访问结构体成员,导致崩溃

  

在编译后,运行 .exe 可执行文件,打开 windbg,在 File 选项卡中选择 Attach to a process,从中选择即将崩溃的进程

 点 OK 后,完成 Attach 操作,windbg 会自动中断,这时在 windbg 的命令行输入 g,表示继续运行

 我们让程序崩溃后,windbg 也会自动捕获到异常,这时输入 kn 查看崩溃时的函数调用堆栈。

对于非动态调试的,即加载 dmp 文件的,需要输入 .ecxr 定位到崩溃位置

上面信息我们看到程序发生了 Access violation 内存访问违例的异常,并且可以看到崩溃时的 eax,ebx 等其他寄存器中的值,并能看到发生崩溃的那条汇编指令。

在执行 kn 之后,可以看到代码崩溃的所在行,对于看不见具体函数信息,我们需要手动加载 pdb 文件

输入 lm vm Test_windbg_one* 查看文件的编译时间,通过编译时间找到对应的 pdb 文件,找到之后在 File 选项卡中 Symbol File Path,里面输入 pdb 文件的绝对地址,再 reload,windbg 就会去自动加载 pdb 文件了,如果没有自动加载,可以在命令行输入 .reload /f Test_windbg_one.exe 来强制加载。

如果我们想要在 windbg 中查看代码崩溃为止,可以在 File 选项卡中选择 Source Search Path,在其中输入源代码所在的绝对路径,点击 ok 后,windbg 会自动跳转到源码对应的位置。

 我们可以点击函数调用堆栈中每行最前面的数字超链接,就可以自动切换到对应的函数中,但是对于系统库中函数调用的堆栈模式是没有源码,所以我们一般只能看到应用程序模块的源码

有时我们在排查异常时,需要查看函数调用堆栈中某个函数中的变量值,可以点击函数调用堆栈中每一行前面的数字超链接

如果需要将 dmp 文件保存到本地,输入 .dump /ma D:\Path\crash.dmp 来保存到 crash.dmp 文件中

 

posted @ 2022-06-15 11:19  strive-sun  阅读(868)  评论(0编辑  收藏  举报