Python PE parsing module for analyzing Portable Executable (PE) files with comprehensive header, section, and directory entry support
—
Access to embedded resources including strings, icons, version information, and other resource types. PE files can contain various resources embedded within the file structure for use by the application.
Parse and navigate the resource directory tree structure.
def parse_resources_directory(self, rva, size=0, base_rva=None, level=0, dirs=None):
"""
Parse resources directory at specified RVA.
Args:
rva (int): RVA of resource directory
size (int): Size of resource directory
base_rva (int, optional): Base RVA for resource calculations
level (int): Current directory level (0=type, 1=name, 2=language)
dirs (list, optional): List to collect directory entries
Populates:
self.DIRECTORY_ENTRY_RESOURCE: ResourceDirData object with resource tree
"""Extract string resources embedded in the PE file.
def get_resources_strings(self):
"""
Get all strings from string table resources.
Returns:
list: List of tuples (language_id, string_id, string_value)
Note:
Extracts strings from RT_STRING resource type, commonly used
for application messages, error text, and UI strings.
"""Parse version information resources containing file metadata.
def parse_version_information(self, version_struct):
"""
Parse version information structure.
Args:
version_struct: Version information resource structure
Returns:
dict: Parsed version information including:
- FileVersion, ProductVersion
- CompanyName, FileDescription
- InternalName, OriginalFilename
- ProductName, LegalCopyright
- And other version fields
"""import pefile
with pefile.PE('executable.exe') as pe:
# Check if resources are present
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
print("Resource Analysis:")
print("-" * 40)
# Walk resource tree
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
# Resource type (RT_ICON, RT_STRING, etc.)
if resource_type.name is not None:
type_name = resource_type.name
else:
type_name = pefile.RESOURCE_TYPE.get(resource_type.struct.Id,
f"Unknown({resource_type.struct.Id})")
print(f"\nResource Type: {type_name}")
# Resource names/IDs within this type
if hasattr(resource_type, 'directory'):
for resource_id in resource_type.directory.entries:
if resource_id.name is not None:
id_name = resource_id.name
else:
id_name = f"ID_{resource_id.struct.Id}"
print(f" Resource: {id_name}")
# Language versions
if hasattr(resource_id, 'directory'):
for resource_lang in resource_id.directory.entries:
lang_id = resource_lang.struct.Id
lang_name = pefile.LANG.get(lang_id >> 10, f"Lang_{lang_id >> 10}")
sublang_id = lang_id & 0x3ff
print(f" Language: {lang_name} (0x{lang_id:04x})")
# Get resource data
data_rva = resource_lang.data.struct.OffsetToData
data_size = resource_lang.data.struct.Size
print(f" Data: RVA=0x{data_rva:08x}, Size={data_size}")
else:
print("No resources found")import pefile
with pefile.PE('executable.exe') as pe:
# Extract string resources
strings = pe.get_resources_strings()
if strings:
print("String Resources:")
print("-" * 40)
for lang_id, string_id, string_value in strings:
# Decode language info
lang_name = pefile.LANG.get(lang_id >> 10, f"Unknown_{lang_id >> 10}")
sublang_id = lang_id & 0x3ff
print(f"Language: {lang_name} (0x{lang_id:04x})")
print(f"String ID: {string_id}")
print(f"Value: {repr(string_value)}")
print()
else:
print("No string resources found")import pefile
def extract_version_info(pe):
"""Extract and display version information."""
if not hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
return None
# Look for version information resource
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if resource_type.struct.Id == pefile.RESOURCE_TYPE['RT_VERSION']:
for resource_id in resource_type.directory.entries:
for resource_lang in resource_id.directory.entries:
# Get version data
data_rva = resource_lang.data.struct.OffsetToData
data_size = resource_lang.data.struct.Size
data = pe.get_data(data_rva, data_size)
# Parse version information
version_info = pe.parse_version_information(data)
return version_info
return None
# Usage
with pefile.PE('executable.exe') as pe:
version_info = extract_version_info(pe)
if version_info:
print("Version Information:")
print("-" * 30)
# Display common version fields
common_fields = [
'FileVersion', 'ProductVersion', 'CompanyName',
'FileDescription', 'InternalName', 'OriginalFilename',
'ProductName', 'LegalCopyright'
]
for field in common_fields:
if field in version_info:
value = version_info[field]
if isinstance(value, bytes):
value = value.decode('utf-8', errors='ignore')
print(f"{field}: {value}")
else:
print("No version information found")import pefile
def extract_icons(pe, output_dir='icons'):
"""Extract icon resources from PE file."""
import os
if not hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
return []
os.makedirs(output_dir, exist_ok=True)
extracted_icons = []
# Find icon resources
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if resource_type.struct.Id == pefile.RESOURCE_TYPE['RT_ICON']:
print("Found icon resources:")
for resource_id in resource_type.directory.entries:
icon_id = resource_id.struct.Id
for resource_lang in resource_id.directory.entries:
lang_id = resource_lang.struct.Id
# Get icon data
data_rva = resource_lang.data.struct.OffsetToData
data_size = resource_lang.data.struct.Size
icon_data = pe.get_data(data_rva, data_size)
# Save icon file
filename = f"{output_dir}/icon_{icon_id}_{lang_id:04x}.ico"
with open(filename, 'wb') as f:
f.write(icon_data)
extracted_icons.append(filename)
print(f" Extracted icon {icon_id}: {filename} ({data_size} bytes)")
elif resource_type.struct.Id == pefile.RESOURCE_TYPE['RT_GROUP_ICON']:
print("Found icon group resources (metadata)")
return extracted_icons
# Usage
with pefile.PE('executable.exe') as pe:
icons = extract_icons(pe)
print(f"Extracted {len(icons)} icons")import pefile
import xml.etree.ElementTree as ET
def extract_manifest(pe):
"""Extract and parse application manifest."""
if not hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
return None
# Look for manifest resource (RT_MANIFEST = 24)
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if resource_type.struct.Id == 24: # RT_MANIFEST
for resource_id in resource_type.directory.entries:
for resource_lang in resource_id.directory.entries:
# Get manifest data
data_rva = resource_lang.data.struct.OffsetToData
data_size = resource_lang.data.struct.Size
manifest_data = pe.get_data(data_rva, data_size)
try:
# Parse XML manifest
manifest_text = manifest_data.decode('utf-8')
return manifest_text
except UnicodeDecodeError:
# Try other encodings
try:
manifest_text = manifest_data.decode('utf-16')
return manifest_text
except:
return manifest_data # Return raw data
return None
# Usage
with pefile.PE('executable.exe') as pe:
manifest = extract_manifest(pe)
if manifest:
print("Application Manifest:")
print("-" * 30)
if isinstance(manifest, str):
# Try to parse XML for better display
try:
root = ET.fromstring(manifest)
# Extract key information
print("Manifest parsed successfully")
# Look for UAC level
for elem in root.iter():
if 'level' in elem.attrib:
print(f"UAC Level: {elem.attrib['level']}")
if 'uiAccess' in elem.attrib:
print(f"UI Access: {elem.attrib['uiAccess']}")
print("\nFull manifest:")
print(manifest)
except ET.ParseError:
print("Manifest (not valid XML):")
print(manifest)
else:
print("Manifest (binary data):")
print(manifest[:200], "..." if len(manifest) > 200 else "")
else:
print("No manifest found")import pefile
def resource_statistics(pe):
"""Generate statistics about resources in PE file."""
if not hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
print("No resources found")
return
stats = {}
total_size = 0
# Count resources by type
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if resource_type.name is not None:
type_name = str(resource_type.name)
else:
type_name = pefile.RESOURCE_TYPE.get(resource_type.struct.Id,
f"Type_{resource_type.struct.Id}")
type_count = 0
type_size = 0
if hasattr(resource_type, 'directory'):
for resource_id in resource_type.directory.entries:
if hasattr(resource_id, 'directory'):
for resource_lang in resource_id.directory.entries:
type_count += 1
size = resource_lang.data.struct.Size
type_size += size
total_size += size
stats[type_name] = {'count': type_count, 'size': type_size}
# Display statistics
print("Resource Statistics:")
print("-" * 50)
print(f"{'Type':<20} {'Count':<8} {'Size':<12} {'Percentage':<10}")
print("-" * 50)
for type_name, info in sorted(stats.items()):
count = info['count']
size = info['size']
percentage = (size / total_size * 100) if total_size > 0 else 0
print(f"{type_name:<20} {count:<8} {size:<12} {percentage:.1f}%")
print("-" * 50)
print(f"{'Total':<20} {sum(s['count'] for s in stats.values()):<8} {total_size:<12} 100.0%")
# Usage
with pefile.PE('executable.exe') as pe:
resource_statistics(pe)Install with Tessl CLI
npx tessl i tessl/pypi-pefile