0
# PE Format
1
2
Complete support for PE (Portable Executable) format used by Windows executables, DLLs, and system files. PE format provides comprehensive metadata for Windows loading, imports/exports, resources, and code signing with extensive Windows-specific features.
3
4
## Capabilities
5
6
### PE Parsing
7
8
Parse PE files with format-specific configuration and validation options.
9
10
```python { .api }
11
def parse(filename: str, config: ParserConfig = None) -> Optional[Binary]:
12
"""Parse PE file from filesystem path."""
13
14
def parse(raw: Sequence[int], config: ParserConfig = None) -> Optional[Binary]:
15
"""Parse PE from raw bytes."""
16
17
def parse(obj: Union[io.IOBase, os.PathLike], config: ParserConfig = None) -> Optional[Binary]:
18
"""Parse PE from file-like object."""
19
20
def get_type(file: Union[str, Sequence[int]]) -> Union[PE_TYPE, lief_errors]:
21
"""Determine PE type (PE32 or PE32+)."""
22
23
class ParserConfig:
24
parse_imports: bool
25
parse_exports: bool
26
parse_resources: bool
27
parse_relocations: bool
28
parse_debug: bool
29
parse_tls: bool
30
parse_load_config: bool
31
parse_exceptions: bool
32
parse_signatures: bool
33
parse_overlay: bool
34
35
enum PE_TYPE:
36
PE32 = 0
37
PE32_PLUS = 1
38
```
39
40
Usage example:
41
```python
42
import lief.PE as PE
43
44
# Check PE type first
45
pe_type = PE.get_type("C:\\Windows\\System32\\kernel32.dll")
46
print(f"PE type: {pe_type}")
47
48
# Parse with configuration
49
config = PE.ParserConfig()
50
config.parse_imports = True
51
config.parse_exports = True
52
config.parse_resources = True
53
binary = PE.parse("C:\\Windows\\System32\\kernel32.dll", config)
54
```
55
56
### PE Binary Operations
57
58
PE-specific binary manipulation with Windows executable features.
59
60
```python { .api }
61
class Binary(lief.Binary):
62
dos_header: DosHeader
63
header: Header
64
optional_header: OptionalHeader
65
sections: Iterator[Section]
66
imports: Iterator[Import]
67
exports: Optional[Export]
68
resources: Optional[ResourceNode]
69
relocations: Iterator[Relocation]
70
tls: Optional[TLS]
71
load_configuration: Optional[LoadConfiguration]
72
signatures: Iterator[Signature]
73
debug: Iterator[Debug]
74
overlay: memoryview
75
dos_stub: memoryview
76
rich_header: Optional[RichHeader]
77
78
def add_section(self, section: Section) -> Section
79
def remove_section(self, name: str, clear: bool = False) -> None
80
def add_library(self, library: str) -> Import
81
def remove_library(self, library: str) -> None
82
def add_import_function(self, library: str, function: str) -> ImportEntry
83
def remove_import_function(self, library: str, function: str) -> None
84
def has_import(self, library: str) -> bool
85
def get_import(self, library: str) -> Optional[Import]
86
def has_signature(self) -> bool
87
def verify_signature(self) -> Signature.VERIFICATION_FLAGS
88
def authentihash(self, algorithm: ALGORITHMS) -> List[int]
89
```
90
91
Usage example:
92
```python
93
binary = PE.parse("C:\\Windows\\System32\\notepad.exe")
94
95
# Add new import
96
import_lib = binary.add_library("user32.dll")
97
entry = binary.add_import_function("user32.dll", "MessageBoxA")
98
print(f"Added import: {entry.name}")
99
100
# Check code signing
101
if binary.has_signature():
102
verification = binary.verify_signature()
103
print(f"Signature verification: {verification}")
104
105
# Calculate authentihash for verification
106
auth_hash = binary.authentihash(PE.ALGORITHMS.SHA_256)
107
print(f"Authentihash: {bytes(auth_hash).hex()}")
108
```
109
110
### DOS and PE Headers
111
112
Analyze DOS header, PE header, and optional header information.
113
114
```python { .api }
115
class DosHeader(lief.Object):
116
magic: int
117
bytes_on_last_page: int
118
pages_in_file: int
119
relocations: int
120
size_of_header: int
121
minimum_extra_paragraphs: int
122
maximum_extra_paragraphs: int
123
initial_relative_ss: int
124
initial_sp: int
125
checksum: int
126
initial_ip: int
127
initial_relative_cs: int
128
addr_relocation_table: int
129
overlay_number: int
130
reserved: List[int]
131
oem_id: int
132
oem_info: int
133
reserved2: List[int]
134
addr_new_exe_header: int
135
136
class Header(lief.Object):
137
machine: MACHINE_TYPES
138
number_of_sections: int
139
time_date_stamp: int
140
pointer_to_symbol_table: int
141
number_of_symbols: int
142
size_of_optional_header: int
143
characteristics: HEADER_CHARACTERISTICS
144
145
class OptionalHeader(lief.Object):
146
magic: PE_TYPE
147
major_linker_version: int
148
minor_linker_version: int
149
size_of_code: int
150
size_of_initialized_data: int
151
size_of_uninitialized_data: int
152
addr_of_entry_point: int
153
base_of_code: int
154
image_base: int
155
section_alignment: int
156
file_alignment: int
157
major_os_version: int
158
minor_os_version: int
159
major_image_version: int
160
minor_image_version: int
161
major_subsystem_version: int
162
minor_subsystem_version: int
163
win32_version_value: int
164
size_of_image: int
165
size_of_headers: int
166
checksum: int
167
subsystem: SUBSYSTEM
168
dll_characteristics: DLL_CHARACTERISTICS
169
size_of_stack_reserve: int
170
size_of_stack_commit: int
171
size_of_heap_reserve: int
172
size_of_heap_commit: int
173
loader_flags: int
174
number_of_rva_and_size: int
175
176
enum MACHINE_TYPES:
177
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
178
IMAGE_FILE_MACHINE_I386 = 0x14c
179
IMAGE_FILE_MACHINE_AMD64 = 0x8664
180
IMAGE_FILE_MACHINE_ARM = 0x1c0
181
IMAGE_FILE_MACHINE_ARM64 = 0xaa64
182
183
enum SUBSYSTEM:
184
IMAGE_SUBSYSTEM_UNKNOWN = 0
185
IMAGE_SUBSYSTEM_NATIVE = 1
186
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
187
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
188
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9
189
```
190
191
Usage example:
192
```python
193
binary = PE.parse("C:\\Windows\\System32\\calc.exe")
194
195
# DOS header analysis
196
dos = binary.dos_header
197
print(f"DOS signature: 0x{dos.magic:x}")
198
print(f"PE header offset: 0x{dos.addr_new_exe_header:x}")
199
200
# PE header analysis
201
header = binary.header
202
print(f"Machine type: {header.machine}")
203
print(f"Number of sections: {header.number_of_sections}")
204
print(f"Timestamp: {header.time_date_stamp}")
205
206
# Optional header analysis
207
opt = binary.optional_header
208
print(f"Entry point: 0x{opt.addr_of_entry_point:x}")
209
print(f"Image base: 0x{opt.image_base:x}")
210
print(f"Subsystem: {opt.subsystem}")
211
```
212
213
### Import/Export Analysis
214
215
Comprehensive import and export table analysis with ordinal resolution.
216
217
```python { .api }
218
class Import(lief.Object):
219
name: str
220
import_address_table_rva: int
221
import_lookup_table_rva: int
222
entries: Iterator[ImportEntry]
223
224
def get_function_rva_from_iat(self, function: str) -> int
225
def add_entry(self, entry: ImportEntry) -> ImportEntry
226
227
class ImportEntry(lief.Object):
228
name: str
229
data: int
230
ordinal: int
231
hint: int
232
iat_value: int
233
234
def is_ordinal(self) -> bool
235
236
class Export(lief.Object):
237
export_flags: int
238
timestamp: int
239
major_version: int
240
minor_version: int
241
ordinal_base: int
242
name: str
243
entries: Iterator[ExportEntry]
244
245
class ExportEntry(lief.Object):
246
name: str
247
ordinal: int
248
address: int
249
is_extern: bool
250
forward_information: ForwardInformation
251
252
def resolve_ordinals(imp: Import, strict: bool = False, use_std: bool = False) -> Union[Import, lief_errors]:
253
"""Resolve import function names from ordinals."""
254
255
def get_imphash(binary: Binary, mode: IMPHASH_MODE = IMPHASH_MODE.DEFAULT) -> str:
256
"""Calculate import hash for malware analysis."""
257
```
258
259
Usage example:
260
```python
261
binary = PE.parse("C:\\Windows\\System32\\notepad.exe")
262
263
# Analyze imports
264
print("Import libraries:")
265
for import_lib in binary.imports:
266
print(f" {import_lib.name}")
267
for entry in import_lib.entries:
268
if entry.is_ordinal():
269
print(f" Ordinal #{entry.ordinal}")
270
else:
271
print(f" {entry.name} (hint: {entry.hint})")
272
273
# Analyze exports (for DLLs)
274
if binary.exports:
275
print(f"Export DLL name: {binary.exports.name}")
276
for entry in binary.exports.entries:
277
print(f" {entry.name} @ ordinal {entry.ordinal}")
278
279
# Calculate import hash
280
imphash = PE.get_imphash(binary)
281
print(f"Import hash: {imphash}")
282
283
# Resolve ordinals if needed
284
for import_lib in binary.imports:
285
resolved = PE.resolve_ordinals(import_lib)
286
if not isinstance(resolved, PE.lief_errors):
287
print(f"Resolved ordinals for {resolved.name}")
288
```
289
290
### Resource Management
291
292
Parse and manipulate PE resources including icons, version information, and custom data.
293
294
```python { .api }
295
class ResourceNode(lief.Object):
296
id: int
297
name: str
298
childs: Iterator[ResourceNode]
299
300
def has_name(self) -> bool
301
def has_id(self) -> bool
302
303
class ResourceData(ResourceNode):
304
content: memoryview
305
code_page: int
306
reserved: int
307
308
class ResourceStringFileInfo(lief.Object):
309
type: int
310
key: str
311
langcode_items: Iterator[LangCodeItem]
312
313
class ResourceVarFileInfo(lief.Object):
314
type: int
315
key: str
316
translations: List[int]
317
318
class ResourceVersion(lief.Object):
319
type: int
320
key: str
321
fixed_file_info: ResourceFixedFileInfo
322
string_file_info: ResourceStringFileInfo
323
var_file_info: ResourceVarFileInfo
324
325
class ResourceIcon(lief.Object):
326
id: int
327
lang: int
328
sublang: int
329
width: int
330
height: int
331
color_count: int
332
reserved: int
333
planes: int
334
bit_count: int
335
size: int
336
pixels: memoryview
337
```
338
339
Usage example:
340
```python
341
binary = PE.parse("C:\\Windows\\System32\\calc.exe")
342
343
if binary.resources:
344
# Walk resource tree
345
def walk_resources(node, level=0):
346
indent = " " * level
347
if node.has_name():
348
print(f"{indent}Name: {node.name}")
349
else:
350
print(f"{indent}ID: {node.id}")
351
352
for child in node.childs:
353
walk_resources(child, level + 1)
354
355
walk_resources(binary.resources)
356
357
# Find version information
358
for resource in binary.resources.childs:
359
if resource.id == 16: # RT_VERSION
360
version_data = ResourceVersion(resource.childs[0].childs[0])
361
print(f"File version: {version_data.key}")
362
```
363
364
### Code Signing
365
366
Analyze and verify Authenticode signatures with certificate chain validation.
367
368
```python { .api }
369
class Signature(lief.Object):
370
version: int
371
digest_algorithm: ALGORITHMS
372
content_info: ContentInfo
373
certificates: Iterator[x509]
374
signers: Iterator[SignerInfo]
375
376
def find_crt_subject(self, subject: str) -> Optional[x509]
377
def find_crt_issuer(self, issuer: str) -> Optional[x509]
378
def check(self, checks: VERIFICATION_CHECKS = VERIFICATION_CHECKS.DEFAULT) -> VERIFICATION_FLAGS
379
380
class ContentInfo(lief.Object):
381
content_type: str
382
digest: memoryview
383
384
class SignerInfo(lief.Object):
385
version: int
386
issuer: str
387
serial_number: memoryview
388
digest_algorithm: ALGORITHMS
389
signature_algorithm: ALGORITHMS
390
encrypted_digest: memoryview
391
392
enum VERIFICATION_FLAGS:
393
OK = 0
394
INVALID_SIGNATURE = 1
395
UNSUPPORTED_ALGORITHM = 2
396
INCONSISTENT_DIGEST_ALGORITHM = 4
397
CERT_NOT_FOUND = 8
398
CORRUPTED_CONTENT_INFO = 16
399
CORRUPTED_AUTH_DATA = 32
400
MISSING_PKCS9_MESSAGE_DIGEST = 64
401
BAD_DIGEST = 128
402
BAD_SIGNATURE = 256
403
NO_SIGNATURE = 512
404
CERT_EXPIRED = 1024
405
CERT_FUTURE = 2048
406
407
enum ALGORITHMS:
408
UNKNOWN = 0
409
SHA_1 = 1
410
SHA_256 = 2
411
SHA_384 = 3
412
SHA_512 = 4
413
MD5 = 5
414
```
415
416
Usage example:
417
```python
418
binary = PE.parse("C:\\Windows\\System32\\kernel32.dll")
419
420
# Check for signatures
421
if binary.has_signature():
422
for signature in binary.signatures:
423
print(f"Signature version: {signature.version}")
424
print(f"Digest algorithm: {signature.digest_algorithm}")
425
426
# Check certificate chain
427
for cert in signature.certificates:
428
print(f"Certificate subject: {cert.subject}")
429
print(f"Certificate issuer: {cert.issuer}")
430
431
# Verify signature
432
verification = signature.check()
433
if verification == PE.VERIFICATION_FLAGS.OK:
434
print("Signature verification: VALID")
435
else:
436
print(f"Signature verification: INVALID ({verification})")
437
```
438
439
## Types
440
441
```python { .api }
442
class Section(lief.Section):
443
characteristics: SECTION_CHARACTERISTICS
444
virtual_size: int
445
pointer_to_relocations: int
446
pointer_to_line_numbers: int
447
number_of_relocations: int
448
number_of_line_numbers: int
449
450
def has_characteristic(self, characteristic: SECTION_CHARACTERISTICS) -> bool
451
452
enum SECTION_CHARACTERISTICS:
453
IMAGE_SCN_TYPE_NO_PAD = 0x00000008
454
IMAGE_SCN_CNT_CODE = 0x00000020
455
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
456
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
457
IMAGE_SCN_LNK_OTHER = 0x00000100
458
IMAGE_SCN_LNK_INFO = 0x00000200
459
IMAGE_SCN_LNK_REMOVE = 0x00000800
460
IMAGE_SCN_LNK_COMDAT = 0x00001000
461
IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000
462
IMAGE_SCN_GPREL = 0x00008000
463
IMAGE_SCN_MEM_FARDATA = 0x00008000
464
IMAGE_SCN_MEM_PURGEABLE = 0x00020000
465
IMAGE_SCN_MEM_16BIT = 0x00020000
466
IMAGE_SCN_MEM_LOCKED = 0x00040000
467
IMAGE_SCN_MEM_PRELOAD = 0x00080000
468
IMAGE_SCN_ALIGN_1BYTES = 0x00100000
469
IMAGE_SCN_ALIGN_2BYTES = 0x00200000
470
IMAGE_SCN_ALIGN_4BYTES = 0x00300000
471
IMAGE_SCN_ALIGN_8BYTES = 0x00400000
472
IMAGE_SCN_ALIGN_16BYTES = 0x00500000
473
IMAGE_SCN_ALIGN_32BYTES = 0x00600000
474
IMAGE_SCN_ALIGN_64BYTES = 0x00700000
475
IMAGE_SCN_ALIGN_128BYTES = 0x00800000
476
IMAGE_SCN_ALIGN_256BYTES = 0x00900000
477
IMAGE_SCN_ALIGN_512BYTES = 0x00A00000
478
IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000
479
IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000
480
IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000
481
IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000
482
IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000
483
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000
484
IMAGE_SCN_MEM_NOT_CACHED = 0x04000000
485
IMAGE_SCN_MEM_NOT_PAGED = 0x08000000
486
IMAGE_SCN_MEM_SHARED = 0x10000000
487
IMAGE_SCN_MEM_EXECUTE = 0x20000000
488
IMAGE_SCN_MEM_READ = 0x40000000
489
IMAGE_SCN_MEM_WRITE = 0x80000000
490
491
class TLS(lief.Object):
492
callbacks: List[int]
493
addressof_index: int
494
addressof_callbacks: int
495
sizeof_zero_fill: int
496
characteristics: int
497
data_template: memoryview
498
section: Section
499
500
class LoadConfiguration(lief.Object):
501
version: WIN_VERSION
502
characteristics: int
503
timedatestamp: int
504
major_version: int
505
minor_version: int
506
global_flags_clear: int
507
global_flags_set: int
508
critical_section_default_timeout: int
509
decommit_free_block_threshold: int
510
decommit_total_free_threshold: int
511
lock_prefix_table: int
512
maximum_allocation_size: int
513
virtual_memory_threshold: int
514
process_affinity_mask: int
515
process_heap_flags: int
516
csd_version: int
517
dependent_load_flags: int
518
editlist: int
519
security_cookie: int
520
guard_cf_check_function_pointer: int
521
guard_cf_dispatch_function_pointer: int
522
guard_cf_function_table: int
523
guard_cf_function_count: int
524
guard_flags: int
525
526
class RichHeader(lief.Object):
527
key: int
528
entries: Iterator[RichEntry]
529
530
class RichEntry(lief.Object):
531
id: int
532
build_id: int
533
count: int
534
```