Last active
May 24, 2018 13:02
-
-
Save tuxuser/080ea2f95b0efb466c0a68f4f15ebe03 to your computer and use it in GitHub Desktop.
PDB and PE download
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
#!/usr/bin/env python | |
""" | |
Based on pdb_downloader.py v0.1 by Steeve Barbeau | |
""" | |
import sys | |
import argparse | |
import requests | |
import pefile | |
import struct | |
import uuid | |
def download_from_symbolserver(filename, fingerprint): | |
headers = {'User-Agent': 'Microsoft-Symbol-Server/10.0.10036.206'} | |
url = 'http://msdl.microsoft.com/download/symbols/{0}/{1}/{0}'.format( | |
filename, fingerprint | |
) | |
print('Downloading from URL: {0}'.format(url)) | |
response = requests.get(url, headers=headers) | |
if response.status_code != 200: | |
print('FAILED downloading, Code: {0}'.format(response.status_code)) | |
return | |
with open(filename, 'wb') as f: | |
f.write(response.content) | |
print('Saved {0}'.format(filename)) | |
def get_pdb_info(filepath): | |
""" | |
Loosely based on: https://github.com/loopCM/chromium/tree/trunk/tools/symsrc | |
# Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
# Use of this source code is governed by a BSD-style license that can be | |
# found in the LICENSE file. | |
""" | |
pe = pefile.PE(filepath) | |
for dbg in pe.DIRECTORY_ENTRY_DEBUG: | |
if dbg.struct.Type != 2: | |
continue | |
off = dbg.struct.AddressOfRawData | |
size = dbg.struct.SizeOfData | |
data = pe.get_memory_mapped_image()[off:off+size] | |
guid = data[4: 20] | |
age = data[20:24] | |
name = data[24: -1] | |
age = struct.unpack('<L', age) | |
fingerprint = uuid.UUID(bytes_le=guid).hex.upper() + ('%X' % age) | |
name = name.decode('utf-8') | |
bs_pos = name.rfind('\\') | |
if bs_pos != -1: | |
name = name[bs_pos + 1:] | |
return name, fingerprint | |
raise Exception('No IMAGE_DEBUG_TYPE_CODEVIEW section found') | |
def get_pe_fingerprint(filepath): | |
pe = pefile.PE(filepath) | |
return "%08X%06x" % ( | |
pe.FILE_HEADER.TimeDateStamp, pe.OPTIONAL_HEADER.SizeOfImage) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument('command', help='Command, either [pdb] or [pe]') | |
parser.add_argument('--pe', help='[pdb] Path of the DLL/EXE to download PDB for') | |
parser.add_argument('--fingerprint', help='[pe] Fingerprint of file to download') | |
parser.add_argument('--filename', help='[pe] Original filename of PE file to download') | |
args = parser.parse_args() | |
filename = None | |
fingerprint = None | |
if args.command not in ['pdb', 'pe']: | |
print('Invalid command [{0}]\n'.format(args.command)) | |
parser.print_help() | |
sys.exit(1) | |
# Symbol Download | |
if args.command == 'pdb' and not args.pe: | |
print('No filepath to source PE file supplied!\n'.format(args.pe)) | |
sys.exit(1) | |
elif args.command == 'pdb': | |
try: | |
filename, fingerprint = get_pdb_info(args.pe) | |
except Exception as e: | |
print('Failed to get PDB info from file: {0}\n'.format(e)) | |
sys.exit(2) | |
# PE file download | |
elif args.command == 'pe' and (not args.fingerprint or not args.filename): | |
print('Insufficient parameters for PE download!\n') | |
parser.print_help() | |
sys.exit(3) | |
elif args.command == 'pe': | |
filename = args.filename | |
fingerprint = args.fingerprint | |
else: | |
print('Something odd happened during argument parsing...\n') | |
parser.print_help() | |
download_from_symbolserver(filename, fingerprint) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment