编程与调试 -- 关于 PDB 与 EXE/DLL 文件的匹配问题

活着的虫子 from 为虫子生,为虫子死,为虫子奋斗一辈子 关于 PDB 与 EXE/DLL 文件的匹配问题

http://www.debuginfo.com/tools.html

DIA2Dump

regsvr32.exe "C:\kSource\pythonx\filetool\DIA SDK\bin\msdia140.dll"
regsvr64.exe "C:\kSource\pythonx\filetool\DIA SDK\bin\msdia140.dll"

C:\Windows\System32\regsvr32.exe "C:\kSource\pythonx\filetool\DIA SDK\bin\amd64\msdia140.dll"
C:\Windows\SysWOW64\regsvr32.exe "C:\kSource\pythonx\filetool\DIA SDK\bin\amd64\msdia140.dll"
  • Minidumps 和 modules 匹配
  • moyix / pdbparse

  • willglynn / pdb – A parser for Microsoft PDB (Program Database) debugging information
  • horsicq / PDBRipper – PDBRipper is a utility for extract an information from PDB-files.

ChkMatch

ChkMatch can be used to check whether an executable and debug information file match. It can also be used to enforce matching between an executable and debug information file, if they are compatible. For more information about debug information matching and related issues, see this article. http://www.debuginfo.com/articles/debuginfomatch.html


Debug information roadmap

Unique identifier explained

PE format

判断 Exe(DLL) 和符号文件是否匹配—验证模块和符号文件是否匹配的工具和方法 当我们进行程序调试时,有时调试器会直接告诉你符号文件不对,或则显示出的调用栈不对,当你怀疑符号文件不匹配时,如何确定呢?

如果是用 windbg 调试,请用 !chksym 模块名


比如,匹配的时候

不匹配的时候

静态检查—symchk.exe

例用 Windows 调试工具集里的工具 symchk.exe symchk xxxx( 模块 ) /v /s .


不匹配时输出

匹配时

静态检查—chkmatch.exe

从这里下载 http://www.debuginfo.com/download/chkmatch.zip chkmatch -c


不匹配时

匹配时

驱动中解析 pe 文件之 pdb

SymFindFileInPath 是 dbghelp.dll 里的函数,但是他也用到了 symsrv.dll,所以我们必须把写好的程序和这两个 dll 放在一起,否则函数 SymFindFileInPath 会返回错误。 from

BOOL SymFindFileInPath(
    HANDLE hprocess,
    LPSTR  SearchPath,
    LPSTR  FileName,
    PVOID  id,
    DWORD  two,
    DWORD  three,
    DWORD  flags,
    LPSTR  FilePath,
    PFINDFILEINPATHCALLBACK callback,
    PVOID  context
);

from

#include <ntifs.h>
#include <windef.h>
#include "ntimage.h"

#define NB10_SIG    '01BN'
#define RSDS_SIG    'SDSR'
typedef struct CV_HEADER
{
    DWORD Signature;
    DWORD Offset;
} CV_HEADER;

typedef struct CV_INFO_PDB20
{
    CV_HEADER    CvHeader;
    DWORD        Signature;
    DWORD        Age;
    BYTE         PdbFileName[1];
} CV_INFO_PDB20;
typedef struct CV_INFO_PDB70
{
    DWORD    CvSignature;
    GUID     Signature;
    DWORD    Age;
    BYTE     PdbFileName[1];
} CV_INFO_PDB70;

BOOL PeIsRegionValid(PVOID Base, DWORD Size, PVOID Addr, DWORD RegionSize)
{
    return ((PBYTE)Addr >= (PBYTE)Base && ((PBYTE)Addr + RegionSize) <= ((PBYTE)Base + Size));
}

// 返回 TRUE 但 PdbStr 为空意思是找过了确实没有 PDB
BOOLEAN PeGetPdb(PVOID ImageBase, DWORD ImageSize, PCHAR PdbStr)
{
    PBYTE Base = (PBYTE)ImageBase;
    BOOLEAN Result = FALSE;
    CV_HEADER* CvInfo;
    PIMAGE_DEBUG_DIRECTORY DbgDir;
    ULONG PdbNameSize = 0;

    __try
    {
        do
        {
            PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)Base;
            PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)(Base + DosHeader->e_lfanew);
            PIMAGE_OPTIONAL_HEADER      OptionalHeader;
            PIMAGE_OPTIONAL_HEADER64    OptionalHeader64;
            PIMAGE_OPTIONAL_HEADER32    OptionalHeader32;
            DWORD DbgDirRva = 0;

            // PE 解析代码
            OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(Base + DosHeader->e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader));
            if (OptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)    // PE32+  x64
            {
                OptionalHeader64 = (PIMAGE_OPTIONAL_HEADER64)OptionalHeader;
                DbgDirRva = OptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
            }
            else    // PE32   x86
            {
                OptionalHeader32 = (PIMAGE_OPTIONAL_HEADER32)OptionalHeader;
                DbgDirRva = OptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
            }

            DbgDir = (PIMAGE_DEBUG_DIRECTORY)(Base + DbgDirRva);
            if (!DbgDir)
                break;

            ProbeForRead(DbgDir, sizeof(IMAGE_DEBUG_DIRECTORY), 1);

            Result = TRUE; // 到此表示解析正常 能不能找到 PDB 就看有没有了

            if (!DbgDir->AddressOfRawData || DbgDir->Type != IMAGE_DEBUG_TYPE_CODEVIEW)
                break;

            CvInfo = (CV_HEADER*)(Base + DbgDir->AddressOfRawData);
            if (!PeIsRegionValid(Base, ImageSize, CvInfo, sizeof(CV_HEADER)))
                break;

            if (CvInfo->Signature == NB10_SIG) // VC6.0 (GBK)
            {
                if (!PeIsRegionValid(Base, ImageSize, CvInfo, sizeof(CV_INFO_PDB20)+MAX_PATH))
                    break;

                PdbNameSize = strlen((CHAR*)((CV_INFO_PDB20*)CvInfo)->PdbFileName);
                if (!PdbNameSize || PdbNameSize >= MAX_PATH)
                    break;

                RtlCopyMemory(PdbStr, (CHAR*)((CV_INFO_PDB20*)CvInfo)->PdbFileName, PdbNameSize);
            }
            else if (CvInfo->Signature == RSDS_SIG) // VS2003+ (UTF-8)
            {
                if (!PeIsRegionValid(Base, ImageSize, CvInfo, sizeof(CV_INFO_PDB70)+MAX_PATH))
                    break;

                PdbNameSize = strlen((CHAR*)((CV_INFO_PDB70*)CvInfo)->PdbFileName);
                if (!PdbNameSize || PdbNameSize >= MAX_PATH)
                    break;

                RtlCopyMemory(PdbStr, (CHAR*)((CV_INFO_PDB70*)CvInfo)->PdbFileName, PdbNameSize);
            }
        } while (0);

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        KdPrint(("EXCEPTION_EXECUTE_HANDLER\n"));
        Result = FALSE;
    }

    return Result;
}

BOOLEAN PeGetFilePdb(PUNICODE_STRING pFilePath, PCHAR PdbStr)
{
    BOOLEAN Result = FALSE;
    SIZE_T Size = 0;
    PVOID BaseAddress = CreateMapFileAndGetBaseAddr(pFilePath, &Size);
    if (NULL == BaseAddress)
        return FALSE;

    Result = PeGetPdb(BaseAddress, Size, PdbStr);

    ZwUnmapViewOfSection(ZwCurrentProcess(), BaseAddress);
    return Result;
}

参考资料快照
参考资料快照

本文短链接:
If you have any questions or feedback, please reach out .