4

我正在尝试编写一个适用于实时远程目标和故障转储的 WinDbg 调试器扩展。这个扩展通过结构偏移分析一个不透明的内存块,并将它的不同区域投射到已知对象。

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

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

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

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

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

在我正在分析的内存区域的开头,我存储了 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);

所以我有我的特定 pdb 实例的路径,但我不确定从这里去哪里。查看 DbgHelp.dll 公开的Sym* 函数,我看不到任何明显的方法可以使用此 pdb 文件来获取类型信息。SymGetTypeInfo等函数需要模块库,而我的模块没有也无法加载。我需要的只是结构中字段的字节偏移量。有任何想法吗?

谢谢!

4

2 回答 2

0

调试接口访问 SDK 提供了用于直接使用 PDB 的 API:

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

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

于 2014-08-04T13:15:51.583 回答
0

下面POC CODE显示了如何使用从 pdb 中提取 TypeInfodia sdk

//小心处理脆弱的代码

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

头文件类型的内容来自pdb.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 您可以看到DBH 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:\>

无论如何i would reiterate that you are 不在 supposed to use dbghelp functionswindbg扩展中阅读以下链接上的注释(编写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. 

编写 wdbgexts windbg 扩展

编写 dbgeng windbg 扩展

编写 engextcpp windbg 扩展

于 2014-08-07T11:03:08.963 回答