Skip to content

Instantly share code, notes, and snippets.

@lennartblanco
Last active October 18, 2022 08:48
Show Gist options
  • Save lennartblanco/9a70961a5aa66fe49df6 to your computer and use it in GitHub Desktop.
Save lennartblanco/9a70961a5aa66fe49df6 to your computer and use it in GitHub Desktop.
Symstore hashes
#!/usr/bin/env python
"""
Print symstore hash values for PDB amd EXE/DLL files.
Usage:
python symhash.py [file1 [file2 ...]]
This script requires that 'pdbparse' and 'pefile' python packages
are installed. To install required packages with pip run:
pip install pdbparse pefile
"""
from os import path
import pdbparse
import pefile
import sys
def _pdb_hash(filename):
"""
Get symstore hash value for a program database (PDB) file.
Open and parse required parts of the file to calculate
the symstore hash value for the file.
"""
pdb = pdbparse.parse(filename, fast_load=True)
pdb.STREAM_PDB.load()
guid = pdb.STREAM_PDB.GUID
guid_str = "%.8X%.4X%.4X%s" % (guid.Data1, guid.Data2, guid.Data3,
guid.Data4.encode("hex").upper())
return "%s%s" % (guid_str, pdb.STREAM_PDB.Age)
def _pe_hash(file):
"""
Get symstore hash value for a Portable Executable (PE) file.
Open and parse required parts of the file to calculate
the symstore hash value for the file.
"""
pe = pefile.PE(file, fast_load=True)
return "%X%X" % (pe.FILE_HEADER.TimeDateStamp,
pe.OPTIONAL_HEADER.SizeOfImage)
def print_hash(filename):
"""
Print file's type and symstore hash value.
"""
# we are using filename extension to figure out
# file's image type
file_ext = path.splitext(filename)[1][1:].lower()
# get the image specific hash value
if file_ext in {"pdb"}:
img_type = "PDB"
sym_hash = _pdb_hash(filename)
elif file_ext in {"exe", "dll"}:
img_type = "PE"
sym_hash = _pe_hash(filename)
else:
print("%s: unknown file type" % filename)
return
print("%s (%s): %s" % (filename, img_type, sym_hash))
# print hash values for all specified files
for fname in sys.argv[1:]:
print_hash(fname)
@franferrax
Copy link

Just in case someone was searching for the way to map PEs to PDBs:

def _pdb_hash_from_pe(filename):
    """
    Get symstore hash value for a program database (PDB) file, taking
    it from the Portable Executable (PE) file associated with it.

    Open and parse required parts of the file to calculate
    the symstore hash value for the file.
    """

    def is_pdb70_info(s):
        return isinstance(s, pefile.Structure) and s.name == 'CV_INFO_PDB70'

    # NOTE: if we use fast load, it will not parse the DIRECTORY_ENTRY_DEBUG
    pe = pefile.PE(filename, fast_load=False)

    pdb70_info_entries = [item.entry for item in pe.DIRECTORY_ENTRY_DEBUG
                          if is_pdb70_info(item.entry)]
    assert pdb70_info_entries, "This PE file does not have CV_INFO_PDB70 data"
    entry = pdb70_info_entries[0]

    guid_str = "%.8X%.4X%.4X%s" % (
        entry.Signature_Data1, entry.Signature_Data2,
        entry.Signature_Data3, entry.Signature_Data4.encode("hex").upper()
    )

    return "%s%s" % (guid_str, entry.Age)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment