• Windows开发,关于通过写代码加载PDB的那些事


    最近,接到一个活,要写一个程序,用来批量分析一堆dll和对应的PDB,

    其实工作很简单,就是根据一堆偏移,通过PDB文件,找到对应dll里面对应位置的明文符号,

    简单的需求,实现起来,通常都很麻烦,

    微软的demo中,有一个demo叫做dia,这个demo可以提供类似的功能,

    我很高兴地编译了这个项目,但是失败了,加载符号失败,

    通过单步调试,越过了若干个小问题(比如msdia120没注册这种),发现出现问题的位置位于 loadDataForExe 这个函数上,

    这个函数原型是

    virtual HRESULT STDMETHODCALLTYPE loadDataForExe( LPCOLESTR executable, LPCOLESTR searchPath, IUnknown *pCallback) = 0

    可以看出,参数1是要解析的可执行文件,参数2是目标dll活着exe,参数3是一个接口,可以为NULL,或者按照微软demo中不用修改。

    但是执行之后发现,它给我报错,说路径错误,无法找到目标pdb。

    具体错误细节不说了,浪费时间。

    说说怎么解决这个问题吧。

    解决方式比较简单,

    首先确定思路,这个函数不能用,说明它不能自己下载符号了,那么怎么办,

    解决办法就是我们下载符号,然后让它直接加载就好了,另一个函数是可以用的 loadDataFromPdb。

    确定了思路,那么就要铺平道路,我怎么怎么自己下载符号,

    最简单的办法,其实就是使用Windows自己的下载功能,为了尽量少开发,所以可以使用WinDBG内部的功能来自动下载符号。

    这样,符号文件有了,加载方式有了,就差如何把符号文件和可执行文件对应起来了,如何对应。

    通过分析,我们发现,实际上符号文件落地之后是有个特殊的目录名字的,这个名字很像一个MD5,或者很像一个GUID,

    通过分析程序,最终发现,这个目录名字实际上是可执行文件内部记录的一个GUID,再在最后补上一个字符 1。

    具体一点,就是这样。

     1 PCHAR pBuffer = (PCHAR)h;
     2 PCHAR pTemp = pBuffer + 0x3C;
     3 pTemp = pBuffer + *(DWORD *)pTemp;
     4 if (!(pTemp[0] == 'P' && pTemp[1] == 'E' && pTemp[2] == '' && pTemp[3] == ''))
     5 {
     6     return NULL;
     7 }
     8 PVOID *pv;
     9 pv = (PVOID*)(pTemp + 0xA8);             //    找到调试节
    10 pTemp = pBuffer + (DWORD)*pv;            //    计算调试节指定的内存地址
    11 pv = (PVOID *)(pTemp + 4 * 5);           //    找到偏移
    12 pTemp = pBuffer + (DWORD)*pv;            //    找到 UUID 基址
    13 if (!(pTemp[0] == 'R' && pTemp[1] == 'S' && pTemp[2] == 'D' && pTemp[3] == 'S'))
    14 {
    15     return NULL;
    16 }
    17 GUID tGuid = { 0 };
    18 memcpy_s(&tGuid, sizeof(tGuid), pTemp + 4, sizeof(tGuid));

    先根据可执行文件,找到PE头,从PE头里面找到调试节,

    调试节里面找到GUID的偏移地址,

    GUID偏移地址的前四个字符固定是RSDS,判断了之后,如果没有问题,

    那么之后就是一个GUID的长度,

    最后把这个GUID格式化出来变成字符串,最后再在后面补一个字符 '1' 即拼装成了当前文件对应的PDB目录名字,

    然后通过这个目录名字可以拼接出一个完整的目录,很像Windows dbghelp.dll 拼接出来的目录,

    然后去里面就能找到自己对应的pdb。

    整个过程叙述结束。

    最后总结一下。

    解决pdb无法加载的方法:自己下载,独立加载。

    方法:

    1:使用WinDBG命令行下载可执行文件对应的PDB文件。

    2:根据可执行文件计算PDB路径,寻找目标PDB。

    3:找到目标PDB之后,loadDataFromPdb 直接加载PDB就好了。

  • 相关阅读:
    关于update set from,第一次碰到,汗!
    列表CheckBox全选 结合DataGrid 进行删除操作
    DataBinder.Eval的基本格式 效率 比较
    [转载](c#)数据结构与算法分析 栈与队列
    [转载]怎样设计递归算法
    Java httpclient.CloseableHttpClient跳过https证书验证
    LeetCode129求根节点到叶节点数字之和
    LeetCode117填充每个节点的下一个右侧节点指针 II
    LeetCode131分割回文串
    LeetCode130被围绕的区域
  • 原文地址:https://www.cnblogs.com/suanguade/p/11351194.html
Copyright © 2020-2023  润新知