Извлечение информации о структуре из pdb выгруженных модулей

Я пытаюсь написать расширение отладчика WinDbg, которое работает как с живыми удаленными целями, так и с аварийными дампами. Это расширение анализирует непрозрачный блок памяти, проходя по нему через смещения структуры и присваивая различные его области известным объектам.

Структуры изменяют порядок полей/полей между версиями, поэтому я не могу жестко запрограммировать его (или включить заголовки) в самом расширении отладчика. Вместо этого я хотел бы извлечь информацию о структуре из PDB, для которых у меня есть частные символы.

При использовании этого на живой цели, где pdb/image находится в списке загруженных модулей, это прекрасно работает, и я могу использовать такие функции, как GetFieldOffset, чтобы получить поле в структуре класса.

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

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

Моя проблема: когда у меня нет модуля в списке загруженных модулей (либо в неправильном контексте, либо при анализе аварийного дампа), я не могу использовать вышеуказанные функции.

В начале области памяти, которую я анализирую, я сохранил GUID и возраст pdb. Используя это, я могу найти путь к моему pdb в моем символьном пути/кэше символов, используя SymFindFileInPath.

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, но я не уверен, куда идти дальше. Просмотр функций Sym*, предоставленный DbgHelp.dll, я не вижу очевидного способа использовать этот файл pdb для получения информации о типе. Такие функции, как SymGetTypeInfo. требуется модульная база, а мой модуль нет и не может быть загружен. Все, что мне нужно, это байтовое смещение полей внутри структуры. Любые идеи?

Спасибо!


person David    schedule 31.07.2014    source источник
comment
выгруженный модуль не имеет соответствующей записи CvRecord в дампе, поэтому память будет недоступна. Windbg отобразит ?? ?? когда вы пытаетесь просмотреть данные с адреса, это остается истинным, когда вы пытаетесь прочитать что-либо с пользовательским расширением, а также (см. MINIDUMP_MODULE и MINIDUMP_UNLOADED_MODULE) структуры в dbghelp.chm, кстати, имейте в виду, что не рекомендуется использовать функцию dbghelp в windbg расширения напрямую, но используйте предоставленные dbgeng оболочки Idebug**** или инфраструктуру engextcpp. Эти оболочки правильно обращаются к базовым данным (кешированные данные, оперативные данные и т. д.)   -  person blabb    schedule 03.08.2014


Ответы (2)


POC CODE ниже показано, как извлечь TypeInfo из pdb с помощью dia 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; }

содержимое файла заголовка 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 вы можете видеть, что в 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 functions в расширениях Windbg прочитайте примечания по следующим ссылкам (написание функций 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. 

написание расширений wdbgexts для WindBG

написание расширений dbgeng для WindBG

написание расширений engextcpp для WindBG

person blabb    schedule 07.08.2014
comment
Я собираюсь принять это из-за усилий, которые вы приложили, но оказалось, что есть гораздо более простой метод, использующий только dbghelp (который, конечно, является общей оболочкой для diah2, но более надежен для непосредственного использования). По-видимому, достаточно использовать SymLoadModule с произвольным базовым адресом и путем PDB. Отлично! - person David; 11.08.2014

Пакет SDK для доступа к интерфейсу отладки предоставляет API для прямой работы с PDB:

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

Образец DIA2Dump является полнофункциональным и демонстрирует, как извлекать информацию о типе.

person snoone    schedule 04.08.2014