Skip to content
Permalink
Browse files

tools/extracticon.py: support PE format

  • Loading branch information...
miniupnp committed May 11, 2019
1 parent 5b25e08 commit 1fd55812859dfe85c574b793e237b6500ee72d0c
Showing with 60 additions and 2 deletions.
  1. +60 −2 tools/extracticon.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab
#
# Extract ICONs from MZ/NE MS Windows executable file
# Extract ICONs from MZ/NE and MZ/PE MS Windows executable files
#

from struct import *
@@ -16,14 +16,72 @@
with open(filename, 'rb') as content_file:
content = content_file.read()

def decode_rsrc_dir(virtual_address, rsrc, offset=0, level=0, rtype=0, rsid=0):
pad = " " * level
characteristic, ts, version_major, version_minor, name_entries, id_entries = unpack_from('<IIHHHH', rsrc, offset)
offset = offset + 16
print '%sversion %d.%d entries : %d, %d' % (pad, version_major, version_minor, name_entries, id_entries)
for i in range(0, name_entries):
name_offset, data_offset = unpack_from('<II', rsrc, offset)
offset = offset + 8
print '%sname 0x%06x data 0x%06x' % (pad, name_offset, data_offset)
for i in range(0, id_entries):
_id, data_offset = unpack_from('<II', rsrc, offset)
# level = 0 _id : type 3 = icon, 14 = group icon
# level = 1 _id : ressource id
# level = 2 _id : language
if level == 0:
rtype = _id
elif level == 1:
rsid = _id
offset = offset + 8
print '%sid 0x%08x data 0x%06x' % (pad, _id, data_offset)
if data_offset & 0x80000000:
decode_rsrc_dir(virtual_address, rsrc, data_offset & 0x7ffffff, level + 1, rtype, rsid)
else:
data, size, codepage = unpack_from('<III', rsrc, data_offset)
realoffset = data - virtual_address
print '%sdata 0x%06x size %d bytes codepage %d' % (pad, realoffset, size, codepage)
# there is 1 header for all the icons...
if rtype == 3: # Icon
icon_data[rsid] = rsrc[realoffset:realoffset+size]
elif rtype == 14: # Icon group
filename = '%04x.ICO' % rsid
with open(filename, 'wb') as icon_file:
icon_file.write(rsrc[realoffset:realoffset+6])
Res, Type, Count = unpack_from('<HHH', rsrc, realoffset)
print pad, Res, Type, Count
Offset = 6 + 16 * Count
for j in range(0, Count):
Width, Height, Ncolor, Res, Planes, Bpp, ByteCount, icon_id = unpack_from('<BBBBHHIH', rsrc, realoffset+6+j*14)
print '%s#%02d %03dx%03d %dcols %dx%dbpp %d bytes at 0x%06x %d' % (pad, j, Width, Height, Ncolor, Planes, Bpp, ByteCount, Offset, icon_id)
icon_file.write(rsrc[realoffset+6+j*14:realoffset+6+j*14+12])
icon_file.write(pack('<I', Offset))
Offset = Offset + len(icon_data[icon_id])
for j in range(0, Count):
Width, Height, Ncolor, Res, Planes, Bpp, ByteCount, icon_id = unpack_from('<BBBBHHIH', rsrc, realoffset+6+j*14)
icon_file.write(icon_data[icon_id])
print '%s%s written' % (pad, filename)

icon_header = {}
icon_data = {}

# RT_GROUP_ICON = 14 = 0x0e
# RT_ICON = 3
if content[0:2] == 'MZ':
newoffset, = unpack_from('<H', content, 0x3C)
if content[newoffset:newoffset+2] == 'NE':
if content[newoffset:newoffset+2] == 'PE':
sections_count, = unpack_from('<H', content, newoffset+6)
size_of_optheader, = unpack_from('<H', content, newoffset+20)
offset = newoffset+24+size_of_optheader
for j in range(0, sections_count):
section_name = content[offset:offset+8].strip("\0")
virtual_size, virtual_offset, section_size, section_offset = unpack_from('<IIII', content, offset + 8)
offset = offset + 40
print 'section %s : 0x%06x %d bytes (virtual 0x%06x %d bytes)' % (section_name, section_offset, section_size, virtual_offset, virtual_size)
if section_name == '.rsrc':
decode_rsrc_dir(virtual_offset, content[section_offset:section_offset+section_size])
elif content[newoffset:newoffset+2] == 'NE':
resoffset, = unpack_from('<H', content, newoffset+0x24)
ressegcount, = unpack_from('<H', content, newoffset+0x34)
#print resoffset, ressegcount

0 comments on commit 1fd5581

Please sign in to comment.
You can’t perform that action at this time.