120 lines
6.2 KiB
Markdown
120 lines
6.2 KiB
Markdown
# Headerless raw-binary analysis with Ghidra
|
|
|
|
REA admits a headerless executable when the caller supplies the CPU family and
|
|
the address where file offset 0 should be mapped. That interpretation is not
|
|
inferred from a `.bin` suffix or from unrecognized bytes.
|
|
|
|
## Open and inspect
|
|
|
|
```bash
|
|
rea inspect /absolute/path/to/ecu.bin --target-format raw-binary --architecture arm --entry-point 0x8000000 --provider ghidra --json
|
|
rea function /absolute/path/to/ecu.bin 0x8000000 --target-format raw-binary --architecture arm --entry-point 0x8000000 --provider ghidra --json
|
|
rea inspect-native-load-image /absolute/path/to/ecu.bin --target-format raw-binary --architecture arm --entry-point 0x8000000 --provider ghidra --json
|
|
```
|
|
|
|
```json
|
|
{
|
|
"name": "open_binary",
|
|
"arguments": {
|
|
"path": "/absolute/path/to/ecu.bin",
|
|
"format": "raw-binary",
|
|
"architecture": "arm",
|
|
"entry_point": "0x8000000",
|
|
"provider_id": "ghidra"
|
|
}
|
|
}
|
|
```
|
|
|
|
`architecture` is one of `x86`, `x86_64`, `arm`, `arm64`, or `6502`. `entry_point` is a
|
|
hexadecimal address of the form `0x…`. The complete file is mapped starting at
|
|
that address, and Ghidra seeds an `entry` function there before auto-analysis.
|
|
ARM and AArch64 entries must be 4-byte aligned; x86 and 6502 entries may be byte-aligned.
|
|
For 6502, the entry and complete mapped file must fit within `0x0000..0xffff`;
|
|
images that cross the 16-bit boundary are rejected before provider startup.
|
|
`open_binary` and an open `binary_session` return the canonical `entry_point`
|
|
for raw targets so callers can verify the selected mapping directly.
|
|
Omitted `format` keeps header-based detection; architecture and entry without
|
|
`format=raw-binary` are rejected.
|
|
|
|
Ghidra imports a private snapshot with `BinaryLoader` and these little-endian
|
|
generic languages and compiler specifications:
|
|
|
|
| architecture | language_id | compiler_spec_id |
|
|
| ------------ | -------------------- | ---------------- |
|
|
| x86 | `x86:LE:32:default` | `gcc` |
|
|
| x86_64 | `x86:LE:64:default` | `gcc` |
|
|
| arm | `ARM:LE:32:v7` | `default` |
|
|
| arm64 | `AARCH64:LE:64:v8A` | `default` |
|
|
| 6502 | `6502:LE:16:default` | `default` |
|
|
|
|
Compiler specifications select analysis conventions; they do not identify the
|
|
original compiler or ABI of a headerless target. Ghidra's x86 languages do not
|
|
provide a compiler specification named `default`.
|
|
|
|
Those settings, the caller-supplied entry, and `language_selection:
|
|
caller-supplied-v1` are committed in the analysis profile. A different entry
|
|
or architecture is a different profile; snapshots from header-detected targets
|
|
do not replay.
|
|
|
|
The mapped start is independent of Ghidra's program image base, which remains
|
|
`0x0` for BinaryLoader. Ghidra may report additional language-defined entry
|
|
points, including unmapped ARM vectors. Load-image verification requires the
|
|
caller-supplied entry and preserves those other entries as observations.
|
|
For 6502, BinaryLoader maps the file before adding its language-defined zero-page
|
|
and stack blocks. Conflicting default blocks are skipped; low-address files stay
|
|
in the default address space rather than an overlay. Non-conflicting uninitialized
|
|
blocks remain observations, not file-backed bytes.
|
|
Independent raw verification streams the complete private snapshot digest and
|
|
extent with bounded memory and supports cancellation during the read.
|
|
It also requires the source-backed block to be initialized, loaded, and
|
|
non-overlay in the bound language's default address space. Contradictory mapping
|
|
observations are retained with `mismatch`, even when the source hashes agree.
|
|
|
|
Hopper and IDA refuse raw-binary targets. Windows Ghidra P0 admits native PE
|
|
applications/DLLs and explicitly selected raw 6502 images. Other raw CPU families
|
|
remain outside the Windows boundary. Native path admission, private DACLs, Job
|
|
Object ownership, immutable snapshots, and the no-mutation policy still apply.
|
|
|
|
## NMOS 6502
|
|
|
|
```bash
|
|
rea function /absolute/path/to/image.bin 0x8001 --target-format raw-binary --architecture 6502 --entry-point 0x8001 --provider ghidra --json
|
|
rea inspect-native-load-image /absolute/path/to/image.bin --target-format raw-binary --architecture 6502 --entry-point 0x8001 --provider ghidra --json
|
|
```
|
|
|
|
Select only headerless NMOS 6502 code with a known entry at file offset 0.
|
|
The built-in Ghidra processor supplies static instructions, functions,
|
|
pseudocode, and references. Evidence preserves `architecture: "6502"`, the
|
|
selected language, entry, file digest, and verified source mapping. Register and
|
|
calling conventions are analysis conventions, not a recovered source ABI.
|
|
|
|
This lane does not interpret iNES headers, cartridge mappers, bank switching,
|
|
or other console-specific memory layouts. 65C02 and 65816 programs need different
|
|
processor semantics and are not admitted as those variants. REA does not infer
|
|
the CPU from the file suffix, guess the reset vector, or emulate the target.
|
|
|
|
`npm run verify:ghidra:6502` assembles and links the source-owned fixture with
|
|
`ca65` and `ld65` (tested from cc65 tag `V2.19`, whose tools report `V2.18`).
|
|
Set `REA_CA65` and `REA_LD65` to explicit executable paths if needed. The lane
|
|
checks real CLI/MCP load-image parity, mapped bytes, decoded calls, decompilation,
|
|
invalid mappings, unchanged source bytes and runtime cleanup.
|
|
Low-memory checks include a file spanning the zero-page/stack boundary at `0xff`
|
|
and a complete 64-KiB image at `0x0`, with verified default-space mappings through
|
|
both CLI and MCP. On Windows, the lane also checks that a caller-selected
|
|
junction path is rejected at snapshot admission through CLI and MCP, with
|
|
unchanged source bytes and complete runtime cleanup. Windows requires the
|
|
matching native addon; the POSIX provider path has not been exercised by the
|
|
Windows run.
|
|
|
|
## Limitations
|
|
|
|
- Headers are not discovered from file bytes. This increment does not guess
|
|
load addresses, vector tables, or memory maps.
|
|
- Big-endian, Thumb-only, Cortex-M, and other Ghidra processor variants are
|
|
unsupported.
|
|
- Reset vectors, memory-mapped I/O, and firmware boot sequences are not
|
|
emulated.
|
|
- Independent load-image verification covers source identity, mapped file
|
|
bytes, the bound language, and the caller-supplied entry. Original bytes
|
|
stay unchanged.
|