当前位置: 首页 > news >正文

WinDbg. From A to Z! 笔记(一)

原文链接: WinDbg. From A to Z!

文章目录

  • 为什么使用WinDbg
  • 为什么通过本书学习
  • 底层原理简述
    • Windows的调试工具一览
      • dbghelp.dll -- Windows 调试助手
      • dbgeng.dll -- 调试引擎接口
    • 调试符号 (Debug Symbols)
      • 有哪些调试信息
      • 生成调试信息
      • 匹配调试信息
      • 调用堆栈
    • 侵入式与非侵入式
    • 异常机制
      • 异常分发
      • AeDebug? Postmortem Debugging!
  • 使用WinDbg
    • WinDbg 命令
    • 主要的扩展插件
    • WinDbg 使用符号
    • WinDbg 使用源代码
    • Windows 上的进程与线程 (Processes and Threads on Windows NT)
      • PEB 与 TEB
        • 示例 -- 输出完整的PEB
      • 用于显示进程信息和模块信息的WinDbg命令
        • 示例 -- 模块信息
      • 用于显示线程信息的WinDbg命令
        • 示例 -- 线程相关
    • WinDbg的窗口与菜单
    • 调试器标记语言 (Debugger Markup Language, DML)
    • 内存 -- 栈详情
      • 示例 -- 线程的栈大小
    • 内存 -- 栈增长
    • 查看调用栈信息的WinDbg命令
    • 处理内存的WinDbg命令
      • 示例 -- 进程内存信息
    • 查看堆信息的WinDbg 命令
      • Heap Structs
      • 得到HeapAlloc的调用者
        • 示例 -- 得到HeapAlloc的调用者
      • HeapCreate的调用者
        • 示例 -- 得到HeapCreate的调用者
    • 排查堆内存泄漏
      • 示例 -- 排查堆内存泄漏

为什么使用WinDbg

  • 微软官方开发的调试工具
  • 比visual studio 有更强大的程序调试能力
  • 可以用dll来进行扩展
  • WinDbg的调试引擎是Windows操作系统的一部分

为什么通过本书学习

  • WinDbg的官方文档对新手不友好
  • 没有良好的文档和示例,以致于WinDbg的学习曲线很陡峭,从而很多同鞋安装完WinDbg后就放到硬盘里吃灰。
  • “WinDbg. From A to Z”可以帮助同鞋们快速上手,读完本书后,你就会觉得自己又行了。

底层原理简述

Windows的调试工具一览

在这里插入图片描述

dbghelp.dll – Windows 调试助手

  • 文档在MSDN
  • 从Windows2000开始就被包含在系统中
  • 被以下程序依赖
    • Process Dumping (MiniDumpWriteDump , DbgHelpCreateUSerDump, …)
    • Obtaining Stack Traces (StackWalk64, …)
    • Symbol Handling (SymFromAddr, Sym* …)
    • Obtaining info about executable images (ImageNtHeader, FindDebugInfoFile, …)

dbgeng.dll – 调试引擎接口

  • WinDbg的文档中有说明
  • 从Windows XP开始被包含在系统中
  • 实现了接口如: IDebugAdvanced, IDebugControl, IDebugSystemObjects, …
  • 调试器的所有调试功能都来自于dbgeng.dll

Fact 1: WinDbg is really just a shell on top of a debugging engine.
Fact 2: You can write new standalone tools on top of this engine.

调试符号 (Debug Symbols)

  • 可执行程序就是一堆机器码
  • 高度符号有助于:
    • 机器码映射到源代码
    • 分析应用程序的内部布局与数据
  • Program DataBase -> PDB 文件
    • 与linux系统不一样,调试信息与可执行文件分开存储
    • 需要特殊的API来使用它:DbgHelp.dll和MsDiaXY.dll

有哪些调试信息

  • 公开的函数与变量
  • FPO 即用来检索堆栈的信息
  • 非公开的函数,局部变量,函数参数
  • 源码文件与行数信息
  • 类型信息

生成调试信息

Compiler options: /Z7, /Zi, /ZI
Linker options: /debug, /pdb, /pdbstripped

匹配调试信息

  • 在可执行文件和PDB文件中的有签名信息
  • 调试器会匹配签名信息
  • 搜索pdb文件的算法步骤大概如下:
    * 先会尝试指定的文件夹
    * 再尝试PE文件中记录的路径
    * 最后尝试从环境变量 _NT_SYMBOL_PATH 和_NT_ALT_SYMBOL_PATH中搜索

调用堆栈

在这里插入图片描述

侵入式与非侵入式

  • 侵入式附加

    • 会调用DebugActiveProcess 接口
    • 会创造一个break-in thread ,就是可以中断进程
    • 在WindowsXP之前,调试器分离进程或结束调试时,进程会结束
    • 同一时间只能有一个侵入式附加来调试同一个进程
  • 非侵入式调试

    • 会调用 OpenProcess 接口
    • 不会创建一个break-in thread
    • 无法作为一个调试器附加到进程
    • 目标进程的所有线程都冻结
    • 可以改变与测试内存
    • 不能设置断点
    • 无法单步调试程序
    • 可以在一个进程上附加几个非侵入性调试器

异常机制

  • 是操作系统的机制而不是编程语言的特性
  • 可以通过语言扩展来使用异常机制,如VC++的__try __except 语句
  • 不要在需要高效执行的部分使用try catch 语句,因为比较低效。

异常分发

  1. 系统首先尝试通知进程的调试器(如果有的话)
  2. 如果进程未被调试,或者关联的调试器未处理异常
    (Winge->gN==Go with Exception Not Handled),系统尝试定位基于帧的异常处理程序
  3. 如果找不到基于帧的处理程序,或者没有基于帧的处理器处理异常,UnhandledException Filter会再次尝试通知进程的调试器。这被称为第二次机会或最后一次机会通知。
  4. 如果进程未被调试,或者关联的调试器未处理异常,则将启动AeDebug中指定的Postmortem调试器。
    在这里插入图片描述

AeDebug? Postmortem Debugging!

在这里插入图片描述
注册表项 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug

使用WinDbg

WinDbg 命令

  • 常规命令

    • 用于调试进程
    • 如: k, lm, g
  • 元命令(点命令)

    • 通常用于控制调试器的行为
    • 如: .cls, .sympath, .lastevent, .detach
  • 扩展命令

    • dll扩展中的函数
    • 通常用于丰富调试器
    • 可以自行开发扩展插件
    • 如: !address, !analyze

主要的扩展插件

在这里插入图片描述

WinDbg 使用符号

  • 必须设置 _NT_SYMBOL_PATH 环境变量
    如MS symbols:
    _NT_SYMBOL_PATH=srv*C:\Symbols\MsSymbols*http://msdl.microsoft.com/download/symbols;
    如此设置,WinDbg会自动下载需要的符号
    可以设置缓存目录
    cache*E:\MyTemp\SymbolCache;SRV*https://msdl.microsoft.com/download/symbols

  • 在WinDbg 界面可以如此设置
    在这里插入图片描述

  • 常用的命令

在这里插入图片描述

WinDbg 使用源代码

  • 可以通过设置环境变量 _NT_SOURCE_PATH
  • 在WinDbg界面
    在这里插入图片描述
  • 常用的命令
    在这里插入图片描述

Windows 上的进程与线程 (Processes and Threads on Windows NT)

先解释一下NT是什么意思
NT 就是New Technology, 是1993年首次发布的windows内核架构,之前使用的是9x内核架构,从windows xp开始Windows统一到NT内核上,9x被弃用。因为历史原因,许多Windows的库会有nt前缀。

  • 每个Windows进程都由内核模式下的执行进程块(EPROCESS)表示
  • EPROCESS指向了许多相关的数据结构;例如,每个进程都有一个或多个由执行线程块(ETHREAD)表示的线程
  • EPROCESS指向进程地址空间中的进程环境块(PEB)
  • ETHREAD指向进程地址空间中的线程环境块(TEB)

PEB 与 TEB

  • PEB (Process Environment Block)

    • 包含基础信息如:基址,版本号,模块列表
    • 进程堆信息
    • 环境变量
    • 命令行参数
    • DLL搜索路径
    • 在WinDbg 使用命令显示: !peb , dt nt!_PEB
  • TEB (Thread Environment Block)

    • 线程栈信息如: 栈基址和栈长度上限
    • TLS(Thread Local Storage)数组
    • 在WinDbg上的输出命令: !teb, dt nt!_TEB

事实上WinDbg的诸多命令如: lm, !dlls, !imgreloc, !tls, !gle 等,都是从数据结构PEB与TEB中得到的。

示例 – 输出完整的PEB

在这里插入图片描述

命令组解析

  • dt : Data Type , 用于显示数据结构(如结构体、联合体)的定义及其在内存中的值。
  • nt!_PEB
    • nt! 表示符号属于 ​NT 内核模块​(通常是 ntoskrnl.exe 或 ntdll.dll)。
    • _PEB 是进程环境块的结构体名称。PEB 包含进程的全局信息(如加载的模块、命令行参数、堆信息等)。
  • -r: 递归选项,表示递归展开嵌套的结构体。默认递归一层(相当于 -r1),若需更多层级可指定(如 -r2)。此选项会展开指针指向的子结构。
  • @$peb : 伪寄存器 $peb,存储当前进程的 PEB 地址。@ 符号用于访问伪寄存器。

功能:

  • 显示 PEB 的完整结构,解析 @$peb 地址处的内存,按 _PEB 结构体的定义格式化输出,包括所有成员的值(如 Ldr, ProcessParameters 等)。

  • 递归展开嵌套成员, 如果成员是指向其他结构体的指针(如 PEB_LDR_DATA* Ldr),-r 会进一步展开这些子结构体的内容。

    用于显示进程信息和模块信息的WinDbg命令

    在这里插入图片描述

示例 – 模块信息

在这里插入图片描述

用于显示线程信息的WinDbg命令

在这里插入图片描述

示例 – 线程相关

在这里插入图片描述

WinDbg的窗口与菜单

  • WinDbg的窗口是可以停靠与悬浮的
  • 每个WinDbg的子窗口有其自己的功能菜单

调试器标记语言 (Debugger Markup Language, DML)

  • DML允许调试器输出以标签的形式包含指令和额外的非显示信息
  • 调试器用户界面解析出额外信息以提供新行为
  • DML主要旨在解决以下问题:
    • 相关信息的链接
    • 调试器和扩展功能的可发现性
    • 增强调试器和扩展的输出
  • DML是在调试工具6.6.0.7版本中引入的

内存 – 栈详情

  • 每一个新的线程都会有一个栈空间,是由已经提交的和已经预约的内存组成
  • 默认情况下每个线程有1MB的预约空间和1个分页的已经提交空间

不明白己预约的内存和己提交的内存是什么意思的同学自行搜索Windows中 VirtualAlloc的资料。

示例 – 线程的栈大小

在这里插入图片描述

内存 – 栈增长

  • ESP寄存器指向线程的当前堆栈位置。
  • 如果程序试图访问保护页中的地址,系统会引发 _UNGUARD-PAGE_VIOLATION(0x80000001)异常。保护页面为内存页面访问提供one-shot警报。
  • 如果堆栈一直增长到保留内存的末尾,则会引发STATUS_STACK_OVERFLOW异常。

查看调用栈信息的WinDbg命令

在这里插入图片描述

处理内存的WinDbg命令

在这里插入图片描述

示例 – 进程内存信息

在这里插入图片描述

查看堆信息的WinDbg 命令

在这里插入图片描述

Heap Structs

如果您的应用程序禁用了页面堆,则应用以下结构。
请注意,默认情况下页面堆是禁用的。

  • _HEAP

    • 在ntdll.dll 中定义 : dt ntdll!_HEAP
    • 每成功调用一次HeapCreate就会产生一个_HEAP
    • 可以使用!heap -p -all来得到进程中所有_HEAP 结构体的地址
  • _HEAP_ENTRY

    • 在ntdll.dll 中定义: dt ntdll!_HEAP_ENTRY
    • 每成功调用一次HeapAlloc就会产生一个_HEAP_ENTRY
    • 使用!heap -p -all来得到地址

如果为应用程序启用了页堆,则应用以下结构。
您可以使用全局标志(gflags.exe)启用页面堆。

  • _DPH_HEAP_ROOT

    • 在ntdll.dll 中定义: dt ntdll!_DPH_HEAP_ROOT
    • HeapCreate时产生
    • !heap -p -all查看
  • _DPH_HEAP_BLOCK

    • ntdll.dll 中定义
    • HeapAlloc产生
    • !heap -p a-all查看

得到HeapAlloc的调用者

  • 为您的应用程序启用堆栈跟踪和页面堆
    使用Global Flags, 在Windows SDK里面有
    在这里插入图片描述

  • 重启应用,WinDbg重新附加进程

  • WinDbg的命令序列:

    1. !heap -p -a <UserAddr>
    2. dt ntdll!_DPH_HEAP_BLOCK StackTrace<MyHeapBlockAddr>
    3. dds <StackTrace>
示例 – 得到HeapAlloc的调用者

在这里插入图片描述
先通过!heap -p -all来找到一个DPH_HEAP_BLOCK,这里得到些结构体的地址是 144e1f3c, UserAddr 是 144e7c00

在这里插入图片描述
然后直接查询栈跟踪StackTrace的地址。
在这里插入图片描述
打印出栈!

HeapCreate的调用者

与HeapAlloc同理

示例 – 得到HeapCreate的调用者

在这里插入图片描述
找到一个DPH_HEAP_ROOT
在这里插入图片描述
直接找到跟踪栈
在这里插入图片描述
打印跟踪栈,找到源码位置。

排查堆内存泄漏

  • !address –summary
    进程内存使用情况摘要。如果RegionUsageHeap或RegionUsagePageHeap不断增长,那么堆上可能会出现内存泄漏。继续执行以下步骤
  • 使用Global Flags 开启 stack traces 与 page heap
  • 重启应用,重连WinDbg

命令序列:
!heap –stat –h 0 : 将列出每个AllocSize的特定分配统计信息。对于每个AllocSize,都会列出以下内容:AllocSize、#blocks和TotalMem。
!heap –flt –s <size>
!heap -p -a <UserAddr>

示例 – 排查堆内存泄漏

先运行起来查看内存统计
在这里插入图片描述

再运行段时间后查看内存统计
在这里插入图片描述
对比前后内存在增长, 其中 heap @ 147d0000 从 0x2b 个 块长到 0x40 个块
在这里插入图片描述
打印出该堆的信息
抽取其中一个Busy allocations 的UserAddr
在这里插入图片描述
通过一系统命令找到源码进而分析。

相关文章:

  • 项目代码第8讲【数据库基础知识】:SQL(DDL、DML、DQL、DCL);函数(聚合、字符串、数值、日期、流程);约束;多表查询;事务
  • 西域平台商品详情接口设计与实现‌
  • 电容式电压互感器在线监测系统
  • Uni-app入门到精通:tabBar节点实现多页面的切换
  • Open GL ES ->模型矩阵、视图矩阵、投影矩阵等变换矩阵数学推导以及方法接口说明
  • 深入解析 JSON-RPC:从基础到高级应用
  • VUE3+VITE 爬坑笔记
  • 判断质数及其优化方法
  • FTP文件传输协议
  • 【redis】数据类型之Stream
  • Java多线程与高并发专题—— CyclicBarrier 和 CountDownLatch 有什么异同?
  • python面试-基础
  • Android系统启动流程学习(四)应用程序进程启动过程
  • MySQL Binlog
  • 解析 HTML 网站架构规范
  • 使用crontab 每两分钟执行一次 进入 /var/xxx 执行 git pull
  • 开发DOM更新算法
  • 经典算法 整数因子分解问题
  • 二分算法-day2
  • 【C#】关键字 volatile
  • 5月1日,多位省级党委书记调研旅游市场、假期安全等情况
  • 天启年间故宫“三殿”重修与晚明财政
  • 中国证券监督管理委员会党委委员、副主席王建军接受审查调查
  • 广东省副省长刘红兵跨省调任湖南省委常委、宣传部长
  • 体坛联播|欧冠半决赛阿森纳主场不敌巴黎,北京男篮险胜山西
  • 深入贯彻中央八项规定精神学习教育中央指导组派驻地方和单位名单公布