# pylint: disable=no-member import struct from io import BytesIO try: import pefile PEFILE_AVAILABLE = True except ImportError: pefile = None PEFILE_AVAILABLE = False from PIL import Image # From https://github.com/firodj/extract-icon-py class ExtractIcon(object): GRPICONDIRENTRY_format = ( "GRPICONDIRENTRY", ("B,Width", "B,Height", "B,ColorCount", "B,Reserved", "H,Planes", "H,BitCount", "I,BytesInRes", "H,ID"), ) GRPICONDIR_format = ("GRPICONDIR", ("H,Reserved", "H,Type", "H,Count")) RES_ICON = 1 RES_CURSOR = 2 def __init__(self, filepath): self.pe = pefile.PE(filepath) def find_resource_base(self, res_type): if hasattr(self.pe, "DIRECTORY_ENTRY_RESOURCE"): try: rt_base_idx = [entry.id for entry in self.pe.DIRECTORY_ENTRY_RESOURCE.entries].index( pefile.RESOURCE_TYPE[res_type] ) if rt_base_idx is not None: return self.pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_base_idx] except (ValueError, IndexError): pass # if the resource is not found or the index is bogus return None def find_resource(self, res_type, res_index): rt_base_dir = self.find_resource_base(res_type) if not rt_base_dir: return None if res_index < 0: try: idx = [entry.id for entry in rt_base_dir.directory.entries].index(-res_index) except: return None else: idx = res_index if res_index < len(rt_base_dir.directory.entries) else None if idx is None: return None test_res_dir = rt_base_dir.directory.entries[idx] res_dir = test_res_dir if test_res_dir.struct.DataIsDirectory: # another Directory # probably language take the first one res_dir = test_res_dir.directory.entries[0] if res_dir.struct.DataIsDirectory: # Ooooooooooiconoo no !! another Directory !!! return None return res_dir def get_group_icons(self): rt_base_dir = self.find_resource_base("RT_GROUP_ICON") if not rt_base_dir: return [] groups = [] for res_index in range(0, len(rt_base_dir.directory.entries)): grp_icon_dir_entry = self.find_resource("RT_GROUP_ICON", res_index) if not grp_icon_dir_entry: continue data_rva = grp_icon_dir_entry.data.struct.OffsetToData size = grp_icon_dir_entry.data.struct.Size data = self.pe.get_memory_mapped_image()[data_rva : data_rva + size] file_offset = self.pe.get_offset_from_rva(data_rva) grp_icon_dir = pefile.Structure(self.GRPICONDIR_format, file_offset=file_offset) grp_icon_dir.__unpack__(data) if grp_icon_dir.Reserved != 0 or grp_icon_dir.Type != self.RES_ICON: continue offset = grp_icon_dir.sizeof() entries = [] for _idx in range(0, grp_icon_dir.Count): grp_icon = pefile.Structure(self.GRPICONDIRENTRY_format, file_offset=file_offset + offset) grp_icon.__unpack__(data[offset:]) offset += grp_icon.sizeof() entries.append(grp_icon) groups.append(entries) return groups def get_icon(self, index): icon_entry = self.find_resource("RT_ICON", -index) if not icon_entry: return None data_rva = icon_entry.data.struct.OffsetToData size = icon_entry.data.struct.Size data = self.pe.get_memory_mapped_image()[data_rva : data_rva + size] return data def export_raw(self, entries, index=None): if index is not None: entries = entries[index : index + 1] ico = struct.pack("