All Options¶
Each entry lists what the switch does, an example, the JSON key it adds, and the matching GUI view.
Point at a layer inside the file
Every switch also works on a payload inside the file: ppee-cli --analysis 'drop.exe#resource:RT_RCDATA/101'. See Analyse a layer inside a file.
| Switch | Short description |
|---|---|
--headers | DOS, NT, File and Optional header fields |
--dirs | The 16-entry data directory table |
--sections | Section headers |
--hashes | CRC32, MD5, SHA-1, SHA-256, SSDEEP, TLSH, ImpHash, Authentihash, entropy |
--similarity | Look the file up in, and add it to, the similarity DB |
--imports | Imported modules and functions |
--exports | Exported functions |
--basereloc | Base relocations |
--tls | TLS directory and callbacks |
--debug | Debug directory (CodeView/PDB, POGO, …) |
--bound-imports | Bound imports |
--delay-imports | Delay-load imports |
--resources | Resource tree (type/name/language) |
--exception | Exception directory (x64/ARM64 unwind info) |
--security | Authenticode certificate table |
--loadconfig | Load configuration, CFG, SafeSEH |
--net | .NET CLR header, metadata root, streams and VTableFixups |
--richheader | Rich header (toolchain records) |
--appmanifest | Embedded application manifest |
--analysis | Derived views for .NET, Go, Rust and NativeAOT builds, and the Code analysis of x86/x64 code |
--analysis-deep | --analysis plus the deep pass |
--strings | ASCII, Unicode, URL, registry and suspicious strings |
--disasm TARGET | Disassemble x86/x64 code at the entry point, a TLS callback, an export or an address (--count N) |
--xrefs TARGET | Where an import, address or string is used in the code (--max-sites N) |
--functions | Function starts found by the code scan |
--all | Everything above except --disasm, --xrefs and --functions |
--json | Emit JSON instead of text |
--timing | Per-stage timings on stderr |
--set NAME=VALUE | Patch a field (repeatable) |
--save | Write edits back |
-o PATH | Write edits to another file |
--no-similarity | Never touch the similarity DB |
--no-update-check | Skip the startup update check |
--scan-budget N | Code scan budget, in millions of instructions |
--no-code-scan | Skip the implicit code scan (--analysis, MCP string references) |
--mcp | Run as an MCP server |
--mcp-allow-write | Enable the MCP patch_pe tool |
-h, --help | Show usage |
--version | Print version |
Analyse a layer inside a file¶
Got a dropper with a payload in a resource or the overlay? Don't carve it out. Add # steps to the file name and every switch works on that layer, read into memory and never written to disk:
| Path | Layer |
|---|---|
drop.exe#overlay | The data after the last section |
drop.exe#resource:RT_RCDATA/101 | A resource (TYPE/NAME, optionally /LANGUAGE; RT_RCDATA, RCDATA and 10 all work) |
drop.exe#section:.rsrc | A section's raw data (#section:#3 by position) |
drop.exe#offset:0x5000+0x2000 | A byte range (#offset:0x5000 to the end) |
drop.exe#overlay#resource:CABINET/1 | Steps nest |
WannaCry's launcher.dll keeps its next stage in resource W/101, 4 bytes in. Hash it where it is:
PS C:\> ppee-cli.exe --hashes 'C:\MalwareSamples\9487edf9b75f4c15e3ba6ccbae23588ee3dc9c4983417f1b469278af17fc3847.exe#resource:W/101#offset:4'
C:\MalwareSamples\9487edf9b75f4c15e3ba6ccbae23588ee3dc9c4983417f1b469278af17fc3847.exe#resource:W/101#offset:4: 5242876 bytes, PE32
FileInfo:
CRC32: 94E15948
Entropy: 4.16148
MD5: 07B2930FB73F97171400953DDF6F28FB
SHA1: B79F48B5DC79606F3C3CF684EC5D2987406514A2
SHA256: 4F3B1943B2D1CAE320D92C3BEB0BBA2FBFEC8F9D14C95E3FFB11D2FAFA26F9AC
SSDEEP: 49152:QnnMSPbcKQej/1Iix+TSqTdX1HkQo6SAARdhnv:QnPouz1bxcSUDk36SAEdhv
TLSH: T12936339971BC91FCC205297484AB8E22A2B23C7925FE5E0F9F4089761D53F56FB90B43
ImpHash: 9ECEE117164E0B870A53DD187CDD7174
Authentihash: 0AA2F61297768D185E2B2C4984008E50D46E7F9BC60F05F226F3265A2C1E229A
Swap --hashes for --analysis, --imports, --disasm ep or anything else. Quote the path: # starts a comment in most shells. A wrong step says what is there:
failed to load '…/9487edf9….exe#resource:W/9': #resource:W/9: no such resource. Resources: W/101, RT_MANIFEST/2
A file whose real name contains # is still read as that file.
Section filters¶
Section filters combine freely. If none is given, all of them are on (the same as --all). Output always follows a fixed order, whatever order the switches were given in.
--headers¶
Includes every field of the DOS header, NT signature, File header and Optional header. The names printed here are the names --set accepts.
$ ppee-cli --headers aepic.dll
Headers:
DosHeader.e_magic = 5A4D
...
FileHeader.Machine = 8664
FileHeader.NumberOfSections = 0007
FileHeader.TimeDateStamp = F8929A64
...
OptionalHeader.AddressOfEntryPoint = 0001A190
OptionalHeader.ImageBase = 0000000180000000
OptionalHeader.Subsystem = 0002
OptionalHeader.DllCharacteristics = 4160
- JSON:
headers(an object of field name → hex string) - GUI: DOS Header, NT Header, File Header, Optional Header
- See also: Headers & Sections, hardening policy gate
--dirs¶
Includes the data directory table: the RVA and size of all 16 directories (Export, Import, Resource, Exception, Security, BaseReloc, Debug, Architecture, GlobalPtr, TLS, LoadConfig, BoundImport, IAT, DelayImport, COM descriptor, Reserved).
$ ppee-cli --dirs sample.exe
Data directories:
DataDirectory[0].VirtualAddress = 00000000
DataDirectory[0].Size = 00000000
DataDirectory[1].VirtualAddress = 00425638
DataDirectory[1].Size = 00000AB4
...
- JSON:
dataDirectories - GUI: Data Directories (n)
- See also: Headers & Sections
Note
For the Security directory (index 4), VirtualAddress is a file offset, not an RVA. That is how the PE format defines it.
--sections¶
Includes every section header: name, virtual address and size, raw pointer and size, relocation and line-number fields, and characteristics.
Example: a UPX-packed dropper, 77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe:
$ ppee-cli --sections 77549422….exe
Sections:
Section[0].Name = UPX0
Section[0].VirtualAddress = 00001000
Section[0].VirtualSize = 00008000
Section[0].PointerToRawData = 00000200
Section[0].SizeOfRawData = 00000000
Section[0].Characteristics = E0000080
Section[1].Name = UPX1
Section[1].VirtualAddress = 00009000
Section[1].VirtualSize = 00002000
Section[1].SizeOfRawData = 00001600
Section[1].Characteristics = E0000040
...
PS C:\> ppee-cli.exe --sections C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe
C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe: 7168 bytes, PE32
Sections:
Section[0].Name = UPX0
Section[0].VirtualAddress = 00001000
Section[0].VirtualSize = 00008000
Section[0].PointerToRawData = 00000200
Section[0].SizeOfRawData = 00000000
Section[0].PointerToRelocations = 00000000
Section[0].PointerToLinenumbers = 00000000
Section[0].NumberOfRelocations = 0000
Section[0].NumberOfLinenumbers = 0000
Section[0].Characteristics = E0000080
Section[1].Name = UPX1
Section[1].VirtualAddress = 00009000
Section[1].VirtualSize = 00002000
Section[1].PointerToRawData = 00000200
Section[1].SizeOfRawData = 00001600
Section[1].PointerToRelocations = 00000000
Section[1].PointerToLinenumbers = 00000000
Section[1].NumberOfRelocations = 0000
Section[1].NumberOfLinenumbers = 0000
Section[1].Characteristics = E0000040
Section[2].Name = .rsrc
Section[2].VirtualAddress = 0000B000
Section[2].VirtualSize = 00001000
Section[2].PointerToRawData = 00001800
Section[2].SizeOfRawData = 00000400
Section[2].PointerToRelocations = 00000000
Section[2].PointerToLinenumbers = 00000000
Section[2].NumberOfRelocations = 0000
Section[2].NumberOfLinenumbers = 0000
Section[2].Characteristics = C0000040
UPX0 takes 32 KB in memory but 0 bytes in the file, and both sections are E00000xx (read + write + execute): the unpacker decompresses UPX1 into the empty UPX0 at run time.
- JSON:
sections - GUI: Section Headers (n)
- See also: Section headers
--hashes¶
Computes whole-file CRC32, MD5, SHA-1, SHA-256, SSDEEP, TLSH, ImpHash, Authentihash and Shannon entropy. The passes run in parallel on multi-core machines.
$ ppee-cli --hashes 77549422….exe
FileInfo:
CRC32: CBBCCE59
Entropy: 6.92387
MD5: B578369C8E42C88CF5DBA6093E4D5601
SHA1: 0E067777F022FFACC522FED4734FB98E50221FD7
SHA256: 77549422A5306F905D68153B1F649745D330D45E564C927046132ECC1D20AE3E
SSDEEP: 192:zXzdrr1FG1WDCgmjPZKYjRnMoyCeFMUA:Lprr1gkDCgS9jlMWIMB
TLSH: T128E17E972E3A10EBD0DA7231528FC26631AFA0E1A7D50AC88A6CEF5F34665149975704
ImpHash: A3581BFE28E762682DBC13D06BF2FDA0
Authentihash: C2C14EAB7EEECC4C525BC839784729F57F7A4A7F109E2179EE3121FF9A4F2553
PS C:\> ppee-cli.exe --hashes C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe
C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe: 7168 bytes, PE32
FileInfo:
CRC32: CBBCCE59
Entropy: 6.92388
MD5: B578369C8E42C88CF5DBA6093E4D5601
SHA1: 0E067777F022FFACC522FED4734FB98E50221FD7
SHA256: 77549422A5306F905D68153B1F649745D330D45E564C927046132ECC1D20AE3E
SSDEEP: 192:zXzdrr1FG1WDCgmjPZKYjRnMoyCeFMUA:Lprr1gkDCgS9jlMWIMB
TLSH: T128E17E972E3A10EBD0DA7231528FC26631AFA0E1A7D50AC88A6CEF5F34665149975704
ImpHash: A3581BFE28E762682DBC13D06BF2FDA0
Authentihash: C2C14EAB7EEECC4C525BC839784729F57F7A4A7F109E2179EE3121FF9A4F2553
The SHA-256 is the sample's name on MalwareBazaar; search it, or the ImpHash and TLSH, there or on VirusTotal to find relatives.
- JSON:
fileInfo→crc32,entropy,md5,sha1,sha256,ssdeep,tlsh,impHash,authentihash - GUI: File Information
- MCP:
get_hashes - See also: Hashes & Entropy
--similarity¶
Hashes the file, compares it with every file previously recorded in the local similarity database, and then records it in the database. Implies the hash computation from --hashes.
$ ppee-cli --similarity explorer2.exe
Similarity DB: 2 record(s)
Match against 1 peer(s):
SHA256 identical - /samples/explorer.exe
- JSON:
similarity→available,dbRecordCount,matches[](peerPath,kind) - If the database can't be opened (for example on a read-only location), PPEE prints
warning: similarity database '…' could not be opened …on stderr, reportsavailable: false/Similarity DB: unavailable, and skips the lookup. - GUI: similarity toast and history window (Similarity Alerts)
- MCP:
check_similarity - See also: Similarity Engine,
--no-similarity
This switch writes to disk
--similarity (and therefore --all, and running with no filters) creates or updates ppee-cli.similarity.db next to the executable. Use --no-similarity on read-only media or when you don't want samples remembered.
--imports¶
Includes the import directory: every imported module with its OriginalFirstThunk, TimeDateStamp and FirstThunk, and every function imported by name (with hint) or by ordinal.
$ ppee-cli --imports 77549422….exe
Imports (7 module(s)):
KERNEL32.DLL (OFT=0 TimeDateStamp=0 FT=B14C) - 6 function(s)
LoadLibraryA (hint=0)
GetProcAddress (hint=0)
VirtualProtect (hint=0)
VirtualAlloc (hint=0)
VirtualFree (hint=0)
ExitProcess (hint=0)
advapi32.dll (OFT=0 TimeDateStamp=0 FT=B168) - 1 function(s)
RegCloseKey (hint=0)
...
PS C:\> ppee-cli.exe --imports C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe
C:\MalwareSamples\77549422a5306f905d68153b1f649745d330d45e564c927046132ecc1d20ae3e.exe: 7168 bytes, PE32
Imports (7 module(s)):
KERNEL32.DLL (OFT=0 TimeDateStamp=0 FT=B14C) - 6 function(s)
LoadLibraryA (hint=0)
GetProcAddress (hint=0)
VirtualProtect (hint=0)
VirtualAlloc (hint=0)
VirtualFree (hint=0)
ExitProcess (hint=0)
advapi32.dll (OFT=0 TimeDateStamp=0 FT=B168) - 1 function(s)
RegCloseKey (hint=0)
comctl32.dll (OFT=0 TimeDateStamp=0 FT=B170) - 1 function(s)
InitCommonControls (hint=0)
gdi32.dll (OFT=0 TimeDateStamp=0 FT=B178) - 1 function(s)
CreateFontIndirectA (hint=0)
shell32.dll (OFT=0 TimeDateStamp=0 FT=B180) - 1 function(s)
ShellExecuteA (hint=0)
shlwapi.dll (OFT=0 TimeDateStamp=0 FT=B188) - 1 function(s)
PathMatchSpecA (hint=0)
user32.dll (OFT=0 TimeDateStamp=0 FT=B190) - 1 function(s)
EndPaint (hint=0)
The classic packer import table: LoadLibraryA + GetProcAddress to rebuild the real imports, VirtualAlloc/VirtualProtect for the unpacked code, and one function from each other DLL, only so the loader maps it.
- JSON:
imports[]→name,originalFirstThunk,timeDateStamp,forwarderChain,firstThunk,functions[] - GUI: DIR_ENTRY_IMPORT (n), where selecting a module lists its functions, including demangled C++ names
- MCP:
list_imports - See also: Import directory, ImpHash
--exports¶
Includes the export directory: the DLL name, ordinal base, counts, and every exported function with its ordinal, name, RVA and forwarder.
$ ppee-cli --exports aepic.dll
Exports: AEPIC.dll (base=1, 12 function(s)):
#1 GetAppInventoryCore rva=29CB0
#2 UpdateSoftwareInventoryTC2 rva=4A3F0
#3 DllCanUnloadNow rva=41BE0
...
- JSON:
exports→present,name,base,numberOfFunctions,numberOfNames,functions[] - GUI: DIR_ENTRY_EXPORT (n)
- MCP:
list_exports - See also: Exports
--basereloc¶
Includes the base relocation blocks and the entries in each (type, offset, RVA, value and target).
$ ppee-cli --basereloc sample.exe
Base relocations: 56 block(s), 10938 entrie(s)
page=0036B000 size=996 entries=494
...
- JSON:
baseRelocations[]→pageRVA,sizeOfBlock,entries[] - GUI: DIR_ENTRY_BASERELOC, with a rebase preview
- See also: Relocations
--tls¶
Includes the TLS directory and its callback list. TLS callbacks run before the entry point, which malware uses for anti-debugging.
PS C:\> ppee-cli.exe --tls C:\MalwareSamples\ef431e36a8ac12051af588d800e1d8128d583a9d4c68187709263a13564081cd.dll
C:\MalwareSamples\ef431e36a8ac12051af588d800e1d8128d583a9d4c68187709263a13564081cd.dll: 3880960 bytes, PE32
TLS: index=6DAF6044 zeroFill=0 callbacks=2
callback VA=6D741870
callback VA=6D741830
ef431e36a8ac12051af588d800e1d8128d583a9d4c68187709263a13564081cd.dll. Two callbacks run before DllMain. Read them with --disasm tls:0: here they check the reason argument and set a flag, the MinGW runtime's own TLS code, not a trick. Only callbacks that don't look like that are worth a closer look.
- JSON:
tls→present,startAddressOfRawData,endAddressOfRawData,addressOfIndex,addressOfCallBacks,callbacks[] - GUI: DIR_ENTRY_TLS (n)
- See also: TLS
--debug¶
Includes the debug directory: CodeView (RSDS PDB path, GUID and age), POGO, FPO, VC feature and repro entries.
$ ppee-cli --debug STEALERDLL.dll
Debug directory: 4 entrie(s)
type=2 sizeOfData=71 pointerToRawData=119EDC [RSDS pdb=D:\Mktmp\StealerDLL\Release.x64\STEALERDLL.pdb age=212 guid=99F662A8-FCA0-49B6-B44E-FB7204BF0677]
type=12 sizeOfData=20 pointerToRawData=119F24
type=13 sizeOfData=852 pointerToRawData=119F38
type=14 sizeOfData=0 pointerToRawData=0
PS C:\> ppee-cli.exe --debug C:\MalwareSamples\STEALERDLL.dll
C:\MalwareSamples\STEALERDLL.dll: 1282048 bytes, PE32+
Debug directory: 4 entrie(s)
type=2 sizeOfData=71 pointerToRawData=119EDC [RSDS pdb=D:\Mktmp\StealerDLL\Release.x64\STEALERDLL.pdb age=212 guid=99F662A8-FCA0-49B6-B44E-FB7204BF0677]
type=12 sizeOfData=20 pointerToRawData=119F24
type=13 sizeOfData=852 pointerToRawData=119F38
type=14 sizeOfData=0 pointerToRawData=0
STEALERDLL.dll. The author left the project name and folder in the PDB path. age=212 says the project was rebuilt about 200 times: an actively developed tool. The GUID links this build to its PDB, and to other builds from the same one.
- JSON:
debug[]→type,timeDateStamp,sizeOfData,pointerToRawData,codeView{format,pdbPath,age,guid} - GUI: DIR_ENTRY_DEBUG (n)
- See also: Debug directory
--bound-imports¶
Includes bound imports: module timestamps and forwarder references that were pre-resolved at bind time.
$ ppee-cli --bound-imports legacy.dll
Bound imports (6 module(s)):
msvcrt.dll (TimeDateStamp=4A5BDFBE) - 1 forwarder(s)
-> NTDLL.DLL
- JSON:
boundImports[] - GUI: DIR_ENTRY_BOUND_IMPORT (n)
- MCP: part of
list_imports
--delay-imports¶
Includes delay-load imports, the modules that are loaded on first call rather than at process start.
$ ppee-cli --delay-imports sample.exe
Delay-load imports (60 module(s)):
SndVolSSO.DLL (attrs=1) - 4 function(s)
Ordinal #1
WINTRUST.dll (attrs=1) - 1 function(s)
WTGetSignatureInfo (hint=91)
- JSON:
delayImports[]→name,attributes,timeDateStamp,functions[] - GUI: DIR_ENTRY_DELAY_IMPORT (n)
- MCP: part of
list_imports
--resources¶
Includes the full resource tree at all three levels (type → name → language). For each leaf it gives the file offset, size, code page, entropy, MD5, the detected content type (PNG, ICO, XML, PE, ZIP, …) and a first-bytes preview.
$ ppee-cli --resources 3c6b036f….exe
Resources: 4 type(s), 9 name(s), 9 language variant(s):
#3 (RT_ICON) [...]
#10 (RT_RCDATA) [...]
#100 [...]
lang=#1033 offset=4C500 size=1515568 codePage=0 entropy=6.49614 md5=AC7A167EE7269BD790F220BB104CCA22 typeDetected=PE File
first bytes: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 | MZ.........ÿÿ..
#14 (RT_GROUP_ICON) [...]
#16 (RT_VERSION) [...]
PS C:\> ppee-cli.exe --resources C:\MalwareSamples\3c6b036f2eebc124c17db51960d9f6c9b39e236e9a33d5ac0c3a3a2cabe36833.exe
C:\MalwareSamples\3c6b036f2eebc124c17db51960d9f6c9b39e236e9a33d5ac0c3a3a2cabe36833.exe: 1826352 bytes, PE32+
Resources: 4 type(s), 9 name(s), 9 language variant(s):
[root] Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=4
#3 (RT_ICON) [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=6]
#1 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BE530 size=296 codePage=0 entropy=2.52572 md5=7D3C73068D397DDE148769EF8EB9B3FA typeDetected=Icon Image
first bytes: 28 00 00 00 10 00 00 00 20 00 00 00 01 00 04 00 | (....... .......
#2 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BE658 size=744 codePage=0 entropy=2.54823 md5=996902231372D924A013649C8240E990 typeDetected=Icon Image
first bytes: 28 00 00 00 20 00 00 00 40 00 00 00 01 00 04 00 | (... ...@.......
#3 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BE940 size=1640 codePage=0 entropy=2.32902 md5=DB628C61BB8A57188CC7751951E7DE41 typeDetected=Icon Image
first bytes: 28 00 00 00 30 00 00 00 60 00 00 00 01 00 04 00 | (...0...`.......
#4 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BEFA8 size=176 codePage=0 entropy=1.98919 md5=60D6E880DCE25CE3906D70E6D1BF4155 typeDetected=Icon Image
first bytes: 28 00 00 00 10 00 00 00 20 00 00 00 01 00 01 00 | (....... .......
#5 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BF058 size=304 codePage=0 entropy=3.13529 md5=5C23901F0E9D4D1783B6CB81F2360E50 typeDetected=Icon Image
first bytes: 28 00 00 00 20 00 00 00 40 00 00 00 01 00 01 00 | (... ...@.......
#6 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BF188 size=816 codePage=0 entropy=2.49222 md5=CB0C36F92C8BAE5BE460B34A8647F2C2 typeDetected=Icon Image
first bytes: 28 00 00 00 30 00 00 00 60 00 00 00 01 00 01 00 | (...0...`.......
#10 (RT_RCDATA) [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
#100 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=4C500 size=1515568 codePage=0 entropy=6.49614 md5=AC7A167EE7269BD790F220BB104CCA22 typeDetected=PE File
first bytes: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 | MZ�.........��..
#14 (RT_GROUP_ICON) [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
#101 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=1BF4B8 size=90 codePage=0 entropy=2.74417 md5=D148C75E59377AA79C180396F45F355C typeDetected=Icon
first bytes: 00 00 01 00 06 00 10 10 10 00 01 00 04 00 28 01 | ..............(.
#16 (RT_VERSION) [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
#1 [Characteristics=00000000 TimeDateStamp=00000000 MajorVersion=0 MinorVersion=0 NumberOfNamedEntries=0 NumberOfIdEntries=1]
lang=#1033 offset=4C220 size=736 codePage=0 entropy=3.36507 md5=656AB2DEAD54829FB5EBCD956A562C39 typeDetected=Version Resource
first bytes: E0 02 34 00 00 00 56 00 53 00 5F 00 56 00 45 00 | �.4...V.S._.V.E.
RemusStealer dropper, 3c6b036f2eebc124c17db51960d9f6c9b39e236e9a33d5ac0c3a3a2cabe36833.exe. A 1.5 MB executable (MZ, typeDetected=PE File) sits in RT_RCDATA #100, most of the file. offset is the resource's RVA, as the format stores it. Extract it with the GUI's Dump… or MCP extract_payload; see the resource page for the whole walkthrough.
- JSON:
resources→types[]→names[]→ languages - GUI: DIR_ENTRY_RESOURCE (n), with previews and Dump… to extract a resource
- See also: Resources
--exception¶
Includes the exception directory (.pdata): RUNTIME_FUNCTION entries and decoded unwind info for AMD64 and ARM64.
$ ppee-cli --exception sample.exe
Exception directory (AMD64): 12411 entrie(s)
begin=00001008 end=000012ED unwindInfo=0040914C [version=1 flags=3 sizeOfProlog=38 countOfCodes=9]
- JSON:
exception→present,machine,entries[]→beginAddress,endAddress,unwindInfoAddress,unwindInfo - GUI: DIR_ENTRY_EXCEPTION (AMD64 | ARM64, n)
- See also: Exception directory
--security¶
Includes the certificate table, with every chained entry (including nested signatures): program name, publisher link, digest algorithm, the embedded digest compared with the computed Authentihash, the signer and timestamp certificates (subject, issuer, serial number, validity period, key, EKU), and the timestamp kind.
$ ppee-cli --security 847d8f49….exe
Security (certificate table): 1 entrie(s)
offset=2DB000 length=2432 revision=0200 type=0002 sha256=417C5AC0038A8E7912703191B4F4B9F25D6FB2E6652E27045E944FF80351EB8E
Validity: Not available on this platform -- Signature validity is checked by the Windows version of ppee
Signature #1 (certificate[0])
Digest Algorithm: SHA1
Signature Algorithm: RSA
Embedded Digest (SHA1): 92522BB8270AC121C54FF11FCAD37AE131B3AF61
Authentihash (SHA1): 92522BB8270AC121C54FF11FCAD37AE131B3AF61
Signer Certificate:
Serial Number: 24 31 0E CA B7 5B FF EA
Issuer Name: jaweralima.com (C=US, ST=bId7Hmyw, L=IsolE, O=421ZtfNiHkua2p, CN=jaweralima.com)
Subject Name: jaweralima.com (C=US, ST=bId7Hmyw, L=IsolE, O=421ZtfNiHkua2p, CN=jaweralima.com)
Valid: 2026/08/05 07:25:56 - 2027/08/05 07:25:56 UTC
Signature Algorithm: SHA256 RSA
Public Key: RSA 4096-bit
Enhanced Key Usage: 1.3.6.1.5.5.7.3.1, 1.3.6.1.5.5.7.3.2
PS C:\> ppee-cli.exe --security C:\MalwareSamples\847d8f4998d22fde37eb76f99b6d91012c42965b741fe2cec453ca5876cdf147.exe
C:\MalwareSamples\847d8f4998d22fde37eb76f99b6d91012c42965b741fe2cec453ca5876cdf147.exe: 2996608 bytes, PE32+
Security (certificate table): 1 entrie(s)
offset=2DB000 length=2432 revision=0200 type=0002 sha256=417C5AC0038A8E7912703191B4F4B9F25D6FB2E6652E27045E944FF80351EB8E
Validity: Broken
Signature #1 (certificate[0])
Digest Algorithm: SHA1
Signature Algorithm: RSA
Embedded Digest (SHA1): 92522BB8270AC121C54FF11FCAD37AE131B3AF61
Authentihash (SHA1): 92522BB8270AC121C54FF11FCAD37AE131B3AF61
Signer Certificate:
Serial Number: 24 31 0E CA B7 5B FF EA
Issuer Name: jaweralima.com (C=US, ST=bId7Hmyw, L=IsolE, O=421ZtfNiHkua2p, CN=jaweralima.com)
Subject Name: jaweralima.com (C=US, ST=bId7Hmyw, L=IsolE, O=421ZtfNiHkua2p, CN=jaweralima.com)
Valid: 2026/08/05 07:25:56 - 2027/08/05 07:25:56 UTC
Signature Algorithm: SHA256 RSA
Public Key: RSA 4096-bit
Enhanced Key Usage: 1.3.6.1.5.5.7.3.1, 1.3.6.1.5.5.7.3.2
RemusStealer, 847d8f4998d22fde37eb76f99b6d91012c42965b741fe2cec453ca5876cdf147.exe. "Signed" does not mean trusted. The digests match, so the file is intact, but Issuer = Subject (self-signed), the state, city and organization are random strings, the EKUs are TLS server/client auth (no code signing, 1.3.6.1.5.5.7.3.3), and there is no timestamp. Windows will not trust it; it exists to make the file look signed.
- JSON:
security→present,certificates[],validity,signatures[] - GUI: DIR_ENTRY_SECURITY (n certificate(s))
- MCP:
check_signature - See also: Authenticode Signatures, signature policy gate
Parsing vs trust
PPEE parses signatures on every platform. Whether a signature is trusted (valid chain, not revoked) is checked with WinVerifyTrust, so only the Windows build reports it.
--loadconfig¶
Includes the load configuration directory: security cookie, SafeSEH handler table, Control Flow Guard (function table, address-taken IAT, long-jump targets, EH continuation targets), guard flags, CHPE and volatile metadata.
$ ppee-cli --loadconfig sample.exe
LoadConfig (PE32+):
Size=118 TimeDateStamp=0 Version=0.0
EditList=0 SecurityCookie=140431C68
GuardCFCheckFunctionPointer=1403A0280 GuardCFDispatchFunctionPointer=1403A0288
GuardCFFunctionTable=1403A097C GuardCFFunctionCount=F71 GuardFlags=417500
GuardCF function table (3953):
RVA=4F10
- JSON:
loadConfig→header,safeSeh,guardCFFunction,guardAddressTakenIat,guardLongJumpTarget,guardEHContinuation - GUI: DIR_ENTRY_LOAD_CONFIG, with Safe SEH, Guard … and Volatile Metadata children
- See also: Load Config & CFG
--net¶
Includes the .NET (CLR / COR20) header, the metadata root, the stream directory (#~, #Strings, #US, #GUID, #Blob) and the VTableFixups.
Metadata tables are shown in the GUI
The rows of the metadata tables (TypeDef, MethodDef, …) and the heap contents are browsed in the GUI. From the CLI you can patch both table cells and heap cells with --set.
$ ppee-cli --net 05570fc8….exe
.NET (COR20 header):
cb=48 RuntimeVersion=2.5 Flags=3 EntryPointToken=600000A
MetaData: RVA=5D64 Size=7B54
Resources: RVA=D8B8 Size=5A11F0
StrongNameSignature: RVA=0 Size=0
...
Metadata root: Signature=424A5342 Version=1.1 VersionString="v4.0.30319" Flags=0 Streams=5
#~ offset=6C size=2F48
#Strings offset=2FB4 size=2C2C
PS C:\> ppee-cli.exe --net C:\MalwareSamples\05570fc80953707bdb230ecca534a259977d8185071c64468c0ce0d810b7cbc5.exe
C:\MalwareSamples\05570fc80953707bdb230ecca534a259977d8185071c64468c0ce0d810b7cbc5.exe: 5972992 bytes, PE32
.NET (COR20 header):
cb=48 RuntimeVersion=2.5 Flags=3 EntryPointToken=600000A
MetaData: RVA=5D64 Size=7B54
Resources: RVA=D8B8 Size=5A11F0
StrongNameSignature: RVA=0 Size=0
CodeManagerTable: RVA=0 Size=0
VTableFixups: RVA=0 Size=0
ExportAddressTableJumps: RVA=0 Size=0
ManagedNativeHeader: RVA=0 Size=0
Metadata root: Signature=424A5342 Version=1.1 VersionString="v4.0.30319" Flags=0 Streams=5
#~ offset=6C size=2F48
#Strings offset=2FB4 size=2C2C
#US offset=5BE0 size=11F8
#GUID offset=6DD8 size=10
#Blob offset=6DE8 size=D6C
05570fc80953707bdb230ecca534a259977d8185071c64468c0ce0d810b7cbc5.exe. About 31 KB of metadata but 5.6 MB of managed resources (Resources Size=5A11F0): almost the whole file is embedded data. --analysis names them (update.g.resources 4.2 MB, update.Properties.Resources.resources 1.5 MB) with their entropy.
- JSON:
net→present,header,metadataRoot,vTableFixups - GUI: DIR_ENTRY_COM_DESCRIPTOR → MetaData → #~ / heaps
- See also: .NET Metadata
--richheader¶
Includes the decoded Rich header: the XOR key, a checksum check, and one record per toolchain component (product ID, build, count), with Visual Studio version names.
$ ppee-cli --richheader sample.exe
Rich Header:
CheckSum(XOR key) = D34DFA25
DanS sign = 536E6144 DanS
Product ID = 0104 C object, VS2015
Minor Compiler Version = 6B14 Build 27412
Count = 00000020
- JSON:
richHeader→present,rows[](member,value,comment) - GUI: Rich Header
- See also: Rich Header
--appmanifest¶
Includes the parsed application manifest (RT_MANIFEST): assembly identity, requested execution level (UAC), uiAccess, supported OS, DPI awareness and dependencies.
PS C:\> ppee-cli.exe --appmanifest C:\MalwareSamples\0617ade62f8b8df572e467459bd63869cb90ab95d98e4fa88d4003abf7bcf0b9.exe.sample
C:\MalwareSamples\0617ade62f8b8df572e467459bd63869cb90ab95d98e4fa88d4003abf7bcf0b9.exe.sample: 521216 bytes, PE32
AppManifest:
ManifestVersion = 1.0
=
AssemblyIdentity: =
Name = MyApplication.app
Version = 1.0.0.0
=
RequestedPrivileges: =
Level = requireAdministrator Full administrator permissions
uiAccess = false
=
0617ade62f8b8df572e467459bd63869cb90ab95d98e4fa88d4003abf7bcf0b9.exe.sample. The file asks for a UAC prompt at every start, and its identity is Visual Studio's template default (MyApplication.app), never edited.
- JSON:
appManifest→present,rows[] - GUI: Application Manifest
- See also: Manifest, UAC policy gate
--analysis¶
Includes derived analysis for every runtime PPEE detects in the file: .NET (summary, imports, native imports, exports, resources), Go (summary, packages and functions, modules, build settings), Rust (summary, crates, project files) and NativeAOT (summary, assemblies, methods). It reports what the runtime metadata says, not PE structures, so it is kept apart from every structure key.
For every x86/x64 file it also runs the Code analysis: entry-point anomalies (packer stubs), the imported APIs the code really calls, and code patterns, each with instruction evidence. This scans the code in-line, so it adds about a second per 5 million instructions.
$ ppee-cli --analysis merlin.dll
Analysis (derived views, not PE structures):
Go
Detected: Go build info at offset 0x5B0220; Go 1.20+ pclntab at offset 0x8C61E0
Go > Summary (built from the Go build info, build ID and pclntab, and the file layout)
- Not yet read: the entropy of appended data. Run the deep pass... [run with --analysis-deep]
Identity
Go version: go1.24.2 [offset 0x5B0220]
- JSON:
analysis→runtimes[]→views[](see JSON output) - GUI: the Analysis node (Tree & List Views)
- MCP:
analyze_pesectionanalysis - See also: Runtime Analysis · .NET · Go · Rust · NativeAOT · Code
Bracketed hints
Text output shows where each fact came from in brackets, for example [offset 0x5B0220] or [Analysis > Go > Build settings]. Anything the deep pass would add says [run with --analysis-deep].
--analysis-deep¶
--analysis plus the deep pass: for .NET, every method body is read to find the ones that don't decode as IL (encrypted or junk code) and the entropy of managed resources, appended data and the metadata's section is measured; for Go, Rust and NativeAOT it measures the entropy of appended data. It is off by default because it reads more of the file than --analysis does. In the GUI it also asks for confirmation first.
PS C:\> ppee-cli.exe --analysis-deep C:\MalwareSamples\crackme.exe
C:\MalwareSamples\crackme.exe: 66048 bytes, PE32
Analysis (derived views, not PE structures):
Code
Detected: x86 machine code
Code > Summary (built from entry point, TLS callbacks, all decoded code)
Entry point
Address: 0x401000 [code 0x401000: entry point] in .text
00401000 push 0x0
00401002 call 0x40134E
00401007 mov dword ptr [0x406206], eax
0040100C push esi
0040100D push 0xA
0040100F push 0x1F7
00401014 push dword ptr [0x406206]
0040101A call 0x401348
0040101F push eax
00401020 push eax
00401021 push dword ptr [0x406206]
00401027 call 0x40136C
What the code does
- Nothing notable in the decoded code.
Imports in use
Other processes: ResumeThread (2), SuspendThread (2)
Run-time linking: GetModuleHandleA (2)
Coverage
Decoded: 1905 instructions, 49 functions
- Found by following direct calls and jumps from the entry point, TLS callbacks, exports, .pdata, the CFG function table and relocated pointers; code reached only through computed jumps is not covered, so every count is a lower bound.
Code > API call sites (32) (built from decoded code, import table)
API Topic Call sites
kernel32.ResumeThread Other processes 2 [code 0x4013A6: kernel32.ResumeThread call]
Function Address Instruction
sub_401384+0x22 0x4013A6 call 0x4040DC [code 0x4013A6: 0x4013A6]
sub_4040DC 0x4040DC jmp dword ptr [kernel32.ResumeThread] [code 0x4040DC: 0x4040DC]
kernel32.GetModuleHandleA Run-time linking 2 [code 0x401002: kernel32.GetModuleHandleA call]
Function Address Instruction
EntryPoint+0x2 0x401002 call 0x40134E [code 0x401002: 0x401002]
sub_40134E 0x40134E jmp dword ptr [kernel32.GetModuleHandleA] [code 0x40134E: 0x40134E]
kernel32.SuspendThread Other processes 2 [code 0x4013AD: kernel32.SuspendThread call]
...
- MCP: section
analysis-deep - GUI: the Summary's Run the deep pass... link (details)
--strings¶
Scans the whole file for ASCII and UTF-16 (Unicode) strings and tags URLs, registry paths and suspicious keywords (from Suspicious.txt). Each hit comes with its file offset and the section it is in.
PS C:\> ppee-cli.exe --strings C:\MalwareSamples\86c6bd8098246eaf4527d9caa406221b3ff1ce551cf3b029cfc71d2e5e7a7963.exe
C:\MalwareSamples\86c6bd8098246eaf4527d9caa406221b3ff1ce551cf3b029cfc71d2e5e7a7963.exe: 1048576 bytes, PE32+
Strings in file:
ASCII (15208):
00000000 Inside header area MZ
0000004D Inside header area !This program cannot be run in DOS mode.
000000A7 Inside header area p?=
000000AF Inside header area p?=
000000B7 Inside header area p?=
000000CB Inside header area p$
000000CF Inside header area p*;
000000D7 Inside header area p*;op
000000DF Inside header area p*;
000000E7 Inside header area pRich
00000108 Inside header area PE
00000112 Inside header area dj
00000198 Inside header area D(
000001AC Inside header area X)
00000210 Inside header area .text
00000237 Inside header area `.rdata
0000025F Inside header area @.data
00000268 Inside header area @'
00000288 Inside header area .pdata
00000290 Inside header area X)
000002AF Inside header area @.fptable
000002D8 Inside header area .rsrc
000002FF Inside header area @.reloc
0000040B .text [RX] (First section) u3H
0000040F .text [RX] (First section) \$0H
0000041B .text [RX] (First section) |$ H
00000420 .text [RX] (First section) =;E
00000430 .text [RX] (First section) (H;
00000438 .text [RX] (First section) |$ H
0000043D .text [RX] (First section) \$0H
00000483 .text [RX] (First section) (H
00000487 .text [RX] (First section) EI
000004A3 .text [RX] (First section) qV
000004B0 .text [RX] (First section) @SH
000004B5 .text [RX] (First section) H
000004DF .text [RX] (First section) [
00000512 .text [RX] (First section) \$
00000515 .text [RX] (First section) WH
00000519 .text [RX] (First section) H
00000546 .text [RX] (First section) \$0H
0000054F .text [RX] (First section) _
...
RemusStealer loader, 86c6bd8098246eaf4527d9caa406221b3ff1ce551cf3b029cfc71d2e5e7a7963.exe. A list of popular sites (an "am I online / in a sandbox?" check) and one raw-IP URL fetching a .bin file: a second-stage download. ppee-cli --xrefs string:uos.bin shows the code that uses it (see Disassembly & Cross-references).
- JSON:
strings→ascii[],unicode[],url[],registry[],suspicious[](offset,sectionName,text, plustypefor tagged hits) - GUI: Strings
- MCP:
get_strings(with filters and limits) - See also: Strings
Large output
A typical DLL yields tens of thousands of strings. If the scan would need more memory than the machine has to spare, PPEE prints a warning on stderr and continues. Filter the output afterwards, for example with jq '.strings.url'.
--disasm, --xrefs, --functions¶
Code switches for x86/x64 files: disassemble at a target, list the uses of an API, address or string, and list function starts. They have their own page with worked malware examples: Disassembly & Cross-references.
PS C:\> ppee-cli.exe --xrefs CryptUnprotectData --max-sites 1 C:\MalwareSamples\STEALERDLL.dll
C:\MalwareSamples\STEALERDLL.dll: 1282048 bytes, PE32+
Cross-references to crypt32.CryptUnprotectData (import at 0x1800FE070): 3 site(s), first ones listed
sub_18008F140+0x143
000000018008F273 mov qword ptr [rsp+0x20], 0x0
000000018008F27C xor edx, edx
000000018008F27E mov dword ptr [rsp+0x40], r14d
> 000000018008F283 call qword ptr [crypt32.CryptUnprotectData]
- JSON:
disasm,xrefs,functions - GUI: the Code window
- MCP:
disassemble,get_xrefs,list_functions
--decode, --decode-text, --hash-range¶
Show the text in a range, decode a range without a script, and hash any range. The steps, the key search and the range forms are those of MCP decode_bytes and hash_range.
| Switch | Description |
|---|---|
--decode AT | The bytes at AT: off:X, rva:X, va:X, section:NAME, overlay, headers, file. Without --steps: their hex and their ASCII and UTF-16 (u) strings in file order |
--strings-offset N | Without --steps: start the strings list at the Nth string (paging) |
--decode-text TEXT | Decode TEXT (a base64 string, hex text) instead of the file's bytes; no file needed |
--steps "xor:5A, base64" | The steps: xor/add/sub:KEY, rol/ror:N, not, reverse, base64[:ALPHABET], hex, rc4:KEY, inflate, zlib, gzip, lznt1, skip/take:N |
--find-key TEXT | The XOR/ADD/ROL keys that make the bytes contain TEXT |
--length N | Bytes to read (default: the whole section or overlay; 4096 from an address) |
--hash-range [AT] | MD5, SHA-1, SHA-256, CRC32, entropy, ssdeep, TLSH of AT (with --length), or of the headers, every section, the overlay and the file |
$ ppee-cli --decode section:.rdata --find-key https:// 106710ac….exe.sample
Source: 0x2200, 3072 bytes, in .rdata
Result: 3072 bytes, entropy 4.270
Keys that reveal 'https://':
xor:B5 at 0x2270 https://kidsko.striawork/telepuzhop/files/telemePanasonicInd\Hel
$ ppee-cli --decode off:0x2270 --length 64 --steps xor:B5 106710ac….exe.sample
Source: 0x2270, 64 bytes, in .rdata
Steps: xor:B5
Result: 64 bytes, entropy 4.383
…
https://kidsko.striawork/telepuzhop/files/telemePanasonicInd\Hel
$ ppee-cli --hash-range section:.text [email protected]
.text offset=0x400 size=178688 entropy=6.586
md5 f10df8e94d500c375ae989cf5ed4b360
sha1 1459f1ebe7691a9060913f30a316c094280f02cc
sha256 eb41b7fea88ccad49e4214c487ea79bc89103fe4d100760cec3a5899b8ba72d4
…
With --json, the output is MCP's document.
--all¶
Turns on every section filter above, including --analysis (but not the slower --analysis-deep, nor the code switches --disasm, --xrefs and --functions). This is also the default when no filter is given.
ppee-cli --json --all sample.exe > sample.full.json
ppee-cli --json --all --no-similarity sample.exe # everything except the DB write
Pipelines: name the sections you need
--all and running with no filter now also run the analyzers and can be large (Go and Rust binaries produce thousands of table rows). Scripts and CI jobs should list only the sections they use, for example --json --hashes --imports --security.
Output options¶
--json¶
Emits one JSON document on stdout instead of the text report. The document always starts with path, size and is64Bit, followed by one key per selected section. Numbers taken from the file are hex strings ("8664"), and counts and indexes are JSON numbers. The output is streamed, so memory use stays flat even for very large files.
- See also: JSON Output reference, jq recipes
--timing¶
Prints a per-stage wall-clock breakdown to stderr when the run ends. Stdout is unchanged, so it is safe to use together with --json.
$ ppee-cli --timing --all --no-similarity aepic.dll > /dev/null
timing: Load 0.952 ms
timing: FieldTable 0.614 ms
timing: ParseImports 0.167 ms
...
timing: Strings 8.266 ms
timing: FileInfo 10.322 ms
timing: Analysis 154.316 ms
timing: Emit 27.701 ms
timing: total 184.832 ms
Analysis is mostly the code scan behind the Code analysis. With --no-code-scan it drops to about 3 ms here; on a large file the difference is seconds.
Stages can run concurrently, so total is elapsed time since startup, not the sum of the stages.
Editing options¶
--set NAME=VALUE¶
Patches one field in memory. You can repeat it; edits are applied in the order given, before any output is produced, so the report shows the edited values. NAME is one of:
- a header, directory or section field name as printed by
--headers,--dirsor--sections(OptionalHeader.DllCharacteristics,Section[2].Name) - a
Cell:address for any list-view cell (imports, resources, .NET tables, …) RawOffset:<hex>:<width>to write raw little-endian bytesRawBytes:<hex>,RawBytes:rva:<hex>orRawBytes:va:<hex>to write a byte string ("90 90 C3";??keeps a byte)OptionalHeader.CheckSum=autoto recompute the checksum after the other editsString:<hex>:ascii|unicode:<maxChars>to rewrite a string in place
Numeric values are hex, unless a Cell: address ends in :dec.
# Preview an edit without saving (the report shows the new value)
ppee-cli --headers --set FileHeader.TimeDateStamp=5F000000 sample.exe
If any edit fails, PPEE prints --set failed: unknown field or bad value '<NAME>', and the exit code is 1.
Full syntax and examples: Editing with --set.
--save¶
Writes the edited image back to disk. The write is all or nothing: if any --set failed, nothing is written and not saved: an --set edit failed, nothing written is printed.
$ ppee-cli --headers --set OptionalHeader.DllCharacteristics=8120 --save sample.exe > /dev/null
applied 1 field edit(s)
saved '/home/me/sample.exe'
Without -o, the input file is overwritten
Keep a backup or use -o.
-o PATH¶
Used with --save: writes to PATH instead of overwriting the input file.
Behavior options¶
--no-similarity¶
Turns the similarity engine off completely. It overrides --similarity and --all whatever the order, and guarantees that the DB is neither opened nor written. Use it on read-only file systems, in containers with --read-only, and whenever you don't want files remembered.
--no-update-check¶
Skips the startup check for a newer release. The check only runs on Windows builds and prints to stderr. Use this switch for offline and scripted runs. The Docker image always passes it.
--scan-budget N¶
The budget of the x86/x64 code scan, in millions of decoded instructions (default 5, 1–50). It applies to --analysis, --xrefs, --functions and, given with --mcp, to every MCP tool call. A file with more code is covered in part, and the counts say so. The GUI setting is Settings → Disassembly.
--no-code-scan¶
Don't scan the code where the scan is implicit: --analysis then checks only the entry point and TLS callbacks, and MCP's get_strings / get_iocs leave out codeRefs / referencedByCode. --xrefs and --functions still scan, since you asked for them. Use it for fast batch triage of large files.
ppee-cli --json --analysis --no-code-scan big.exe # entry-point checks only, milliseconds
ppee-cli --mcp --scan-budget 20 # MCP server with a bigger budget
--mcp¶
Runs ppee-cli as a Model Context Protocol server on stdin/stdout instead of analyzing a file. It speaks JSON-RPC 2.0, one message per line, and serves until stdin closes. No file argument is allowed.
- See also: MCP overview, client setup, tool reference
--mcp-allow-write¶
Used with --mcp: also exposes the patch_pe tool, so the AI client can write patched copies of files. It is off by default. Read the security model first.
-h, --help¶
Prints usage and exits with code 0.
--version¶
Prints ppee-cli <version> and exits with code 0.