Skip to content

Instantly share code, notes, and snippets.

@tuxuser
Last active May 24, 2018 13:02
Show Gist options
  • Save tuxuser/080ea2f95b0efb466c0a68f4f15ebe03 to your computer and use it in GitHub Desktop.
Save tuxuser/080ea2f95b0efb466c0a68f4f15ebe03 to your computer and use it in GitHub Desktop.
PDB and PE download
#!/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