0

I'm setting up our private symbol server. Everything works great. Observe the following Resharper log when I debug into one of our Nuget packages using symbol server:

Searching for 'ClassLibrary1.Class1' type sources in C:\SNIPPED\SymbolCache\ClassLibrary1.pdb\91180103b9def6ca85f41230aaf9a4611\ClassLibrary1.pdb
Downloader: https ://LOCAL_SYMBOL_SVR/app/sources/builds/id-1641/sources/files/ClassLibrary1/Class1.cs -> ok, 268 bytes

See the hash, 91180103b9def6ca85f41230aaf9a4611? Notice that it is 33 digits.

I figured it might be stored in a PE header, but dumpbin.exe /all DLL doesn't contain the hash in its output.

Where does that hash come from? Is it stored within the DLL somewhere? If so, how and where is it stored?

  • Possible duplicate of [Microsoft Symbol Server / Local Cache Hash Algorithm](https://stackoverflow.com/questions/1419347/microsoft-symbol-server-local-cache-hash-algorithm) – Remus Rusanu Nov 21 '18 at 18:01
  • See the answers at https://stackoverflow.com/questions/1419347/microsoft-symbol-server-local-cache-hash-algorithm – Remus Rusanu Nov 21 '18 at 18:01

1 Answers1

1

if PE build with debug information - must exist IMAGE_DEBUG_DIRECTORY in it with IMAGE_DEBUG_TYPE_CODEVIEW. so first debugger search for array of IMAGE_DEBUG_DIRECTORY elements (it can be multiple). this array located at IMAGE_DIRECTORY_ENTRY_DEBUG data directory. for IMAGE_DEBUG_TYPE_CODEVIEW debug info now locate in format RSDS

struct RSDSI                       // RSDS debug info
{
    DWORD   dwSig;                 // RSDSI
    GUID    guidSig;
    DWORD   age;
    char    szPdb[];
};

the what you called "hash" this is really not hash formated from guidSig and age as %08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x

the dwSig must equal to 'SDSR' and szPdb stored as utf8 string code example:

ULONG FormatPdbPath(PWSTR* ppdbPath, PCWSTR SymbolsPath, PCSTR PdbFileName, LPGUID Signature, DWORD Age)
{
    ULONG UTF8StringByteCount = (ULONG)strlen(PdbFileName) + 1;

    ULONG UnicodeStringLen = MultiByteToWideChar(CP_UTF8, 0, PdbFileName, UTF8StringByteCount, 0, 0);

    if (!UnicodeStringLen)
    {
        return ERROR_GEN_FAILURE;
    }

    if (UnicodeStringLen >= MAXSHORT)
    {
        return ERROR_FILENAME_EXCED_RANGE;
    }

    PWSTR FileName = (PWSTR)alloca(UnicodeStringLen * sizeof(WCHAR));

    UnicodeStringLen = MultiByteToWideChar(CP_UTF8, 0, PdbFileName, UTF8StringByteCount, FileName, UnicodeStringLen);

    if (!UnicodeStringLen)
    {
        return ERROR_GEN_FAILURE;
    }

    if (PWSTR pdbPath = new WCHAR[2 * UnicodeStringLen + wcslen(SymbolsPath) + 42])
    {
        *ppdbPath = pdbPath;

        swprintf(pdbPath, L"%s\\%s\\%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x\\%s", 
            SymbolsPath, FileName, 
            Signature->Data1, Signature->Data2, Signature->Data3,
            Signature->Data4[0], Signature->Data4[1], Signature->Data4[2], Signature->Data4[3], 
            Signature->Data4[4], Signature->Data4[5], Signature->Data4[6], Signature->Data4[7], 
            Age, FileName);

        return NOERROR;
    }

    return ERROR_NO_SYSTEM_RESOURCES;
}

ULONG FormatPdbPath(PWSTR* ppdbPath, PCWSTR SymbolsPath, PCWSTR lpszName)
{
    HMODULE hmod = LoadLibraryExW(lpszName, 0, LOAD_LIBRARY_AS_DATAFILE);

    if (!hmod) return GetLastError();

    ULONG status = ERROR_NOT_FOUND;

    DWORD cb;
    BOOLEAN bMappedAsImage = !((DWORD_PTR)hmod & (PAGE_SIZE - 1));

    PIMAGE_DEBUG_DIRECTORY pidd = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(hmod, bMappedAsImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &cb);

    if (pidd && cb && !(cb % sizeof(IMAGE_DEBUG_DIRECTORY)))
    {
        do 
        {
            struct RSDSI                       // RSDS debug info
            {
                DWORD   dwSig;                 // RSDSI
                GUID    guidSig;
                DWORD   age;
                char    szPdb[];
            };

            if (pidd->Type == IMAGE_DEBUG_TYPE_CODEVIEW && pidd->SizeOfData > sizeof(RSDSI))
            {
                if (DWORD PointerToRawData = bMappedAsImage ? pidd->AddressOfRawData : pidd->PointerToRawData)
                {
                    RSDSI* lpcvh = (RSDSI*)RtlOffsetToPointer(PAGE_ALIGN(hmod), PointerToRawData);

                    if (lpcvh->dwSig == 'SDSR')
                    {
                        PCSTR szPdb = lpcvh->szPdb, c = strrchr(szPdb, L'\\');

                        if (c)
                        {
                            szPdb = c + 1;
                        }

                        status = FormatPdbPath(ppdbPath, SymbolsPath, szPdb, &lpcvh->guidSig, lpcvh->age);

                        break;
                    }
                }
            }

        } while (pidd++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY));
    }

    FreeLibrary(hmod);

    return status;
}

void test(PCWSTR SymbolsPath, PCWSTR lpszName)
{
    PWSTR pdbPath;
    if (!FormatPdbPath(&pdbPath, SymbolsPath, lpszName))
    {
        DbgPrint("%S\n", pdbPath);
        delete [] pdbPath;
    }
}

void test2(PCWSTR SymbolsPath = L"C:\\SNIPPED\\SymbolCache")
{
    WCHAR myExe[MAX_PATH];
    GetModuleFileNameW(0, myExe, RTL_NUMBER_OF(myExe));
    test(SymbolsPath, myExe);
    test(SymbolsPath, L"hal.dll");
    test(SymbolsPath, L"drivers/ntfs.sys");
    test(SymbolsPath, L"kernel32.dll");
}
RbMm
  • 25,803
  • 2
  • 21
  • 40
  • It would have been good if you also tell what exactly is PAGE_SIZE and PAGE_ALIGN – rez Sep 02 '20 at 12:23
  • @AssassiN - look in *wdm.h* – RbMm Sep 02 '20 at 12:52
  • 1
    `#define PAGE_ALIGN(Va) ((PVOID)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)))` – RbMm Sep 02 '20 at 12:53
  • `#define PAGE_SIZE 0x1000` – RbMm Sep 02 '20 at 12:53
  • Can I ask another question from you? Where do you know these precise information from? I've been searching on google for hours but I couldn't find a decent information about RSDSI aka IMAGE_DEBUG_DIRECTORY_RAW, I could find https://github.com/rajkumar-rangaraj/PDB-Downloader but he's a microsoft employee. – rez Sep 02 '20 at 17:27
  • @AssassiN - you can compare with my [*PDB Downloader (64)*](https://github.com/rbmm/partial/blob/master/GETPDB/X64/GetPdb.exe) and [*PDB Downloader (32)*](https://github.com/rbmm/partial/blob/master/GETPDB/X86/GetPdb.exe) - this is lightweight tool - near 50 KB in size. and i am not employee at any place – RbMm Sep 02 '20 at 21:10