从卸载模块的pdbs中提取结构信息

时间:2021-04-18 07:15:34

I'm trying to write a WinDbg debugger extension that works on both live remote targets and crash dumps. This extension analyzes an opaque block of memory by walking down it via structure offsets and casting different regions of it to known objects.

我正在尝试编写一个WinDbg调试器扩展,它可以在实时远程目标和崩溃转储上工作。这个扩展通过结构偏移量来分析一个不透明的内存块,并将它的不同区域转换为已知对象。

The structures change fields/field ordering between versions, so I can't hard code it (or include the headers) in my debugger extension itself. Instead I'd like to extract the structure information from the pdbs for which I have private symbols.

这种结构改变了版本之间的字段/字段顺序,因此我无法在调试器扩展本身中硬编码它(或包含头)。相反,我想从我有专用符号的pdbs中提取结构信息。

When using this on a live target where the pdb/image is in the loaded module list, this works great, and I can use functions like GetFieldOffset to get a field in a structure in a class.

当在加载模块列表中有pdb/image的活动目标上使用这个函数时,它非常有用,我可以使用GetFieldOffset这样的函数在类中的结构中获取字段。

GetFieldOffset("MyClass!MyNestedClass", "m_Struct", &offsetInClass);

GetFieldData(offsetInClass + classAddr, "MyClass!_MY_STRUCT", "FieldInStruct",
             sizeof(ULONG), &myFieldValue);

My problem: When I don't have the module in the loaded module list (either in the wrong context, or analyzing a crash dump), I can't use the above functions.

我的问题是:如果在加载的模块列表中没有模块(无论是在错误的上下文中,还是分析崩溃转储),我就不能使用上述函数。

At the beginning of the memory region I'm analyzing, I've stored the pdb GUID and age. Using that I can find the path to my pdb in my symbol path/symbol cache using SymFindFileInPath.

在我分析的内存区域的开始,我存储了pdb GUID和年龄。使用它,我可以使用SymFindFileInPath在符号路径/符号缓存中找到pdb的路径。

char symbolPath[MAX_SYMBOL_PATH] = "";
PSTR pdbPath = NULL;

hr = ExtSymbols->lpVtbl->GetSymbolPath(ExtSymbols,
                                       symbolPath,
                                       sizeof(symbolPath),
                                       NULL);

SymSetOptions(SYMOPT_IGNORE_CVREC | SYMOPT_FAIL_CRITICAL_ERRORS | 
              SYMOPT_CASE_INSENSITIVE);

result = SymFindFileInPath(hSymbols,
                           symbolPath,
                           Name,
                           &GUID,
                           Age,
                           0,
                           SSRVOPT_GUIDPTR,
                           pdbPath,
                           NULL,
                           NULL);

So I have the path to my specific pdb instance, but I'm not sure where to go from here. Looking through the Sym* functions exposed by DbgHelp.dll, I don't see any obvious way to use this pdb file to get type information. Functions such as SymGetTypeInfo require a module base, and my module is not and cannot be loaded. All I need is the byte offset of fields within a structure. Any ideas?

我有到特定pdb实例的路径,但是我不确定从这里开始。查看DbgHelp公开的Sym*函数。我看不出有什么明显的方法可以使用这个pdb文件来获取类型信息。像SymGetTypeInfo这样的函数需要一个模块库,而我的模块不是也不能被加载。我所需要的是结构中字段的字节偏移量。什么好主意吗?

Thanks!

谢谢!

2 个解决方案

#1


0  

The POC CODE below show how to extract TypeInfo from a pdb using dia sdk

下面的POC代码展示了如何使用dia sdk从pdb中提取类型信息

//fragile code handle with care

//小心易碎的代码句柄

#include "typefrompdb.h"
int main(int argc, char* argv[]) {
    USAGE;
    swprintf(pdb, MAX_PATH,L"%S",argv[1]);
    swprintf(type, MAX_PATH,L"%S",argv[2]);
    result = CoInitialize(NULL);
    result = CoCreateInstance( CLSID_DiaSource,NULL, 
        CLSCTX_INPROC_SERVER,__uuidof( IDiaDataSource ),(void **) &pSource);
    result = pSource->loadDataFromPdb(pdb);
    SHOUT("%s 2find %S %d\n",(result==S_OK)?"succeded":"failed",pdb,__LINE__);
    result = pSource->openSession(&pSession);
    result = pSession->get_globalScope(&pSymbol);
    result = pSymbol->findChildren(SymTagUDT,type,nsNone,&pEnumsymbols);
    result = pEnumsymbols->get_Count(&count);   
    result = pEnumsymbols->Next(1,&pSymudt,&noofsymret);
    SHOUT("%s 2find %S %d\n",(result==S_OK)?"succeded":"failed",type,__LINE__);
    result = pSymudt->get_name(udtname);
    result = pSymudt->findChildren(SymTagNull,NULL,nsNone,&pEnumsymbols);
    result = pEnumsymbols->get_Count(&count);
    SHOUT("no of members in struct %S is  0X%X %d\n",type,count,__LINE__);
    wprintf(L"\nstruct %s {\nType Leng Tags Name  \n",*udtname);
    for (LONG i =0 ; i< count; i++)     {
        result = pEnumsymbols->Next(1,&pSymchild,&noofsymret);            
        result = pSymchild->get_name(childname);
        result = pSymchild->get_type(&pSymtags);
        result = pSymtags->get_symTag(&dwtag);
        result = pSymtags->get_length(&len);
        result = pSymtags->get_baseType(&basetype);
        wprintf(L"0x%.2X 0x%.2I64X 0x%.2X %s\n",basetype,len,dwtag,*childname);
    }    return 0; }

contents of header file typefrompdb.h

头文件typefrompdb.h的内容

/* handling errors/releasing memory BSTRS pointers  closing handles using 
sensible coding standards using dynamic allocations replacing ansi with unicode
etc etc etc should be implemented POC CODE not meant for blind copy pasting 
typical test case is typefrompdb.exe ntdll.pdb _DRIVER_OBJECT */
#include <stdio.h>
#include <Windows.h>
#include <Dia2.h>    // set INCLUDE=diasdkdir\inc
#include <atlbase.h> // vs 2010 express edition used with wdk 7600 
#include <atlcom.h>  // set INCLUDE=C:\WinDDK\7600.16385.1\inc\atl71
#include <dbghelp.h> // set INCLUDE=windbg\sdk\inc
#define SHOUT(...) if(result!=S_OK){printf(__VA_ARGS__);exit(0);\
        }else{printf(__VA_ARGS__);}
#define USAGE if (argc != 3) { printf( \
    "usage %s %s %s\n",argv[0],"file.pdb","typename"); return 0;}
HRESULT                 result              = E_FAIL;
IDiaDataSource          *pSource            = NULL;
IDiaSession             *pSession           = NULL;
IDiaSymbol              *pSymbol,*pSymchild = NULL;
IDiaEnumSymbols         *pEnumsymbols       = NULL;
wchar_t                 pdb[500], type[500] = {0};
BSTR        childname[0x100],udtname[0x100] = {0};
LONG                    count               = 0;
ULONG                   noofsymret          = 0;
DWORD               dwtag,basetype          = 0;
ULONGLONG               len                 = 0;
CComPtr< IDiaSymbol >   pSymudt;
CComPtr< IDiaSymbol >   pSymtags;

compiled and linked with

编译并与

@call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
set INCLUDE=XXXX;XXXX;XXXX;%INCLUDE%
set LIB=YYYY;YYYY;YYYY;%LIB%
cl /c /Zi /nologo /W4 /wd6387 /analyze %1% 
link /DEBUG /nologo /RELEASE /IGNORE:4254 diaguids.lib  *.obj
pause

results for test case

测试用例的结果

typefrompdb.exe
usage typefrompdb.exe file.pdb typename  
typefrompdb.exe ntd dr
failed 2find ntd 11

typefrompdb.exe ntdll.pdb _driver_object
succeded 2find ntdll.pdb 11
failed 2find _driver_object 17

typefrompdb.exe ntdll.pdb _DRIVER_OBJECT
succeded 2find ntdll.pdb 11
succeded 2find _DRIVER_OBJECT 17
no of members in struct _DRIVER_OBJECT is  0XF 21    
struct _DRIVER_OBJECT {
Type Leng Tags Name
0x06 0x02 0x10 Type
0x06 0x02 0x10 Size
0x00 0x04 0x0E DeviceObject
0x0E 0x04 0x10 Flags
0x00 0x04 0x0E DriverStart
0x0E 0x04 0x10 DriverSize
0x00 0x04 0x0E DriverSection
0x00 0x04 0x0E DriverExtension
0x00 0x08 0x0B DriverName
0x00 0x04 0x0E HardwareDatabase
0x00 0x04 0x0E FastIoDispatch
0x00 0x04 0x0E DriverInit
0x00 0x04 0x0E DriverStartIo
0x00 0x04 0x0E DriverUnload
0x00 0x70 0x0F MajorFunction

interpretation of results for the typical test case

对典型测试用例结果的解释

grep -iE "btint|btulong|btnotype" cvconst.h
    btNoType = 0,
    btInt = 6,
    btULong = 14,

grep -i -A 35 "enum symtagenum" cvconst.h 
| awk "{ if ( NR==0x0B || NR==0x0E || NR==0x0F || NR==0x10 ) print $0 }"
    SymTagAnnotation,
    SymTagUDT,
    SymTagEnum,
    SymTagFunctionType,

edit
I was never sure this was an answer this was more of a test or experiment in using dia sdk SymLoadModule uses an arbitrary address hardcoded as 0x1000000 you can see that in DBH src in platform sdk samples the compiled binary of the same src is available in windbg installation

编辑我不确定这是一个答案这是更多的测试或实验使用dia sdk SymLoadModule使用任意地址硬编码为0 x1000000胸径src中您可以看到,平台sdk编译后的二进制样品相同的src windbg安装中可用

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\winbase\debug\dbh


//global
DWORD64 gDefaultBaseForVirtualMods;

BOOL init()
{
    int i;

    *gModName = 0;
    gBase = 0;;
    gDefaultBaseForVirtualMods = 0x1000000;

else if (!_tcsicmp(ext, _T(".pdb"))) 
{
    addr = gDefaultBaseForVirtualMods;
    dontopen = true;
} else {
    addr = gDefaultBase;
}


C:\>dbh XXXXXXX\ntdll.pdb t _DRIVER_OBJECT

   name : _DRIVER_OBJECT
   addr :        0
   size : a8
  flags : 0
   type : 1
modbase :  1000000
  value :        0
    reg : 0
  scope : SymTagNull (0)
    tag : SymTagUDT (b)
  index : 1

C:\>

anyway i would reiterate that you are not supposed to use dbghelp functions in windbg extensions read the notes on following links (writing wdbg extensions/ dbgeng extensions / engextcpp function which states that it is not supported to use dbghelp functions in windbg extension

无论如何,我要重申,您不应该在windbg扩展中使用dbghelp函数,请阅读以下链接的说明(编写wdbg扩展/ dbgeng扩展/ engextcpp函数,该函数声明在windbg扩展中不支持使用dbghelp函数

Note   You must not attempt to call any DbgHelp or ImageHlp routines from any debugger extension. Calling these routines is not supported and may cause a variety of problems. 

writing wdbgexts windbg extensions

写作wdbgexts windbg扩展

writing dbgeng windbg extensions

写作dbgeng windbg扩展

writing engextcpp windbg extensions

写作engextcpp windbg扩展

#2


0  

The Debug Interface Access SDK provides APIs for working with the PDB directly:

调试接口访问SDK提供了与PDB直接协作的api:

http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx

http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx

The DIA2Dump sample is full featured and demonstrates how to extract type information.

DIA2Dump示例是完整的,演示了如何提取类型信息。

#1


0  

The POC CODE below show how to extract TypeInfo from a pdb using dia sdk

下面的POC代码展示了如何使用dia sdk从pdb中提取类型信息

//fragile code handle with care

//小心易碎的代码句柄

#include "typefrompdb.h"
int main(int argc, char* argv[]) {
    USAGE;
    swprintf(pdb, MAX_PATH,L"%S",argv[1]);
    swprintf(type, MAX_PATH,L"%S",argv[2]);
    result = CoInitialize(NULL);
    result = CoCreateInstance( CLSID_DiaSource,NULL, 
        CLSCTX_INPROC_SERVER,__uuidof( IDiaDataSource ),(void **) &pSource);
    result = pSource->loadDataFromPdb(pdb);
    SHOUT("%s 2find %S %d\n",(result==S_OK)?"succeded":"failed",pdb,__LINE__);
    result = pSource->openSession(&pSession);
    result = pSession->get_globalScope(&pSymbol);
    result = pSymbol->findChildren(SymTagUDT,type,nsNone,&pEnumsymbols);
    result = pEnumsymbols->get_Count(&count);   
    result = pEnumsymbols->Next(1,&pSymudt,&noofsymret);
    SHOUT("%s 2find %S %d\n",(result==S_OK)?"succeded":"failed",type,__LINE__);
    result = pSymudt->get_name(udtname);
    result = pSymudt->findChildren(SymTagNull,NULL,nsNone,&pEnumsymbols);
    result = pEnumsymbols->get_Count(&count);
    SHOUT("no of members in struct %S is  0X%X %d\n",type,count,__LINE__);
    wprintf(L"\nstruct %s {\nType Leng Tags Name  \n",*udtname);
    for (LONG i =0 ; i< count; i++)     {
        result = pEnumsymbols->Next(1,&pSymchild,&noofsymret);            
        result = pSymchild->get_name(childname);
        result = pSymchild->get_type(&pSymtags);
        result = pSymtags->get_symTag(&dwtag);
        result = pSymtags->get_length(&len);
        result = pSymtags->get_baseType(&basetype);
        wprintf(L"0x%.2X 0x%.2I64X 0x%.2X %s\n",basetype,len,dwtag,*childname);
    }    return 0; }

contents of header file typefrompdb.h

头文件typefrompdb.h的内容

/* handling errors/releasing memory BSTRS pointers  closing handles using 
sensible coding standards using dynamic allocations replacing ansi with unicode
etc etc etc should be implemented POC CODE not meant for blind copy pasting 
typical test case is typefrompdb.exe ntdll.pdb _DRIVER_OBJECT */
#include <stdio.h>
#include <Windows.h>
#include <Dia2.h>    // set INCLUDE=diasdkdir\inc
#include <atlbase.h> // vs 2010 express edition used with wdk 7600 
#include <atlcom.h>  // set INCLUDE=C:\WinDDK\7600.16385.1\inc\atl71
#include <dbghelp.h> // set INCLUDE=windbg\sdk\inc
#define SHOUT(...) if(result!=S_OK){printf(__VA_ARGS__);exit(0);\
        }else{printf(__VA_ARGS__);}
#define USAGE if (argc != 3) { printf( \
    "usage %s %s %s\n",argv[0],"file.pdb","typename"); return 0;}
HRESULT                 result              = E_FAIL;
IDiaDataSource          *pSource            = NULL;
IDiaSession             *pSession           = NULL;
IDiaSymbol              *pSymbol,*pSymchild = NULL;
IDiaEnumSymbols         *pEnumsymbols       = NULL;
wchar_t                 pdb[500], type[500] = {0};
BSTR        childname[0x100],udtname[0x100] = {0};
LONG                    count               = 0;
ULONG                   noofsymret          = 0;
DWORD               dwtag,basetype          = 0;
ULONGLONG               len                 = 0;
CComPtr< IDiaSymbol >   pSymudt;
CComPtr< IDiaSymbol >   pSymtags;

compiled and linked with

编译并与

@call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
set INCLUDE=XXXX;XXXX;XXXX;%INCLUDE%
set LIB=YYYY;YYYY;YYYY;%LIB%
cl /c /Zi /nologo /W4 /wd6387 /analyze %1% 
link /DEBUG /nologo /RELEASE /IGNORE:4254 diaguids.lib  *.obj
pause

results for test case

测试用例的结果

typefrompdb.exe
usage typefrompdb.exe file.pdb typename  
typefrompdb.exe ntd dr
failed 2find ntd 11

typefrompdb.exe ntdll.pdb _driver_object
succeded 2find ntdll.pdb 11
failed 2find _driver_object 17

typefrompdb.exe ntdll.pdb _DRIVER_OBJECT
succeded 2find ntdll.pdb 11
succeded 2find _DRIVER_OBJECT 17
no of members in struct _DRIVER_OBJECT is  0XF 21    
struct _DRIVER_OBJECT {
Type Leng Tags Name
0x06 0x02 0x10 Type
0x06 0x02 0x10 Size
0x00 0x04 0x0E DeviceObject
0x0E 0x04 0x10 Flags
0x00 0x04 0x0E DriverStart
0x0E 0x04 0x10 DriverSize
0x00 0x04 0x0E DriverSection
0x00 0x04 0x0E DriverExtension
0x00 0x08 0x0B DriverName
0x00 0x04 0x0E HardwareDatabase
0x00 0x04 0x0E FastIoDispatch
0x00 0x04 0x0E DriverInit
0x00 0x04 0x0E DriverStartIo
0x00 0x04 0x0E DriverUnload
0x00 0x70 0x0F MajorFunction

interpretation of results for the typical test case

对典型测试用例结果的解释

grep -iE "btint|btulong|btnotype" cvconst.h
    btNoType = 0,
    btInt = 6,
    btULong = 14,

grep -i -A 35 "enum symtagenum" cvconst.h 
| awk "{ if ( NR==0x0B || NR==0x0E || NR==0x0F || NR==0x10 ) print $0 }"
    SymTagAnnotation,
    SymTagUDT,
    SymTagEnum,
    SymTagFunctionType,

edit
I was never sure this was an answer this was more of a test or experiment in using dia sdk SymLoadModule uses an arbitrary address hardcoded as 0x1000000 you can see that in DBH src in platform sdk samples the compiled binary of the same src is available in windbg installation

编辑我不确定这是一个答案这是更多的测试或实验使用dia sdk SymLoadModule使用任意地址硬编码为0 x1000000胸径src中您可以看到,平台sdk编译后的二进制样品相同的src windbg安装中可用

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\winbase\debug\dbh


//global
DWORD64 gDefaultBaseForVirtualMods;

BOOL init()
{
    int i;

    *gModName = 0;
    gBase = 0;;
    gDefaultBaseForVirtualMods = 0x1000000;

else if (!_tcsicmp(ext, _T(".pdb"))) 
{
    addr = gDefaultBaseForVirtualMods;
    dontopen = true;
} else {
    addr = gDefaultBase;
}


C:\>dbh XXXXXXX\ntdll.pdb t _DRIVER_OBJECT

   name : _DRIVER_OBJECT
   addr :        0
   size : a8
  flags : 0
   type : 1
modbase :  1000000
  value :        0
    reg : 0
  scope : SymTagNull (0)
    tag : SymTagUDT (b)
  index : 1

C:\>

anyway i would reiterate that you are not supposed to use dbghelp functions in windbg extensions read the notes on following links (writing wdbg extensions/ dbgeng extensions / engextcpp function which states that it is not supported to use dbghelp functions in windbg extension

无论如何,我要重申,您不应该在windbg扩展中使用dbghelp函数,请阅读以下链接的说明(编写wdbg扩展/ dbgeng扩展/ engextcpp函数,该函数声明在windbg扩展中不支持使用dbghelp函数

Note   You must not attempt to call any DbgHelp or ImageHlp routines from any debugger extension. Calling these routines is not supported and may cause a variety of problems. 

writing wdbgexts windbg extensions

写作wdbgexts windbg扩展

writing dbgeng windbg extensions

写作dbgeng windbg扩展

writing engextcpp windbg extensions

写作engextcpp windbg扩展

#2


0  

The Debug Interface Access SDK provides APIs for working with the PDB directly:

调试接口访问SDK提供了与PDB直接协作的api:

http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx

http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx

The DIA2Dump sample is full featured and demonstrates how to extract type information.

DIA2Dump示例是完整的,演示了如何提取类型信息。