Windbg及Dump文件分析方法

2023-05-16

1.WinDbg

1.1WinDbg介绍

WinDbg全称Debugging Tools for Windows,是windows平台下的调试工具。

获取Windbg的三种途径:

(1)在Visual Studio安装时安装Windows Driver Kit(WDK)。WDK中包含WinDbg。

(2)安装Windows Software Development Kit (SDK)。SDK中包含WinDbg。下载地址

(3)如果只下载单独的WinDbg,先下载SDK,在安装过程中选择“Debugging Tools for Windows”,同时勾掉其他选择框。

1.2用户模式的WinDbg

WinDbg有两种类型:内核模式调试器和用户模式调试器。内核模式用于调试Windows内核以及驱动程序。用户模式用于调试用户程序,本文主要介绍用户模式的调试器,内核模式调试器的使用方法可在微软官网查找。

1.2.1无代码情况下调试

(1)打开WinDbg.exe

(2)在File菜单中选择Open Executable, 在 Open Executable 对话框中选择notepad.exe(C:\Windows\System32),点击Open。

(3)在底部窗口中,输入命令:

.sympath srv*

窗口将输出以下内容:

Symbol search path is: srv*

Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols

符号搜索路径指示WinDbg查找符号文件(PDB)的地方,通过符号文件调试器可以获取代码模块中的函数名称、变量名等信息。输入如下命令将通知WinDbg进行初始化搜索和加载符号文件动作:

.reload

(4)输入以下命令可查看Notepad.exe模块的符号

x notepad!*

如果看不到任何输出,在此输入.reload命令。

输入以下命令可查看Notepad.exe模块中包含main名称的符号

x notepad!*main*

窗口将输出以下内容:

00a31409          notepad!WinMain (<no parameter info>)

00a331c9          notepad!WinMainCRTStartup (<no parameter info>)

(5)输入以下命令可在notepad!WinMain上打断点:

bu notepad!WinMain

输入以下命令验证断点是否已经设置:

bl

窗口将输出以下内容:

     0 e Disable Clear  00a31409     0001 (0001)  0:**** notepad!WinMain

(6)输入以下命令运行Notepad:

g

Nopad将会运行到WinMain函数,并中断。输入以下命令可查看Notepad进程已加载模块列表:

lm

调试器窗口将输出以下内容:

start    end        module name

00a30000 00a60000   notepad    (pdb symbols)          C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\sym\notepad.pdb\BAF2EA337470437B9DF28CCDFD3EDEB22\notepad.pdb

6dfa0000 6dff1000   WINSPOOL   (deferred)            

6e1b0000 6e34e000   COMCTL32   (deferred)            

73730000 73739000   VERSION    (deferred)            

74f10000 74f1c000   CRYPTBASE   (deferred)            

74f20000 74f80000   SspiCli    (deferred)            

74f80000 74ffb000   COMDLG32   (deferred)            

75100000 75191000   OLEAUT32   (deferred)            

75300000 75f4b000   SHELL32    (deferred)            

76130000 76220000   RPCRT4     (deferred)            

76220000 762c1000   ADVAPI32   (deferred)            

76510000 76610000   USER32     (deferred)            

76640000 76687000   KERNELBASE   (deferred)            

76730000 76787000   SHLWAPI    (deferred)            

76930000 76949000   sechost    (deferred)            

76d30000 76dfc000   MSCTF      (deferred)            

76e00000 76e90000   GDI32      (deferred)            

76f30000 76f90000   IMM32      (deferred)            

770c0000 7721c000   ole32      (deferred)            

77250000 772fc000   msvcrt     (deferred)            

77350000 773ed000   USP10      (deferred)            

773f0000 773fa000   LPK        (deferred)            

77400000 77510000   kernel32   (deferred)            

77a50000 77bd0000   ntdll      (pdb symbols)          C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\sym\wntdll.pdb\EA251A0A79C44D5AAF977F6875A518662\wntdll.pdb

输入以下命令可查看调用堆栈信息:

k

调试器窗口将输出以下内容:

# ChildEBP RetAddr 

00 0020fbac 00a3190e notepad!WinMain

01 0020fc3c 7741336a notepad!_initterm_e+0x1a1

02 0020fc48 77a89902 kernel32!BaseThreadInitThunk+0xe

03 0020fc88 77a898d5 ntdll!__RtlUserThreadStart+0x70

04 0020fca0 00000000 ntdll!_RtlUserThreadStart+0x1b

(7)输入以下命令再次运行Notepad:

g

(8)如果想中断Notepad的运行,可在Debug菜单中选择Break。

(9)输入以下命令可在ZwWriteFile处设置并且验证断点:

bu ntdll!ZwWriteFile

bl

(10)输入g再次运行Notepad。在Notepad窗口中输入一些文字然后在文件菜单中选择保存。运行代码将会在ZwCreateFile处中断。输入k可查看调用堆栈。

在调试器窗口左下角,命令行的左侧,显示了处理器和线程的数字。在上图中处理器数字为0,线程数字为0。下图中处理器数字为0,线程数字为19。所以,在下图中我们看到是线程19(在处理器0上运行)的堆栈。

(11)输入以下命令可查看现场0的堆栈:

~0s

k

(12)输入以下命令退出调试,并且从Notepad进程中分离:

qd

1.2.2有代码情况下调试

假设写好了以下简单的控制台程序并且已经编译完成。

...

void MyFunction(long p1, long p2, long p3)

{

         long x = p1 + p2 + p3;

         long y = 0;

         y = x / p2;

}

void main ()

{

         long a = 2;

         long b = 0;

         MyFunction(a, b, 5);

}

在这个例子中,我们假设编译好了程序(MyApp.exe),符号文件(MyApp.pdb)在C:\MyApp\x64\Debug这个路径中,程序代码在C:\MyApp\MyApp。

(1)打开WinDbg

(2)在File菜单中选择Open Executable,在Open Executable对话框中选择文件路径C:\MyApp\x64\Debug,选择MyApp.exe,点击Open。

(3)输入命令:

.sympath srv*

.sympath+ C:\MyApp\x64\Debug

.srcpath C:\MyApp\MyApp

现在WinDbg知道从何处查找程序的符号和代码。

(4)输入命令:

.reload

bu MyApp!main

g

程序将启动并发生中断,中断位置在main函数上。WinDbg显示出了代码和命令窗口。

(5)在Debug菜单中选择Step Into(或者按下F11)。继续单步调试知道进入MyFunction函数。当单步调试到代码行“y = x / p2”时,程序将会发生崩溃并且在调试器中发生中断。调试器窗口将输出以下内容:

(1450.1424): Integer divide-by-zero - code c0000094 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

MyApp!MyFunction+0x44:

00007ff6`3be11064 f77c2428    idiv  eax,dword ptr [rsp+28h] ss:00000063`2036f808=00000000

(6)输入命令:

!analyze -v

WinDbg将显示出问题(除0异常)的分析结果

FAULTING_IP:

MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]

00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)

ExceptionAddress: 00007ff63be11064 (MyApp!MyFunction+0x0000000000000044)

   ExceptionCode: c0000094 (Integer divide-by-zero)

  ExceptionFlags: 00000000

NumberParameters: 0

...

STACK_TEXT: 

00000063`2036f7e0 00007ff6`3be110b8 : ... : MyApp!MyFunction+0x44

00000063`2036f800 00007ff6`3be1141d : ... : MyApp!main+0x38

00000063`2036f840 00007ff6`3be1154e : ... : MyApp!__tmainCRTStartup+0x19d

00000063`2036f8b0 00007ffc`b1cf16ad : ... : MyApp!mainCRTStartup+0xe

00000063`2036f8e0 00007ffc`b1fc4629 : ... : KERNEL32!BaseThreadInitThunk+0xd

00000063`2036f910 00000000`00000000 : ... : ntdll!RtlUserThreadStart+0x1d

STACK_COMMAND: dt ntdll!LdrpLastDllInitializer BaseDllName ;dt ntdll!LdrpFailureData ;.cxr 0x0 ;kb

FOLLOWUP_IP:

MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]

00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]

FAULTING_SOURCE_LINE:  c:\myapp\myapp\myapp.cpp

FAULTING_SOURCE_FILE:  c:\myapp\myapp\myapp.cpp

FAULTING_SOURCE_LINE_NUMBER:  7

FAULTING_SOURCE_CODE: 

     3: void MyFunction(long p1, long p2, long p3)

     4: {

     5: long x = p1 + p2 + p3;

     6: long y = 0;

>    7: y = x / p2;

     8: }

     9:

    10: void main ()

    11: {

    12: long a = 2;

...

1.2.3调试进程

(1)在File菜单中选择Attach to a Process,或者按F6

(2)在Attach to Process对话框中选择需要调试的进程,然后点击OK

(3)调试方法和以上两个类似

2.符号

当应用程序、库、驱动或者操作系统进行链接时,链接器将会创建.exe,.dll以及一些额外的符号文件。符号文件中包含了大量程序运行时不需要用到的数据,但是在调试时这些数据会很有用。通常情况下,符号文件包含以下几个类别:

  1. 全局变量
  2. 局部变量
  3. 函数名称和相应的入口地址
  4. 框架指针省略(Frame Pointer Omission)(FPO)
  5. 代码行数信息

单个符号文件可能包含很多个符号,包括全局变量、函数名称以及很多局部变量。通常情况下,软件公司会发布两种版本的符号文件:全符号文件(包含公有符号和私有符号)和裁剪符号文件(只包含公有符号)

调试时,需要确保调试器可以访问调试对象相关联的符号文件。无论实时调试或者是调试dump文件都需要符号。调试代码时,需要加载正确的符号进入调试器。

Windows下的符号文件后缀名是.pdb。编译器和链接器控制符号的格式,Visual C++连接器将所有的符号都放到了.pdb文件中。

Windows操作系统提供了两种发布版本。小的二进制文件的免费版(或零售版)以及大的二进制文件并且包含很多调试符号的检测版(或者调试版)。每种发布版本都有其自己的符号文件。调试时,需要匹配正确的Windows版本的符号文件。

下表列出了一些列的包含标准的Windows符号树的目录:

目录

包含特定类型的符号文件

ACM

Microsoft Audio Compression Manager files

COM

Executable files (.com)

CPL

Control Panel programs

DLL

Dynamic-link library files (.dll)

DRV

Driver files (.drv)

EXE

Executable files (.exe)

SCR

Screen-saver files

SYS

Driver files (.sys)

在调试Windows内核、驱动或者应用程序时,需要访问正确的符号文件。

如果调试器在运行的时候已经连上了网络,可以直接使用微软的符号服务器。连接符号服务器的方法是使用命令.symfix(设置符号存储路径)。调试器会缓存连接的服务器上的符号文件,下次调试会自动使用本地的缓存文件。

3.Dump文件

3.1Dump文件介绍

Dump文件可分为内核Dump文件和用户模式Dump文件。本文主要讲述用户模式下Dump文件。用户模式Dump文件又可分为:完整用户模式Dump文件和Minidump文件。

(1)完整用户模式Dump文件

完整用户模式Dump文件是最基本的用户模式的dump文件。文件中包含进程的全部内存空间,程序自身镜像,句柄表,以及其他对调试器非常有用的信息。完整用户模式dump文件可以剪切成minidump文件,先将dump文件加载到调试器中,然后使用.dump(Create Dump File)命令保存一个新的minidump格式的dump文件。

注意尽管其名称有mini,但最大的minidump文件实际上包含的信息比完整的用户模式转储还多。 例如,.dump /mf.dump /ma将创建比.dump /f更大,更完整的文件。

在用户模式下,.dump /m [MiniOptions]是最佳选择。用此开关创建的转储文件的大小可以从很小到很大。通过指定适当的MiniOptions,可以精确控制所包含的信息。

(2)Minidumps

用户模式转储文件仅包含与进程关联的内存的选定部分,称为最小转储。

小型转储文件的大小和内容取决于要转储的程序和执行转储的应用程序。有时,小型转储文件很大,并且包含完整的内存和句柄表。在其他时候,它要小得多-例如,它可能仅包含有关单个线程的信息,或仅包含有关堆栈中实际引用的模块的信息。

名称“minidump”具有误导性,因为最大的minidump文件实际上比“全”用户模式转储包含更多的信息。例如,.dump /mf.dump /ma将创建比.dump /f更大,更完整的文件。 因此,建议在所有用户模式转储文件创建中使用.dump /m [MiniOptions],而不是.dump /f

如果要使用调试器创建小型转储文件,则可以准确选择要包含的信息。 一个简单的.dump /m命令将包含有关组成目标进程的已加载模块的基本信息,线程信息和堆栈信息。可以使用以下任一选项进行修改:

选项

描述

/ma

使用所有选项创建转储文件。/ma选项等同于/mfFhut。它将完整的内存数据,句柄数据,卸载的模块信息,基本内存信息和线程时间信息添加到小型转储文件中。

/mf

将完整的内存数据添加到小型转储。将包含目标应用程序拥有的所有可访问的提交页面。

/mF

将所有基本内存信息添加到小型转储。这会将流添加到小型转储,其中包含所有基本内存信息,而不仅仅是有关有效内存的信息。这使得调试器可以在调试小型转储时重建进程的完整虚拟内存布局。

/mh

将有关与目标应用程序关联的句柄的数据添加到小型转储。

/mu

将卸载的模块信息添加到小型转储。仅在Windows Server 2003和更高版本的Windows中可用。

/mt

将其他线程信息添加到minidump。这包括线程时间,调试minidump时可以使用.ttime(显示线程时间)显示该时间。

/mi

将辅助内存添加到小型转储。 辅助存储器是堆栈或后备存储器上的指针引用的任何存储器,外加围绕该地址的小区域。

/mp

将进程环境块(PEB)和线程环境块(TEB)数据添加到小型转储。 如果您需要访问有关应用程序进程和线程的Windows系统信息,这将很有用。

/mw

将所有已提交的可读写私有页面添加到小型转储中。

/md

将可执行镜像中的所有读写数据段添加到小型转储中。

/mc

在镜像中添加代码段。

/mr

从小型转储中删除堆栈的那些部分,并存储对重新创建堆栈跟踪无用的内存。局部变量和其他数据类型值也将被删除。此选项不会使minidump变小(因为这些内存部分仅被清零了),但是如果希望保护其他应用程序的隐私,则该选项很有用。

/mR

从小型转储中删除完整的模块路径。 仅包含模块名称。如果您希望保护用户目录结构的私密性,这是一个有用的选项。

/mk "FileName"

(仅Windows Vista)除了用户模式小型转储之外,还创建内核模式小型转储。内核模式小型转储将限于用户模式小型转储中存储的相同线程。FileName必须用引号引起来。

这些选项可以组合。例如,命令.dump /mfiu可用于创建相当大的小型转储,或者命令.dump /mrR可用于创建可保留用户隐私的小型转储。 有关完整语法的详细信息,请参见.dump(创建转储文件)。

3.2分析Dump文件

WinDbg可以分析用户模式的内存转储文件。在其上创建转储文件的处理器或Windows版本不需要与运行WinDbg的平台匹配。

注意:发生崩溃的程序必须和pdb文件的版本一致(同一时间编译),否则将会发生符号加载失败的情况。

分析步骤:

(1)在菜单File中选择Open Crash Dump菜单或者按下CTRL+D快捷键。当出现“Open Crash Dump”对话框时,在“File name”文本框中输入故障转储文件的完整路径和名称,或使用对话框选择正确的路径和文件名。 选择正确的文件后,单击“Open”。

(2)调试方法和1.2章节类似

A.输入 !analyze -v 命令进行自动分析

B.使用 .excr 命令定位到崩溃位置

C.使用 kp 命令查看崩溃时的堆栈信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windbg及Dump文件分析方法 的相关文章

  • 我的堆是否碎片化

    0 000 gt dumpheap stat total 1755874 objects Statistics MT Count TotalSize Class Name 7b9b0c64 1 12 System Windows Forms
  • 在 WinDbg 中定义自定义错误检查代码

    有没有一种方法可以定义自定义代码 带有消息 描述等 以便当我在 Windows 的内核模式驱动程序中调用KeBugCheckEx要发出自定义 BugCheck 代码 WinDbg 会显示该自定义 BugCheck 代码附带的关联消息吗 有关
  • Windbg可以显示线程名称吗?

    Windbg应该明白 https groups google com forum topic microsoft public windbg 2atvu7h3D3c the MS异常协议 https msdn microsoft com e
  • c0000005 C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.threads 调试器扩展中的异常

    当使用 load by 命令加载扩展时 我在首次运行任何 SOS 扩展命令时遇到异常 但是 如果我使用 load 命令 则不会出现异常 以下是我使用的过程的一个步骤 有人可以解释为什么会发生这种情况以及可能的解决方案 0 007 gt ch
  • WinDbg - 将字符串参数与内存中的字符串进行比较

    我需要比较一个字符串 作为参数传递给WinDbg用记忆中的字符串 如何才能实现这一目标 例如 该字符串位于加载的 PE 内的特定偏移处 所以 我可以通过执行轻松读取字符串da c 100
  • 在windbg中调试.Net字符串值

    我有一个 Net 应用程序转储 它捕获了一个异常 我正在使用 Windbg 进行分析 并对其中一种方法的 String 参数的值感兴趣 我已经隔离了 String 对象 我的windbg工作是 0 000 gt loadby sos msc
  • 如何识别STATUS_INVALID_CRUNTIME_PARAMETER异常

    平台是Windows 7 SP1 我最近花了一些时间调试由于代码将无效参数传递给 安全 CRT 函数之一而引起的问题 结果 我的应用程序立即中止 没有任何警告或任何内容 甚至没有崩溃对话框 起初 我尝试通过将 Windbg 附加到我的应用程
  • 从 sql 文件恢复单个表转储

    我有 sql 文件的完整转储 例如dump full sql尺寸的1 3GB 它有一些像这样的表 dancing core spice dancing sea beast forde clear one forde super now 现在
  • 没有 JDK 的 JRE 6 (Windows) 上的堆转储

    有没有办法在没有安装 JDK 的远程计算机上创建堆转储 我无法更改安装 设置 并且它在 Windows 上运行 所以我可以随时访问命令行工具 问题是远程计算机上的 Java 应用程序冻结 没有内存不足异常 因此 XX HeapDumpOnO
  • 使用 Windbg 调试 .NET OutOfMemoryException

    我需要帮助调试 net dll 中的 OutOfMemoryException 该 dll 将 rtf 文本转换为原始文本或 html 这是转换代码 http matthewmanela com blog converting rtf to
  • JavaScript 中相当于 PHP 中的 var_dump 或 print_r 的是什么? [复制]

    这个问题在这里已经有答案了 我想查看 JavaScript 中对象的结构 用于调试 PHP中有类似var dump的东西吗 大多数现代浏览器的开发工具中都有一个控制台 对于此类调试很有用 console log myvar 然后 您将在控制
  • 如何在Python中正确编码json转储[重复]

    这个问题在这里已经有答案了 我有一个 python 3 脚本 应该从 csv 文件获取一些数据并将其写入 json 文件 在我的处理过程中 编码是正确的 因此德语变音 或度数符号 就像它们本来的样子 coding cp1252 在头部 但是
  • Windbg !address 输出中的 是什么意思

    Example 0 074 gt address summary Usage Summary RgnCount Total Size ofBusy ofTotal Free 90919 7ec 34659000 7 923 Tb 99 03
  • 如何更改年龄不匹配的 PDB 以使其正确匹配?

    我们的夜间构建过程被破坏了很长一段时间 因此它生成的 PDB 文件与相应的图像文件的年龄相差几个小时 我已经解决了这个问题 但是 我想开始使用符号服务器 但由于必须使用这些年龄不匹配的 pdb 文件而无法开始 我通过使用 Windbg 中的
  • Windows 调试工具未安装

    我正在尝试通过 Windows SDK 安装 Windows 调试工具 两次尝试后我不知道该怎么做 我开始安装 没有收到任何错误 但调试工具 windbg 和 kd 却找不到 日志几乎毫无用处 9 16 59 PM Monday July
  • 分析 Windbg 中的故障转储

    我正在使用第三方闭源 API 它会抛出一个异常 指出 所有命名管道都忙 我想进一步调试 而不是单步调试 这样我就可以真正了解幕后发生的事情 我使用 WinDbg 转储了这个过程 我现在应该使用什么命令来分析此转储 Thanks 您可以开始执
  • 使用mysqldump只转储数据,不转储任何表信息

    我正在寻找转储 mysql 数据库中所有数据的语法 我不需要任何表格信息 mysqldump no create info 您也可以使用 skip triggers 如果您使用触发器 no create db 如果您正在使用 databas
  • 什么可以解释托管堆上超过 5,000,000 个 System.WeakReference 实例?

    我一直在针对生产 ASP NET Web 应用程序运行负载测试 并且看到在堆上创建了大量 System WeakReference 在大约 15 分钟内 负载管理堆内存已飙升至大约 3GB 并且我有大约 5 000 000 个对 Syste
  • WinDbg:dd <地址> L <长度> 的范围限制

    WinDbg 对 d 命令系列有范围限制 根据文档 限制为 256 MB 使用 L 可以绕过此限制 句法 L Size 带问号 的意思与LSize相同 只是L 大小删除了调试器的自动范围限制 通常 有 范围限制为 256 MB 因为更大的范
  • 如何证明 .NET CLR JIT 每次运行只编译每个方法一次?

    There s 一个老问题 https stackoverflow com questions 1255803 does the net clr jit compile every method every time 1255832每次询问

随机推荐