一:背景
1. 讲故事
前几天训练营里的一位朋友在复习课件的时候,程序一跑就报错,截图如下:
从给出的错误信息看大概是因为json格式无效导致的,在早期的训练营里曾经也有一例这样的报错,最后定位下来是公司的电脑安全软件导致的,一旦有非托管调试器,安全软件就会加密 runtimeconfig.json,最后导致程序无法正常被调试执行。
此时相信有很多人想搞清楚,windbg 在那个时刻到底读到了什么脏东西?到底经历了怎样的惊魂时刻?
二:WinDbg 到底遇到了什么
1. 一个小案例
为了方便演示,写一个简单的 hello world
程序,代码如下:
接下来将程序编译之后观察 runtimeconfig.json
内容,截图如下。
2. 如何用 windbg 观察文件内容
熟悉 win32 api 的朋友都知道,C# 的 ReadFile 底层会调用 win32 的 ReadFile 方法,方法签名如下:
方法的 lpBuffer 参数存放的就是读取到的文件内容。
这里还有一个问题就是 ReadFile 是在 dotnet 进程被初始化的时候读取到内存的,在这个初始化过程中会有一系列的加载,那到底在哪个时刻埋点呢?这时候可以借助 procmon 工具,观察 runtimeconfig.json
的加载时机,截图如下:
上面的卦中 runtimeconfig.json
的读取是发生在 hostfxr.dll
加载之后,有了这些信息,思路就有了。
- sxe ld hostfxr 获取插入点。
- bp KERNELBASE!ReadFile 观察第二个参数。
从上面的输出中果然看到了 runtimeconfig.json
中的内容,最后打开导出的文件,没毛病。
3. 有没有快捷的方式
刚才的操作确实能够完成,但还是不爽,因为介入了第三方工具,所以能不能完全通过 windbg 显示打开的 文件路径
和对应的 文件内容
呢?当然是可以的,只需关注如下两个方法 KERNELBASE!CreateFileW
和 KERNELBASE!ReadFile
即可,签名如下:
在 CreateFileW 中我们提取 lpFileName
和返回的 handle
句柄,在 ReadFile 中提取 hFile
句柄 和 lpBuffer
文件内容,参考脚本如下:
稍微说一下 KERNELBASE!CreateFileW+0x6a
是方法的ret处,可以通过 uf KERNELBASE!CreateFileW
计算得到,如下输出所示:
这里的 KERNELBASE!ReadFile+0x73
是内部函数 ntdll!NtReadFile
返回的RIP处。
最后用 windbg 执行如下:
三:总结
有了windbg之后,很多东西都会豁然开朗,而不再像以前那样人云亦云,高级调试这门救火技术
应该是高级程序员必须的进阶之路。