pefile: Python PE Parsing Library
pefile is a Python module for parsing and working with Portable Executable (PE) files, commonly found on Windows systems. It allows security analysts and developers to inspect various aspects of PE files, such as sections, imports, exports, resources, and header information. The library is actively maintained, with a recent release (2024.8.26) and frequent updates addressing bugs and adding features, primarily focusing on Python 3.
Warnings
- breaking Python 2.x support was officially dropped starting with versions 2021.5.13 and 2021.9.2. Code written for Python 2 will require migration.
- gotcha A bug in `PE.get_data()` (fixed in v2024.8.26) could have led to incorrect data retrieval, especially when dealing with specific PE file structures or data overlays.
- gotcha The internal `__data__` attribute, which holds the raw file content, had issues with closing and reassignment fixed in v2024.8.26. While an internal detail, it might affect scenarios where `PE` objects are extensively modified or reused in memory.
- gotcha Due to the nature of PE files (which can be malformed, packed, or protected), `pefile` might raise `PEFormatError` or other exceptions for certain files. Robust error handling is crucial.
Install
-
pip install pefile
Imports
- PE
import pefile pe = pefile.PE('path/to/executable.exe') - PEFormatError
from pefile import PEFormatError
Quickstart
import pefile
import os
# Create a dummy executable for demonstration if one doesn't exist
dummy_exe_path = 'dummy_app.exe'
if not os.path.exists(dummy_exe_path):
# This is not a real PE file, just a placeholder
with open(dummy_exe_path, 'wb') as f:
f.write(b'MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x0e\x1f\xba\x0e\x00\xb4\x09\xcd\x21\xb8\x01\x4c\xcd\x21This is a dummy executable file.')
try:
pe = pefile.PE(dummy_exe_path)
print(f"[*] Successfully parsed: {dummy_exe_path}")
print(f" Image Base: 0x{pe.OPTIONAL_HEADER.ImageBase:X}")
print(f" Number of Sections: {pe.FILE_HEADER.NumberOfSections}")
print("\n[*] Sections:")
for section in pe.sections:
print(f" Name: {section.Name.decode().strip(chr(0))}, Virtual Address: 0x{section.VirtualAddress:X}, Virtual Size: 0x{section.Misc_VirtualSize:X}")
# Attempt to print imports if any (unlikely for a dummy file)
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
print("\n[*] Imports:")
for entry in pe.DIRECTORY_ENTRY_IMPORT:
print(f" DLL: {entry.dll.decode().strip(chr(0))}")
for imp in entry.imports:
if imp.name:
print(f" Function: {imp.name.decode().strip(chr(0))}")
else:
print(f" Ordinal: {imp.ordinal}")
except pefile.PEFormatError as e:
print(f"[!] PEFormatError: {e}")
except Exception as e:
print(f"[!] An unexpected error occurred: {e}")
finally:
# Clean up the dummy file
if os.path.exists(dummy_exe_path):
os.remove(dummy_exe_path)