Binary hardening
Use inspect_binary_hardening to read compile-time and link-time hardening from an explicit local ELF, PE, or Mach-O file. No disassembler, pwntools install, or target execution is required. Universal Mach-O files return one image per slice.
rea inspect-binary-hardening /absolute/path/to/program --json
rea inspect-binary-hardening /absolute/path/to/program --max-file-bytes 1048576 --jsonMCP accepts { "path": "/absolute/path/to/program" }. CLI paths may be relative to the current directory; MCP paths must be absolute.
Each image has one row per property: property, state, confidence, basis, location, note, and next_probe. States are enabled, disabled, partial, unknown, and not_applicable. confidence is observed for a single header or import, and derived when the state combines several fields, such as ELF PIE or full RELRO. An image's architecture is its CPU family, or null when REA has no family for it. machine and slice.architecture keep the exact identity, such as arm64e.
ELF rows cover PIE (ET_DYN with PT_INTERP or DF_1_PIE), NX (PT_GNU_STACK; a missing header is unknown and the architecture default is only noted), RELRO (PT_GNU_RELRO plus BIND_NOW), stack protector and FORTIFY undefined dynamic imports, CET and AArch64 BTI/PAC GNU property notes, DT_RPATH, DT_RUNPATH, and whether a SHT_SYMTAB section is present. Only an undefined dynamic import counts. Imports come from the table DT_SYMTAB declares. A SHT_DYNSYM section only supplies the symbol count when DT_HASH and DT_GNU_HASH leave it open, and only if it names the same symbol and string tables. Without that count the import rows are unknown and give the reason. A missing __stack_chk_fail or fortify import is unknown. That absence does not establish that the protection was left out of a static or stripped build. A present import is a sign that some code uses the protection, not proof that all code does. NX, RELRO, DT_RPATH, and DT_RUNPATH are not_applicable when e_type is neither ET_EXEC nor ET_DYN, and unknown for a linked image with no readable program headers.
PE rows read DllCharacteristics for dynamic base, high-entropy VA, NX compatibility, force integrity, no SEH, and guard CF. cfg_instrumented is the load-config GuardFlags linker claim when Size covers that field. An unreadable load configuration, including a TLS failure in that parser, leaves only cfg_instrumented unknown. Authenticode and debug rows report certificate and debug directory presence, not signature validity or debug content. A directory whose address and size disagree is unknown.
Mach-O rows read MH_PIE, MH_ALLOW_STACK_EXECUTION, MH_NO_HEAP_EXECUTION, an __RESTRICT segment, LC_CODE_SIGNATURE presence, encryption from the existing encryption reader, the arm64e subtype, and a stack-protector import. hardened_runtime is unknown with next_probe inspect_signature. CodeDirectory flags stay with that tool.
The report states presence of build-time features. It does not state exploitability. inspect_binary_layout is unchanged.
The default read budget is 64 MiB (max_file_bytes, ceiling 512 MiB). A changed file is refused. A malformed header, a Mach-O segment or encryption command that fails admission, or a program, section, or segment payload declared outside the file returns no partial report, except that one bad slice in a universal Mach-O leaves the other slices. A symbol table or symbol name over its budget leaves the import rows unknown and keeps the header rows. A GNU property note over its budget, or a compressed note section that may hold one, leaves the CET and BTI/PAC rows unknown and keeps the header rows. A dynamic-table budget still fails the ELF report. The image is never executed.