PE File Analysis
Overview
The Portable Executable (PE) format is the standard binary format for Windows executables (EXE), dynamic-link libraries (DLL), drivers (SYS), and other executable types. Analyzing PE headers, sections, imports, exports, and resources reveals a malware sample's capabilities, compiler information, and anomalies that indicate malicious intent.
PE Structure Overview
┌──────────────────────┐
│ DOS Header │ (MZ signature, e_lfanew pointer)
├──────────────────────┤
│ DOS Stub │ ("This program cannot be run...")
├──────────────────────┤
│ PE Signature │ ("PE\0\0")
├──────────────────────┤
│ COFF File Header │ (machine, sections, timestamp)
├──────────────────────┤
│ Optional Header │ (entry point, image base, subsystem)
├──────────────────────┤
│ Section Headers │ (.text, .data, .rdata, .rsrc, ...)
├──────────────────────┤
│ Section Data │ (actual code and data)
└──────────────────────┘
Analysis with pefile (Python)
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.exe')
# Basic info
print(f"Entry point: {hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)}")
print(f"Image base: {hex(pe.OPTIONAL_HEADER.ImageBase)}")
print(f"Subsystem: {pe.OPTIONAL_HEADER.Subsystem}")
print(f"Machine: {hex(pe.FILE_HEADER.Machine)}")
print(f"Timestamp: {pe.FILE_HEADER.TimeDateStamp}")
# Compilation timestamp (can be faked)
import datetime
timestamp = pe.FILE_HEADER.TimeDateStamp
compile_time = datetime.datetime.utcfromtimestamp(timestamp)
print(f"Compiled: {compile_time}")
# Import hash
print(f"Imphash: {pe.get_imphash()}")
Analyzing Sections
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.exe')
for section in pe.sections:
print(f"Name: {section.Name.decode().rstrip(chr(0))}")
print(f" Virtual Addr: {hex(section.VirtualAddress)}")
print(f" Virtual Size: {hex(section.Misc_VirtualSize)}")
print(f" Raw Size: {hex(section.SizeOfRawData)}")
print(f" Entropy: {section.get_entropy():.2f}")
print(f" Flags: {hex(section.Characteristics)}")
print()
Section Anomalies to Look For
| Anomaly | Indicator |
|---|---|
| High entropy (> 7.0) | Encrypted or compressed data (packed?) |
| Virtual size >> raw size | Section will be unpacked at runtime |
| Raw size = 0 but virtual size > 0 | Data generated at runtime |
.text section is writable |
Self-modifying code |
| Unusual section names | UPX0, .enigma, .themida, etc. (packer names) |
Entry point not in .text |
Entry point in a packer section |
Analyzing Imports
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.exe')
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in pe.DIRECTORY_ENTRY_IMPORT:
print(f"\n{entry.dll.decode()}")
for imp in entry.imports:
name = imp.name.decode() if imp.name else f"ordinal_{imp.ordinal}"
print(f" {name}")
Analyzing Exports
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.dll')
if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
name = exp.name.decode() if exp.name else "N/A"
print(f" {name} @ {hex(pe.OPTIONAL_HEADER.ImageBase + exp.address)}")
Extracting Resources
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.exe')
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
name = pefile.RESOURCE_TYPE.get(resource_type.id, str(resource_type.id))
print(f"Resource type: {name}")
if hasattr(resource_type, 'directory'):
for entry in resource_type.directory.entries:
if hasattr(entry, 'directory'):
for res in entry.directory.entries:
offset = res.data.struct.OffsetToData
size = res.data.struct.Size
print(f" Offset: {hex(offset)}, Size: {size}")
Embedded resources often contain additional payloads, configuration data, or secondary executables.
Analysis with rabin2
# radare2
# https://github.com/radareorg/radare2
# Show binary info (headers, protections)
rabin2 -I sample.exe
# List imports
rabin2 -i sample.exe
# List exports
rabin2 -E sample.exe
# List sections
rabin2 -S sample.exe
# List strings
rabin2 -z sample.exe
# Show entry point
rabin2 -e sample.exe
# Show libraries (DLL dependencies)
rabin2 -l sample.exe
# Show header fields
rabin2 -H sample.exe
# Calculate hashes
rahash2 -a md5,sha256 sample.exe
# Show all info (comprehensive)
rabin2 -g sample.exe
Analysis with objdump
# Display PE file headers
objdump -x sample.exe | head -60
# Display all section headers
objdump -h sample.exe
# Disassemble the .text section
objdump -d sample.exe | head -100
# Show private headers (PE-specific)
objdump -p sample.exe | head -40
Suspicious PE Characteristics
Compilation Timestamp
# pefile
# https://github.com/erocarrera/pefile
import pefile, datetime
pe = pefile.PE('sample.exe')
ts = pe.FILE_HEADER.TimeDateStamp
compile_time = datetime.datetime.utcfromtimestamp(ts)
print(f"Compile time: {compile_time}")
# Red flags:
# - Timestamp in the future
# - Timestamp of 0 (Jan 1, 1970) — stripped/zeroed
# - Very old timestamp for a modern binary
# - Timestamp set to a known Delphi/Borland epoch
DLL Characteristics (ASLR/DEP/SEH)
# pefile
# https://github.com/erocarrera/pefile
import pefile
pe = pefile.PE('sample.exe')
dll_chars = pe.OPTIONAL_HEADER.DllCharacteristics
print(f"ASLR: {bool(dll_chars & 0x0040)}")
print(f"DEP/NX: {bool(dll_chars & 0x0100)}")
print(f"No SEH: {bool(dll_chars & 0x0400)}")
print(f"High entropy VA: {bool(dll_chars & 0x0020)}")
Malware may disable ASLR or DEP for easier exploitation.
Common Suspicious Imports
| DLL | Function | Capability |
|---|---|---|
| kernel32.dll | CreateRemoteThread |
Process injection |
| kernel32.dll | VirtualAllocEx |
Remote memory allocation |
| kernel32.dll | WriteProcessMemory |
Remote code writing |
| kernel32.dll | CreateFileA/W |
File operations |
| kernel32.dll | WinExec, CreateProcessA |
Process execution |
| advapi32.dll | RegSetValueExA |
Registry modification |
| advapi32.dll | OpenProcessToken |
Token manipulation |
| ws2_32.dll | connect, send, recv |
Network communication |
| wininet.dll | InternetOpenA, HttpSendRequestA |
HTTP communication |
| urlmon.dll | URLDownloadToFileA |
File download |
| ntdll.dll | NtUnmapViewOfSection |
Process hollowing |
| advapi32.dll | CryptEncrypt, CryptDecrypt |
Encryption |