如何使用 SymLoadModuleEx 加载 PDB 文件?

发布于 2024-10-15 02:49:46 字数 1024 浏览 2 评论 0原文

我正在尝试调用 SymLoadModuleEx 从 PDB 文件加载符号,然后使用 SymFromAddr 从该 PDB 中查找符号。但是,我不知道要为参数 BaseOfDllDllSize 传递什么——文档明确指出,在加载 PDB 文件时,这些参数不能是0,并且确实尝试传递 0 会导致失败并显示 ERROR_INVALID_PARAMETER

我的代码如下所示:

SymSetOptions(SYMOPT_LOAD_LINES);
HANDLE hprocess = GetCurrentProcess();
if (!SymInitialize(hprocess, NULL, FALSE))
    die("SymInitialize");

if(SymLoadModuleEx(hprocess, NULL, "full path to some PDB file.pdb", NULL,
                   0,  // What to pass here?
                   0,  // What to pass here?
                   NULL, 0) == 0)
{
    die("SymLoadModuleEx");
}

如何确定加载 PDB 文件时要传入的 BaseOfDllDllSize 内容?所涉及的 PDB 文件是不同程序可执行文件(不是 DLL)的符号文件,并且为了便于论证,假设您无权访问生成 PDB 的原始 EXE。

或者,是否有更好的方法从 PDB 文件中查找与给定地址对应的符号?

I'm trying to call SymLoadModuleEx to load the symbols from a PDB file and then use SymFromAddr to look up symbols from that PDB. However, I can't figure out what to pass for the parameters BaseOfDll and DllSize -- the documentation explicitly says that when loading a PDB file, these parameters can't be 0, and indeed attempting to pass 0 results in it failing with ERROR_INVALID_PARAMETER.

Here's what my code looks like:

SymSetOptions(SYMOPT_LOAD_LINES);
HANDLE hprocess = GetCurrentProcess();
if (!SymInitialize(hprocess, NULL, FALSE))
    die("SymInitialize");

if(SymLoadModuleEx(hprocess, NULL, "full path to some PDB file.pdb", NULL,
                   0,  // What to pass here?
                   0,  // What to pass here?
                   NULL, 0) == 0)
{
    die("SymLoadModuleEx");
}

How do you figure out what BaseOfDll and DllSize to pass in when loading a PDB file? The PDB file in question is the symbol file for a different program executable (not a DLL), and just for the sake of argument, assume that you don't have access to the original EXE from which the PDB was generated.

Alternatively, is there a better method of looking up the symbols corresponding to a given address from a PDB file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

囚你心 2024-10-22 02:49:46

dbghelp.dll 和此处的 Sym* 方法利用 调试接口访问 (DIA) SDK。1
DIA 本身是基于 COM 的,并且比 DbgHelp 提供的灵活得多。

具体来说,要加载已知的 PDB 并根据地址查找符号,可以执行以下操作:

  1. 共同创建 DIA 数据源(请参阅“示例”部分 此处)。
  2. 使用 IDiaDataSource::loadDataFromPdb 加载特定的 PDB(不需要 DLL 大小和基地址)。
  3. 使用 IDiaDataSource::openSession 获取您的数据源的 IDiaSession
  4. 根据您是否拥有绝对虚拟地址 (VA) 还是相对虚拟地址 (RVA),您可以使用 findSymbolByVAfindSymbolByRVA分别获取与该地址关联的 IDiaSymbol
  5. 最后,您可以使用 IDiaSymbol::get_name 获取包含您指定的地址的函数名称。

这些都不需要原始图像;仅需要 PDB。假设您使用的是 Visual Studio,DIA 的标头和库可在(例如)下找到:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK

dbghelp.dll and the Sym* methods here make use of the Debug Interface Access (DIA) SDK.1
DIA itself is COM-based and much more flexible than what DbgHelp offers.

Specifically, to load a known PDB and lookup a symbol based on an address, you can do the following:

  1. CoCreate a DIA data source (see the "Example" section here).
  2. Use IDiaDataSource::loadDataFromPdb to load a specific PDB (DLL size and base address are not needed).
  3. Use IDiaDataSource::openSession to get the IDiaSession for your data source.
  4. Depending on if you have an absolute virtual address (VA) or relative virtual address (RVA), you can use findSymbolByVA or findSymbolByRVA, respectively, to get the IDiaSymbol associated with that address.
  5. Finally, you can use IDiaSymbol::get_name to get the function name containing the address you specified.

None of this requires the original image; only the PDB is required. Assuming you're using Visual Studio, the headers and libraries for DIA are available under (for example):
C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK.

转角预定愛 2024-10-22 02:49:46

Dia2Dump 示例非常适合我将相对虚拟地址(eip 程序加载地址)解析为 pdb 以获取未解析的函数指针。这是我尝试的方法:

    DWORD64  dwAddress = _wcstoui64(argv[i], NULL, 16);
    DWORD64 dwRVA  = dwAddress - dwLoadAddress;
    long displacement = 0;
    IDiaSymbol* pFunc = 0;
    error = (DWORD)g_pDiaSession->findSymbolByRVAEx(dwRVA, SymTagFunction, &pFunc, &displacement );

    if (!error && pFunc)
    {
        BSTR bstrName;

        if (pFunc->get_name(&bstrName) != S_OK) {
            wprintf(L"(???)\n\n");
        }

        else {
            wprintf(L"%s \n\n", bstrName);
            if (displacement)
                wprintf(L"+ 0x%x \n\n", displacement);
            else
                wprintf(L" \n\n");
            SysFreeString(bstrName);
        }
    }

例如:
函数: [00447B60][0001:00446B60] ServerConfig::getSSLConfig(public: struct ssl_config __cdecl ServerConfig::getSSLConfig(void) __ptr64)

这里的 RVA 是 00447B60 [ eip - 进程加载地址 ]
该段是 0001
偏移量是00446B60

The Dia2Dump sample works well for me in resolving relative virtual address (eip-program load address) to pdb for unresolved function pointers. This is the way I try it:

    DWORD64  dwAddress = _wcstoui64(argv[i], NULL, 16);
    DWORD64 dwRVA  = dwAddress - dwLoadAddress;
    long displacement = 0;
    IDiaSymbol* pFunc = 0;
    error = (DWORD)g_pDiaSession->findSymbolByRVAEx(dwRVA, SymTagFunction, &pFunc, &displacement );

    if (!error && pFunc)
    {
        BSTR bstrName;

        if (pFunc->get_name(&bstrName) != S_OK) {
            wprintf(L"(???)\n\n");
        }

        else {
            wprintf(L"%s \n\n", bstrName);
            if (displacement)
                wprintf(L"+ 0x%x \n\n", displacement);
            else
                wprintf(L" \n\n");
            SysFreeString(bstrName);
        }
    }

For example:
Function: [00447B60][0001:00446B60] ServerConfig::getSSLConfig(public: struct ssl_config __cdecl ServerConfig::getSSLConfig(void) __ptr64)

Here the RVA is 00447B60 [ eip - Process Load Address ]
the Segment is 0001
the offset is 00446B60

愁杀 2024-10-22 02:49:46

我没有发表评论的权限,因此将在单独的答案中进行此操作。

  1. 是的,DbgHelp 是 DIA 的包装器,只是在静态库方面。 DIA 静态链接到 DbgHelp.dll。 DbgHelp绕过COM直接调用Dia的COM类工厂(IClassFactory)实现。我说的是6.1.7601.17514版本。因此 DbgHelp.dll 是独立的(与 symcrv.dll 和 srcsrv.dll 结合)
  2. Dia COM 对象随 Visual Studio 一起提供(与 dbgeng.dll 位于同一位置),因此解决方案我们不适用于未安装 VS 的环境(但您仍然可以尝试使用 msdia120.dll 作为通过 ActivateActCtx,但还需要部署依赖项(如果存在)
  3. DbgHelp 很紧凑,建议 Microsoft 随您的应用程序分发私有副本。 请参阅“这些内容的重新分发策略” DLL 经过专门设计,使人们能够尽可能轻松地将这些文件包含在自己的包中并发布”

  4. 我没有找到如何使用 DIA 接口下载 PDB 文件的方法。 Sym API 允许这样做。它委托对 SymSrv.dll 的调用。

所以原来的问题仍然是实际的。

I don't have permitions to comment, so will do this in separate answer.

  1. Yes, DbgHelp is a wrapper around DIA, only in terms of static lib. DIA is statically linked into DbgHelp.dll. DbgHelp directly calls Dia's COM class factory (IClassFactory) implementation bypassing COM. I'm talking about 6.1.7601.17514 version. So DbgHelp.dll is self-contained (in combination with symcrv.dll and srcsrv.dll)
  2. Dia COM objects are shipped with Visual Studio (same location with dbgeng.dll), so solution we not work on envs where VS is not installed (but you still could try to use msdia120.dll as private assembly pointing to it via ActivateActCtx, but also need to deploy dependencies, if they present)
  3. DbgHelp is compact and recommended to distribute private copies with your application by Microsoft. See "The redistribution policies for these included DLLs were specifically designed to make it as easy as possible for people to include these files in their own packages and release"

  4. I didn't find the way how to download PDB files using DIA interfaces. Sym API allows this. it delegates calls to SymSrv.dll.

So original question is still actual.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文