背景:
调试FPU指令过程时,需要一直跟踪FPU Status寄存器TOP字段(ST寄存器对应的BC寄存器),TOP寄存器位于FPU Status[13:11],这种转换过程并非一目了然(如下图):
[Disassembly窗口fld指令执行后,Registers窗口中fpsw的值更新为0x3800,很难马上得到TOP=7的结果]
虽然windbg并没有提供现成的扩展命令简化上述过程,但我发现有一个名为pykd的扩展可以定制脚本实现上述目的。调试目标程序有x86/x64两种,因此需要为x86/x64 2个版本的windbg分别按爪个pykd扩展。(虽然windbg x64可以通过WOW子系统调试x86程序,但是由于x64环境并不支持FPU指令,pykd x64扩展命令在解析FPU指令时会崩溃)
部署:
1. 分别安装python3.9 x86 x64版本;
2. 从github下载pykd的wheel/.whl文件;
3.切换环境变量PATH指向的python解释器,执行pip install安装pykd
#for x86
pip install pykd-0.3.4.15-cp39-none-win32.whl#for x64
pip install pykd-0.3.4.15-cp39-none-win_amd64.whl
4. 从pip安装包中拷贝pykd.pyd到windbg/winext目录下:
通过以下 Python 代码来查看pip安装包的路径:
>>> import site
>>> print(site.getsitepackages())### 输出
### ['C:\\Users\\Eugene\\AppData\\Local\\Programs\\Python\\Python39-32', 'C:\\Users\\Eugene\\AppData\\Local\\Programs\\Python\\Python39-32\\lib\\site-packages']
5.将pykd.pyd重命名为pykd.dll
加载运行pykd:
1.制作python脚本FpuTop.py, 将脚本存放在windbg script(自己创建该目录)目录下:
import pykddef GetCurrFPUTop():# 读取 FPU 状态字fpsw = pykd.reg("fpsw")# 提取 TOP 字段(第 11-13 位)top = (fpsw >> 11) & 0x7# 打印 TOP 值print(f"FPU TOP: {top}")# 计算当前 ST(0) 对应的物理寄存器st0_physical_reg = (8 - top) % 8print(f"ST(0) corresponds to physical register ST({st0_physical_reg})")if __name__ == "__main__":GetCurrFPUTop()
2.windbg加载调试目标,加载pykd扩展:
#加载pkkd扩展
0:000> .load pykd#检查pykd是否加载
0:000> .chain
Extension DLL chain:pykd: image 0.3.4.15, API 1.0.0, built Mon Oct 19 20:32:23 2020[path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\winext\pykd.dll]#在windbg中进入python交互环境:
0:000> !py
Python 3.9.0 (tags/v3.9.0:9cf6752, Oct 5 2020, 15:23:07) [MSC v.1927 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
3.执行脚本
0:000> !py script\FpuTop.py
#######
FPU TOP: 0
ST(0) corresponds to physical register ST(0)