Python PE parsing module for analyzing Portable Executable (PE) files with comprehensive header, section, and directory entry support
—
Methods for working with PE sections, including accessing section data and metadata. Sections contain the actual code, data, and resources of the PE file, organized into logical segments with specific characteristics and permissions.
Locate and access sections by address or offset.
def get_section_by_rva(self, rva):
"""
Get section containing the specified RVA.
Args:
rva (int): Relative virtual address
Returns:
SectionStructure: Section containing the RVA, or None if not found
"""
def get_section_by_offset(self, offset):
"""
Get section containing the specified file offset.
Args:
offset (int): File offset
Returns:
SectionStructure: Section containing the offset, or None if not found
"""Apply modifications made to section data back to the PE structure.
def merge_modified_section_data(self):
"""
Update PE internal data with modified section data.
This method applies any changes made to section data back to the
main PE data structure, ensuring consistency between section objects
and the underlying file data. Must be called after modifying section
data through section.set_data() or direct manipulation.
"""Individual section objects provide detailed access to section data and properties.
class SectionStructure:
def get_data(self, start=None, length=None, ignore_padding=False):
"""
Get section data.
Args:
start (int, optional): Start offset within section
length (int, optional): Number of bytes to read
ignore_padding (bool): Whether to ignore alignment padding
Returns:
bytes: Section data
"""
def get_entropy(self):
"""
Calculate Shannon entropy of section data.
Returns:
float: Entropy value (0.0 to 8.0), higher values indicate more randomness
"""
def get_hash_md5(self):
"""
Calculate MD5 hash of section data.
Returns:
str: MD5 hash as hexadecimal string
"""
def get_hash_sha1(self):
"""
Calculate SHA-1 hash of section data.
Returns:
str: SHA-1 hash as hexadecimal string
"""
def get_hash_sha256(self):
"""
Calculate SHA-256 hash of section data.
Returns:
str: SHA-256 hash as hexadecimal string
"""
def get_hash_sha512(self):
"""
Calculate SHA-512 hash of section data.
Returns:
str: SHA-512 hash as hexadecimal string
"""
def contains_rva(self, rva):
"""
Check if section contains the specified RVA.
Args:
rva (int): Relative virtual address
Returns:
bool: True if RVA is within section bounds
"""
def contains_offset(self, offset):
"""
Check if section contains the specified file offset.
Args:
offset (int): File offset
Returns:
bool: True if offset is within section bounds
"""Parse section headers from the PE file.
def parse_sections(self, offset):
"""
Parse section headers starting at specified offset.
Args:
offset (int): File offset where section headers begin
Populates:
self.sections: List of SectionStructure objects
"""Each section in the pe.sections list is a SectionStructure object with the following key attributes:
class SectionStructure:
"""Represents a PE file section."""
Name: bytes # Section name (8 bytes, null-padded)
VirtualSize: int # Size of section when loaded in memory
VirtualAddress: int # RVA where section is loaded
SizeOfRawData: int # Size of section in file
PointerToRawData: int # File offset to section data
PointerToRelocations: int # File offset to relocations
PointerToLinenumbers: int # File offset to line numbers
NumberOfRelocations: int # Number of relocations
NumberOfLinenumbers: int # Number of line number entries
Characteristics: int # Section characteristics/flags
def get_data(self, start=None, length=None):
"""Get section data."""
def set_data(self, data):
"""Set section data."""
def get_entropy(self):
"""Calculate section entropy."""
def get_hash_sha1(self):
"""Get SHA1 hash of section data."""
def get_hash_sha256(self):
"""Get SHA256 hash of section data."""
def get_hash_md5(self):
"""Get MD5 hash of section data."""import pefile
with pefile.PE('executable.exe') as pe:
print("Section Analysis:")
print("-" * 60)
print(f"{'Name':<10} {'VirtAddr':<10} {'VirtSize':<10} {'RawSize':<10} {'Entropy':<8}")
print("-" * 60)
for section in pe.sections:
name = section.Name.decode('utf-8').strip('\x00')
virt_addr = f"0x{section.VirtualAddress:08x}"
virt_size = f"0x{section.VirtualSize:08x}"
raw_size = f"0x{section.SizeOfRawData:08x}"
entropy = f"{section.get_entropy():.2f}"
print(f"{name:<10} {virt_addr:<10} {virt_size:<10} {raw_size:<10} {entropy:<8}")import pefile
with pefile.PE('executable.exe') as pe:
print("Section Characteristics:")
print("-" * 40)
for section in pe.sections:
name = section.Name.decode('utf-8').strip('\x00')
characteristics = section.Characteristics
print(f"\nSection: {name}")
print(f"Characteristics: 0x{characteristics:08x}")
# Decode characteristics flags
flags = []
if characteristics & 0x00000020: # IMAGE_SCN_CNT_CODE
flags.append("CODE")
if characteristics & 0x00000040: # IMAGE_SCN_CNT_INITIALIZED_DATA
flags.append("INITIALIZED_DATA")
if characteristics & 0x00000080: # IMAGE_SCN_CNT_UNINITIALIZED_DATA
flags.append("UNINITIALIZED_DATA")
if characteristics & 0x20000000: # IMAGE_SCN_MEM_EXECUTE
flags.append("EXECUTABLE")
if characteristics & 0x40000000: # IMAGE_SCN_MEM_READ
flags.append("READABLE")
if characteristics & 0x80000000: # IMAGE_SCN_MEM_WRITE
flags.append("WRITABLE")
if flags:
print(f"Flags: {', '.join(flags)}")import pefile
import os
with pefile.PE('executable.exe') as pe:
# Create directory for section dumps
output_dir = 'section_dumps'
os.makedirs(output_dir, exist_ok=True)
for i, section in enumerate(pe.sections):
name = section.Name.decode('utf-8').strip('\x00')
# Get section data
section_data = section.get_data()
# Save section to file
filename = f"{output_dir}/{i:02d}_{name}.bin"
with open(filename, 'wb') as f:
f.write(section_data)
print(f"Extracted {name}: {len(section_data)} bytes -> {filename}")
# Calculate hashes
sha256 = section.get_hash_sha256()
md5 = section.get_hash_md5()
entropy = section.get_entropy()
print(f" SHA256: {sha256}")
print(f" MD5: {md5}")
print(f" Entropy: {entropy:.3f}")import pefile
# Load PE file
pe = pefile.PE('executable.exe')
# Find text section
text_section = None
for section in pe.sections:
name = section.Name.decode('utf-8').strip('\x00')
if name == '.text':
text_section = section
break
if text_section:
print(f"Found .text section at RVA 0x{text_section.VirtualAddress:08x}")
# Get current section data
original_data = text_section.get_data()
print(f"Original size: {len(original_data)} bytes")
# Modify section data (example: NOP out first few bytes)
modified_data = bytearray(original_data)
modified_data[0:10] = b'\x90' * 10 # NOP instructions
# Set modified data back to section
text_section.set_data(bytes(modified_data))
# Apply changes to PE structure
pe.merge_modified_section_data()
# Write modified PE
pe.write('modified_executable.exe')
print("Modified executable saved")
pe.close()import pefile
with pefile.PE('executable.exe') as pe:
# Find section containing entry point
entry_point = pe.OPTIONAL_HEADER.AddressOfEntryPoint
entry_section = pe.get_section_by_rva(entry_point)
if entry_section:
name = entry_section.Name.decode('utf-8').strip('\x00')
print(f"Entry point 0x{entry_point:08x} is in section: {name}")
# Calculate offset within section
section_offset = entry_point - entry_section.VirtualAddress
print(f"Offset within section: 0x{section_offset:08x}")
# Find section containing specific file offset
file_offset = 0x1000
offset_section = pe.get_section_by_offset(file_offset)
if offset_section:
name = offset_section.Name.decode('utf-8').strip('\x00')
print(f"File offset 0x{file_offset:08x} is in section: {name}")import pefile
def analyze_entropy(pe):
"""Analyze section entropy to detect packing."""
print("Entropy Analysis:")
print("-" * 30)
high_entropy_sections = []
for section in pe.sections:
name = section.Name.decode('utf-8').strip('\x00')
entropy = section.get_entropy()
print(f"{name:<10}: {entropy:.3f}")
# Flag high entropy sections (possibly packed/encrypted)
if entropy > 7.0: # High entropy threshold
high_entropy_sections.append((name, entropy))
if high_entropy_sections:
print("\nHigh entropy sections (possibly packed):")
for name, entropy in high_entropy_sections:
print(f" {name}: {entropy:.3f}")
return high_entropy_sections
# Usage
with pefile.PE('executable.exe') as pe:
high_entropy = analyze_entropy(pe)import pefile
with pefile.PE('executable.exe') as pe:
file_alignment = pe.OPTIONAL_HEADER.FileAlignment
section_alignment = pe.OPTIONAL_HEADER.SectionAlignment
print(f"File Alignment: 0x{file_alignment:x}")
print(f"Section Alignment: 0x{section_alignment:x}")
print()
for section in pe.sections:
name = section.Name.decode('utf-8').strip('\x00')
# Check alignment
raw_addr_aligned = (section.PointerToRawData % file_alignment) == 0
virt_addr_aligned = (section.VirtualAddress % section_alignment) == 0
print(f"Section {name}:")
print(f" Raw Address: 0x{section.PointerToRawData:08x} (aligned: {raw_addr_aligned})")
print(f" Virtual Address: 0x{section.VirtualAddress:08x} (aligned: {virt_addr_aligned})")Install with Tessl CLI
npx tessl i tessl/pypi-pefile