PE


Introduction

import lief

# Using filepath
pe: lief.PE.Binary = lief.PE.parse(r"C:\Users\test.exe")

# Using a Path from pathlib
pe: lief.PE.Binary = lief.PE.parse(pathlib.Path(r"C:\Users\test.exe"))

# Using an io object
with open(r"C:\Users\test.exe", 'rb') as f:
  pe: lief.PE.Binary = lief.PE.parse(f)

Note

In Python, you can also use lief.parse() which returns a lief.PE.Binary object.

From this parsed PE binary you can use all the API exposed by the object to inspect or modify the binary itself.
pe: lief.PE.Binary = ...

print(pe.rich_header)
print(pe.authentihash_md5.hex(':'))

for section in pe.sections:
    print(section.name, len(section.content))
pe: lief.PE.Binary = ...

section = lief.PE.Section(".hello")
section.content = [0xCC] * 0x100
pe.add_section(section)

pe.write("new.exe")

Advance Parsing/Writing

Warning

Generally speaking, requires a complete initial parsing of the PE file.
Similarly, can be configured to avoid reconstructing some parts of the PE binary
parser_config = lief.PE.ParserConfig()
parser_config.parse_signature = False

pe: lief.PE.Binary = lief.PE.parse("some.exe", parser_config)

builder = lief.PE.Builder(pe)
builder.build_imports(False)
builder.patch_imports(False)

builder.build()
builder.write("new.exe")

Accessing PDB

For more the details about the PDB support, please check the PDB section.

Authenticode

LIEF supports PE authenticode by providing API to inspect and verify the signature of PE executables.

Note

Usually, a signed PE executable embeds only one signature but the format does not limit the number of signature. Thus, returns an iterator and not only one signature object.
import

pe = lief.PE.parse("signed.exe")
for signature in pe.signatures:
    for crt in signature.certificates:
      print(crt)

assert pe.verify_signature() == lief.PE.Signature.VERIFICATION_FLAGS.OK

You can find additional details about the authenticode support in this tutorial: PE Authenticode