Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract 128x128 icon bitmap data from EXE in python

I'm trying to extract icons from .exe files in windows using win32gui. I found the functionalities ExtractIconEx() and ExtractIcon().

I am able to get Icons of size 32x32 or 16x16 only from the above functionalities. the following link only answers way to extract 32x32 images. How to extract 32x32 icon bitmap data from EXE and convert it into a PIL Image object?

I need to extract icons of size either 128x128 or greater than that.Any ideas on how to extract the largersize icons from exe files?

like image 512
user3296385 Avatar asked Apr 24 '14 08:04

user3296385


2 Answers

I've made some researches and also post it. If you would like just see the result code (I hope it's exactly what you ask) you could find it after the "horizontal rule" below.

First I tried to use the next code to determine what icon sizes stored in the resources of the file:

# Using LoadLibrary (rather than CreateFile) is required otherwise 
# LoadResource, FindResource and others will fail
PATH = ...  # Valid file path
hlib = win32api.LoadLibrary(PATH)

# This loop should print sizes of resources icons
icon_names = win32api.EnumResourceNames(hlib, win32con.RT_ICON)
for icon_name in icon_names:
    rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
    hicon = win32gui.CreateIconFromResource(rec, True)
    info = win32gui.GetIconInfo(hicon)
    bminfo = win32gui.GetObject(info[3])
    print("%2d: 0x%08X -> %d %d " % (icon_name, hicon, bminfo.bmWidth, bminfo.bmHeight))

While file contains only 16x16 and 32x32 pixels icons everything will be Ok, here the output for Windows XP calculator:

 1: 0x0093051B -> 32 32
 2: 0x005B0513 -> 32 32
 3: 0x007004CB -> 32 32
 4: 0x002E04C9 -> 32 32
 5: 0x033A04C5 -> 32 32
 6: 0x00780487 -> 32 32
 7: 0x0052045D -> 32 32
 8: 0x055D053D -> 32 32

Once I've tried on file with large icon I've get the exception:

Traceback (most recent call last):
  File "extract_icon.py", line 50, in <module>
    hicon = win32gui.CreateIconFromResource(rec, True)
pywintypes.error: (0, 'CreateIconFromResource', 'No error message is available')

After some researches I've figured out that large icon stored not in ico format but in png (for my case).

Of course I don't know what exactly your .exe file (it's internals) but after I've analyze several .exe files that I have located in my PC I've find out that icons large than 32x32 or 16x16 pixels most probably represented by mean of .png files (you could check it using e.g. PE Explorer, trial-version existed).

So to read image from resources I've used the guide on C++. The main goal here is to obtain pointer to the image resource real data and copy it to the Python buffer. And the finish step is save it to the file (I think you could translate it to PIL by yourself).


COMPLETE CODE TO READ LARGE RESOURCE:

# Use wchar_t function version (FindResourceW rather than FindResourceA)
from __future__ import unicode_literals

# pywin32 imports
import pywintypes
import win32ui
import win32gui
import win32con
import win32api
import win32file

# ctypes configuring. pywin32 has no a lot of required functions
import ctypes
import ctypes.util

# memcpy used to copy data from resource storage to our buffer
libc = ctypes.CDLL(ctypes.util.find_library('c'))
libc.memcpy.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
libc.memcpy.restype = ctypes.c_char_p

# All Windows backslashes must be escaped to LoadLibrary worked correctly '\' -> '\\'
PATH = ...

# WARNING: Assumed that icon_name - VALID resource ID
# It can be determined in loop when enumerating resources:
# if exception at CreateIconFromResource raised than this code appropriate
# otherwise resource is standard icon and first code snippet can be used.
# If resources Id exactly known then it can be hardcoded as in this code
icon_name = 1

try:
    hlib = win32api.LoadLibrary(PATH)

    # This part almost identical to C++ 
    hResInfo = ctypes.windll.kernel32.FindResourceW(hlib, icon_name, win32con.RT_ICON)
    size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
    rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
    mem_pointer = ctypes.windll.kernel32.LockResource(rec)

    # And this is some differ (copy data to Python buffer)
    binary_data = (ctypes.c_ubyte * size)()
    libc.memcpy(binary_data, mem_pointer, size)

    # Save it
    with open("icon.png", "wb") as test_file:
        test_file.write(bytearray(binary_data))

except pywintypes.error as error:
    print "ERROR: %s" % error.strerror
    raise

UPDATED:

Code to automatically look up non-icon resources and extract it to file named "Resource_XX":

# Same IMPORT's as previously should be used

# All Windows backslashes must be escaped to LoadLibrary worked correctly '\' -> '\\'
PATH = ...


def extract(rec):
    try:
        hicon = win32gui.CreateIconFromResource(rec, True)
    except pywintypes.error as error:
        # Check on appropriate error
        if error.winerror != 6:
            raise

        print("Resource %2d isn't .ico, extract" % icon_name)
        # This part almost identical to C++ 
        hResInfo = ctypes.windll.kernel32.FindResourceW(hlib, icon_name, win32con.RT_ICON)
        size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
        mem_pointer = ctypes.windll.kernel32.LockResource(rec)

        # And this is some differ (copy data to Python buffer)
        binary_data = (ctypes.c_ubyte * size)()
        libc.memcpy(binary_data, mem_pointer, size)

        # Save it
        with open("Resource_%s.png" % icon_name, "wb") as extract_file:
            extract_file.write(bytearray(binary_data))
    else:
        info = win32gui.GetIconInfo(hicon)
        bminfo = win32gui.GetObject(info[3])
        print("Resource %2d is .ico: 0x%08X -> %d %d " % 
                  (icon_name, hicon, bminfo.bmWidth, bminfo.bmHeight))


try:
    hlib = win32api.LoadLibrary(PATH)
    icon_names = win32api.EnumResourceNames(hlib, win32con.RT_ICON)
    for icon_name in icon_names:
        rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
        extract(rec)

except pywintypes.error as error:
    print "ERROR: %s" % error.strerror
    raise
like image 107
mblw Avatar answered Sep 17 '22 21:09

mblw


I want to extract the default icon and the different sizs. Based on Alexei's answer and Audionautics' answer in the 32x32 thread, here is the code.

# Use wchar_t function version (FindResourceW rather than FindResourceA)
from __future__ import unicode_literals

# pywin32 imports
import win32con
import win32api
import win32file
import win32gui
import win32ui
import pywintypes

# ctypes configuring. pywin32 has no a lot of required functions
import ctypes
import ctypes.util

# memcpy used to copy data from resource storage to our buffer
libc = ctypes.CDLL(ctypes.util.find_library('c'))
libc.memcpy.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
libc.memcpy.restype = ctypes.c_char_p

# patch FindResourceW, ctypes.windll.kernel32.SizeofResource
FindResourceW = ctypes.windll.kernel32.FindResourceW
FindResourceW.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
FindResourceW.restype = ctypes.c_void_p
SizeofResource = ctypes.windll.kernel32.SizeofResource
SizeofResource.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
SizeofResource.restype = ctypes.c_size_t

# Using LoadLibrary (rather than CreateFile) is required otherwise 
# LoadResource, FindResource and others will fail
PATH = "C:\\Program Files\\Internet Explorer\\iexplore.exe"
hlib = win32api.LoadLibraryEx(PATH, 0, 2)

# get icon groups, default is the first group
icon_groups = win32api.EnumResourceNames(hlib, win32con.RT_GROUP_ICON)
group_name = icon_groups[0]
print group_name
hRes = win32api.LoadResource(hlib, win32con.RT_GROUP_ICON, group_name)
mem_icon_dir = ctypes.windll.kernel32.LockResource(hRes)

# 32 bits color; 16 and 256 colors are too old
# iterate through the common sizes
icon_sizes = (16, 24, 32, 48, 96, 256)
for icon_size in icon_sizes:
    icon_name = ctypes.windll.user32.LookupIconIdFromDirectoryEx(mem_icon_dir, True, icon_size, icon_size, 0x00000000);
    hResInfo = FindResourceW(hlib, icon_name, win32con.RT_ICON)
    size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
    rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
    mem_icon = ctypes.windll.kernel32.LockResource(rec)

    # And this is some differ (copy data to Python buffer)
    binary_data = (ctypes.c_ubyte * size)()
    libc.memcpy(binary_data, mem_icon, size)    
    hIconRet = ctypes.windll.user32.CreateIconFromResourceEx(binary_data, size, True, 0x00030000, 0, 0, 0x00000000);
    info = win32gui.GetIconInfo(hIconRet)
    bminfo = win32gui.GetObject(info[4])

    # generate bitmap by drawing the icon
    hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
    hbmp = win32ui.CreateBitmap()
    hbmp.CreateCompatibleBitmap(hdc, bminfo.bmWidth, bminfo.bmHeight)
    hcdc = hdc.CreateCompatibleDC()
    hcdc.SelectObject(hbmp)
    win32gui.DrawIconEx(hcdc.GetHandleOutput(), 0, 0, hIconRet, bminfo.bmWidth, bminfo.bmHeight, 0, 0, 0x0003)
    hbmp.SaveBitmapFile(hcdc, "icon-%03dx%03d-%05d-%03d.bmp" % (bminfo.bmWidth, bminfo.bmHeight, group_name, icon_name))
    win32gui.DestroyIcon(hIconRet)
like image 27
chunki Avatar answered Sep 16 '22 21:09

chunki