Skip to content

Instantly share code, notes, and snippets.

@dnet
Created August 31, 2016 09:23
Show Gist options
  • Save dnet/07b96ae069770921673cbc143b665382 to your computer and use it in GitHub Desktop.
Save dnet/07b96ae069770921673cbc143b665382 to your computer and use it in GitHub Desktop.
Extracting main icon from 64-bit PE (Windows EXE) files in Python 2.x using 7z (p7zip)
#!/usr/bin/env python
import subprocess, tempfile, struct, shutil, os
HDR_FMT = '<hhh'
HDR_LEN = struct.calcsize(HDR_FMT)
def extract_64bit_ico(exefn, icofn):
d = tempfile.mkdtemp()
gis = os.path.join(d, '.rsrc', 'GROUP_ICON')
iis = os.path.join(d, '.rsrc', 'ICON')
entries = []
try:
subprocess.check_call(['7z', '-o' + d, 'x', exefn, '.rsrc/ICON', '.rsrc/GROUP_ICON'])
with open(os.path.join(gis, sorted(os.listdir(gis))[0]), 'rb') as group:
header = group.read(HDR_LEN)
reserved, img_type, no_images = struct.unpack(HDR_FMT, header)
pos = no_images * 16 + HDR_LEN
with open(icofn, 'wb') as ico_out:
ico_out.write(header)
for _ in xrange(no_images):
hdr, rsrc_id = struct.unpack('<12sH', group.read(14))
fn = os.path.join(iis, str(rsrc_id))
if os.path.exists(fn):
with open(fn, 'rb') as png:
payload = png.read()
else:
with open(fn + '.ico', 'rb') as ico_in:
ico_in.seek(HDR_LEN)
hdr = ico_in.read(16)
payload = ico_in.read(struct.unpack('<I', hdr[8:12])[0])
entries.append(payload)
ico_out.write(hdr[:12] + struct.pack('<I', pos))
pos += len(payload)
ico_out.write(''.join(entries))
finally:
shutil.rmtree(d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment