Created
February 11, 2025 12:28
-
-
Save marshal20/46977fe656ae2a8312c8e1c0352988e5 to your computer and use it in GitHub Desktop.
Command line tool to get program database (PDB) debug symbols file URL from windows server. With options to download the PDB file directly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!python3 | |
| """ | |
| Command line tool to get program database (PDB) debug symbols file URL from windows server. | |
| With options to download the PDB file directly. | |
| Credits to **Barakat@github** for the original script, though it didn't work without modifications: | |
| https://gist.github.com/Barakat/e20ec993748c6ab382d727f08eaa523e | |
| I fixed the GUID calculation which were ignoring Signature_Data5 and Signature_Data6 thus not creating a complete GUID. | |
| Also I added the ability to download the file directly and a simple command line functionality. | |
| example: | |
| ```console | |
| $ python pdburl.py -d kernel32.dll | |
| PDB symbols file for kernel32.dll: | |
| https://msdl.microsoft.com/download/symbols/kernel32.pdb/5A77DE8CE8D58731F0EA38F1C92F48D81/kernel32.pdb | |
| Downloading... | |
| Downloaded: https://msdl.microsoft.com/download/symbols/kernel32.pdb/5A77DE8CE8D58731F0EA38F1C92F48D81/kernel32.pdb | |
| To: kernel32.pdb | |
| ``` | |
| """ | |
| import os | |
| import argparse | |
| import pefile | |
| import urllib.request | |
| SYMBOLS_SERVER = 'https://msdl.microsoft.com/download/symbols' | |
| def get_pdb_symbol_url(binary_file_path: str): | |
| """ | |
| Gets the PDB debug symbols file of the given binary file from windows server. | |
| Arguments: | |
| binary_file_path: Binary file to get PDB to. | |
| """ | |
| pe = pefile.PE(binary_file_path, fast_load=True) | |
| pe.parse_data_directories() | |
| for directory in pe.DIRECTORY_ENTRY_DEBUG: | |
| debug_entry = directory.entry | |
| if hasattr(debug_entry, 'PdbFileName'): | |
| pdb_file = debug_entry.PdbFileName[:-1].decode('ascii') | |
| guid = '' | |
| guid += f'{debug_entry.Signature_Data1:08x}' | |
| guid += f'{debug_entry.Signature_Data2:04x}' | |
| guid += f'{debug_entry.Signature_Data3:04x}' | |
| guid += f'{debug_entry.Signature_Data4:02x}' | |
| guid += f'{debug_entry.Signature_Data5:02x}' | |
| guid += f'{int.from_bytes(debug_entry.Signature_Data6, byteorder='big'):012x}' | |
| guid = guid.upper() | |
| url = f'{SYMBOLS_SERVER}/{pdb_file}/{guid}{debug_entry.Age:x}/{pdb_file}' | |
| return url | |
| return None | |
| def downlod_pdb_symbol_file(binary_file_path: str): | |
| """ | |
| Downloads the PDB debug symbols file of the given binary file from windows server. | |
| Arguments: | |
| binary_file_path: Binary file to get PDB to. | |
| """ | |
| # get url | |
| url = get_pdb_symbol_url(binary_file_path) | |
| print(f"PDB symbols file for {os.path.split(binary_file_path)[1]}:") | |
| print(f"\t{url}") | |
| # calculate output file path | |
| output_dir = os.path.split(binary_file_path)[0] | |
| output_file_name = os.path.split(url)[1] | |
| output_file_path = os.path.join(output_dir, output_file_name) | |
| # download | |
| print(f"Downloading...") | |
| urllib.request.urlretrieve(url, output_file_path) | |
| print(f"\tDownloaded: {url}") | |
| print(f"\tTo: {output_file_path}") | |
| def main(): | |
| """ | |
| Gets debug symbols url of a windows binary. | |
| """ | |
| # parse arguments | |
| parser = argparse.ArgumentParser(description='Command line tool to get PDB symbols file URL from windows server for a windows binary file with the ability to download it.') | |
| parser.add_argument('input', type=str, help='Input binary file.') | |
| parser.add_argument('-d', "--download", action='store_true', help='Download the PDB symbols file instead of just outputing the URL.') | |
| args = parser.parse_args() | |
| # handle based on the download switch | |
| if args.download: | |
| downlod_pdb_symbol_file(args.input) | |
| else: | |
| # just print the URL | |
| url = get_pdb_symbol_url(args.input) | |
| print(f"PDB symbols file for {os.path.split(args.input)[1]}:") | |
| print(f"\t{url}") | |
| if __name__ == '__main__': | |
| main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment