Skip to content

Load & Apply PDB Symbols

Loads PDB symbols from a file via the PDB plugin, then writes a report of all renamed symbols to disk.

import ida_auto
import ida_loader
import ida_nalt
import ida_netnode
import ida_pro
import idautils
import idc


def load_pdb(pdb_path):
    """Drive the PDB plugin to load symbols for the current image."""
    base = ida_nalt.get_imagebase()

    # Create a new netnode to store the pdb plugin information in the database.
    # Netnodes are modeled on top of a BTree data structure.
    # The netnode for the PDB plugin is "$ pdb".
    n = ida_netnode.netnode()
    n.create("$ pdb")

    # The PDB plugin expects the base address in the altval array.
    n.altset(0, base)
    # The PDB plugin expects the PDB path in the supval array.
    n.supset(0, pdb_path)

    # 3 = don't ask the user for data, but use the information
    # stored in the netnode.
    if ida_loader.load_and_run_plugin("pdb", 3) == 0:
        raise RuntimeError(f"Failed to load PDB plugin for {pdb_path}")

    # After running the plugin, wait for it to finish.
    ida_auto.auto_wait()


def main(output, pdb_path):
    # Wait for initial auto-analysis to finish.
    ida_auto.auto_wait()

    # Snapshot the set of names before loading the PDB.
    before = {name for ea, name in idautils.Names()}

    load_pdb(pdb_path)

    # Snapshot again.
    after = {name for ea, name in idautils.Names()}

    # Compute the newly added names.
    new_names = after - before

    # Write the new names to the output file.
    for ea, name in idautils.Names():
        if name in new_names:
            print(f"{hex(ea)}: {name}", file=output)


if __name__ == "__main__":
    if len(idc.ARGV) < 3:
        print("Usage: load_and_apply_pdb.py <output_path> <pdb_path>")
        ida_pro.qexit(0)
    with open(idc.ARGV[1], "w") as f:
        main(f, idc.ARGV[2])
        f.flush()
    ida_pro.qexit(0)