| name | analyzing-blackbox-elf-object |
| description | Reconstruct the logic of Linux/Unix ELF executables, shared objects, and relocatable object files (.o), plus Mach-O. Covers entrypoint discovery, import/syscall mapping, function decompilation, and solving input-gated branches. Use for ELF/.o/.so/Mach-O targets. |
| license | Apache-2.0 |
| metadata | {"domain":"reverse-engineering","formats":"elf, object, so, macho"} |
Analyzing Black-Box ELF / Object Files
Scope
ELF executables and PIE, shared objects (.so), relocatable objects (.o), and
Mach-O. .o/relocatable files have no entrypoint — analyze per-function.
Workflow
-
Confirm shape with triage: arch, bits, endianness, elf_type
(executable / shared-object/PIE / relocatable). Note PIE → addresses are
offsets from a base.
-
Surface map:
symbols what=imports — what the program calls. Libc/syscall imports reveal
capability (network: socket/connect, files: open/read, exec: execve/system,
crypto: EVP_*, AES_*).
symbols what=exports / what=symbols — named functions to target.
strings_scan — endpoints, paths, format strings, crypto constants.
-
Find the logic core:
- Executables: start at
main (or entry0/_start → locate main via the
__libc_start_main argument). decompile mode=func name=main.
.so: inspect exported functions and JNI_OnLoad/constructors.
.o: symbols what=symbols, then disasm symbol=<fn> for each defined
function; relocations (symbols what=relocs) show external references.
-
Decompile selectively. decompile mode=list to enumerate, then
decompile mode=func name=<fn|0xADDR> on the handful that matter (large funcs,
ones referencing interesting strings/imports). Use disasm when you need exact
instructions or decompilation is unavailable.
-
Cross-reference data. Map interesting strings/constants back to the
functions that use them (rizin: axt @ str.<name>), to find where decisions are
made.
-
Solve input-gated logic. For password/license/serial checks or opaque
predicates: identify the "success" and "fail" addresses from the decompilation,
then symexec find=<success> avoid=<fail> input=stdin|arg length=<n>. The
returned input_ascii/input_hex is a concrete satisfying input.
Arch notes
- Statically-linked / stripped binaries: lean on
strings_scan + import-free
syscall patterns; rizin's aa/aaa analysis still recovers many functions.
- Rust/Go binaries are large and boilerplate-heavy — focus on functions touching
your strings of interest; complementary skills:
reverse-engineering-rust-malware.
Report
Identity & arch · entrypoint chain · key functions (with reconstructed logic) ·
syscalls/imports → capabilities · strings/constants/crypto · solved inputs · findings.