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

时间:2014-07-31 18:38:05

标签: c windows windbg pdb-files dbghelp

我试图编写一个WinDbg调试器扩展,该扩展适用于实时远程目标和崩溃转储。这个扩展分析了一个不透明的内存块,它通过结构偏移向下走,并将它的不同区域转换为已知对象。

结构更改了版本之间的字段/字段顺序,因此我无法在调试器扩展本身中对其进行硬编码(或包含标头)。相反,我想从我有私人符号的pdbs中提取结构信息。

在pdb / image位于加载模块列表中的实时目标上使用它时,这很有效,我可以使用GetFieldOffset之类的函数来获取类中结构中的字段。

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

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

我的问题:当我没有在加载的模块列表中有模块(在错误的上下文中,或分析崩溃转储)时,我无法使用以上功能。

在我分析的内存区域的开头,我已经存储了pdb GUID和age。使用它我可以使用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);

所以我有通往我特定pdb实例的路径,但我不知道从哪里开始。查看DbgHelp.dll公开的Sym* functions,我没有看到任何明显的方法来使用此pdb文件来获取类型信息。诸如SymGetTypeInfo之类的函数需要一个模块库,而我的模块不能加载也不能加载。我只需要结构中字段的字节偏移量。有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

Debug Interface Access SDK提供了直接使用PDB的API:

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

DIA2Dump样本功能齐全,演示了如何提取类型信息。

答案 1 :(得分:0)

下面的POC CODE显示如何使用dia sdk从pdb中提取TypeInfo

//脆弱的代码小心处理

#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; }

头文件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;

已编译并与

相关联
@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
测试用例的

结果

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

解释典型测试用例的结果

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,

修改
我不知道这是一个答案,这更像是使用dia sdk的测试或实验 SymLoadModule uses an arbitrary address hardcoded as 0x1000000你可以在平台sdk示例中DBH src看到windbg安装中可用的同一src的编译二进制文件

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:\>

无论如何{b}扩展中的i would reiterate that you are supposed to use dbghelp functions阅读以下链接的注释(编写wdbg extensions / dbgeng extensions / engextcpp函数,声明不支持使用dbghelp在windbg扩展中的功能

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

writing dbgeng windbg extensions

writing engextcpp windbg extensions