[PR #3129] feat(ghidra): admit ELF and thin Mach-O targets on Windows #5634

Open
opened 2026-10-31 01:08:08 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3129
Author: @dkemper-maker
Created: 10/14/2026
Status: 🔄 Open

Base: main ← Head: feat/windows-ghidra-elf-targets


📝 Commits (1)

  • cac5bd4 feat(ghidra): admit ELF and thin Mach-O targets on Windows

📊 Changes

4 files changed (+64 additions, -20 deletions)

View changed files

📝 docs/windows-ghidra-p0.md (+15 -5)
📝 src/ghidra/GhidraProvider.behavior.test.ts (+35 -10)
📝 src/ghidra/GhidraProvider.ts (+13 -4)
📝 src/ghidra/GhidraProviderCapabilities.ts (+1 -1)

📄 Description

Draft. This widens the Windows Ghidra P0 admission boundary and follows the shape of #2186 / #2631, which set the verification gate for that kind of change (source-built fixtures with decompiler readback plus the real-provider verifier lane). This PR currently has the admission change, tests, docs, and one real-target verification on a proprietary binary. It does not yet have a source-owned ELF fixture or verify:ghidra coverage. Maintainer scope guidance is requested before that work is done; see "Contribution scope fit" below.

Summary

On Windows, the Ghidra provider refused every non-PE executable with target_format_unsupported, so an analyst on a Windows host could not open an Android, Linux, or macOS binary even with a working Ghidra installation. This PR admits ELF and thin Mach-O images on Windows through the same shared processor checks the POSIX hosts use, and verifies the path on a real Windows host with a 44 MB AArch64 Android shared library.

Related: #2186 and #2631 (bounded ARM/ARM64 PE admission on Windows P0; adjacent lane in the same gate, kept compatible here: PE AArch64 remains rejected by this PR and is left to #2631). #3111 (Windows host blocked on Android analysis; different cause, same user need). #1048 / #2150 / #2358 (re-import cost per CLI call, which the real-target verification below hit in practice).

Problem and expected behavior

Trigger: rea analyze libpdandroid.so --provider ghidra on Windows 11 x64 with Ghidra 12.1.4 and JDK 21 configured. Observed: rejection in about two seconds with target_format_unsupported, while rea doctor reports the provider available. Expected: the same import, overview, and decompile workflow the provider offers for that target on Linux and macOS.

The PE-only rule recorded the scope that had been verified when Windows P0 shipped, not a technical constraint. The native Windows addon under native/windows performs path admission, private runtime creation, snapshotting, and Job Object ownership; it does no executable-format classification. The launcher and snapshot paths are format-agnostic, and Ghidra's own importer selects the loader from the header.

Change and scope

  • inspectWindowsP0TargetSupport now returns null for elf and mach-o targets so the shared MIPS/PSP, universal-slice, and supported-architecture checks decide, exactly as on other hosts. The raw NMOS 6502 lane added on main is kept. PE keeps its architecture, role, and managed checks unchanged. DOS, other raw-binary, and universal Mach-O images stay rejected on Windows, with a reason that names them.
  • windowsP0Limitations and docs/windows-ghidra-p0.md state the new boundary and the exact verification performed.
  • Not included: DOS and non-6502 raw-binary admission on Windows, PE ARM/ARM64 admission (#2631), and any change to the native addon.

Follows the contribution scope: static import and read-only analysis of a caller-selected file through an existing provider boundary. No execution, injection, mutation, or protection recovery.

Contract and boundary impact

  • Semantic owner and earliest changed stage: GhidraProvider.inspectTargetSupport (provider adapter admission); no domain or application change.
  • Contribution scope fit and linked maintainer decision: existing read-only Ghidra boundary extended to additional input formats on one host. No maintainer decision linked yet; #2186 is the closest precedent and its gate (fixtures + verifier) is not yet met here. Requesting guidance on whether a separate proposal issue is wanted, and whether a source-built ELF AArch64 fixture (same shape as the x86 PE DLL fixtures: no imports, two exported functions) plus a verify:ghidra Windows lane is the required bar.
  • CLI and MCP/tool-catalog contract: none. Operation names, schemas, and error codes are unchanged; only the reason text of one target_format_unsupported rejection and one limitation string in the Ghidra capability inventory changed.
  • Provider, bridge, target-format, or platform compatibility: Windows Ghidra P0 now admits ELF and thin Mach-O targets on x86, x86-64, ARM, and AArch64. The MIPS PSP profile remains Linux x64 only through the existing check.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Target selection, authority, upstream behavior, and cleanup details: unchanged. ELF and Mach-O targets pass through the same native path admission, immutable private snapshot, digest match, Job Object ownership, and ephemeral-project cleanup as PE targets.
  • Generated metadata, package, or installation impact: the limitation string flows into generated catalogs; npm run docs:check passes. No package or installation change.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process. (Ghidra headless, as for every existing Ghidra-backed operation; no new launch path.)
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed. (On the verification bar only, not on effects.)

Evidence and regression coverage

  • Tests added or updated: GhidraProvider.behavior.test.ts asserts that a win32 host admits ELF x86-64, ELF AArch64, and thin Mach-O AArch64, keeps universal Mach-O rejected with target_format_unsupported, and keeps PE AArch64 rejected with architecture_unsupported. Existing PE role and managed assertions, the raw 6502 lane assertions, and the native-failure diagnostics assertions are unchanged apart from the two ELF expectations that flip to supported.
  • Base reproduction: on the pre-rebase base (83a4445) the same rea analyze call on the Android library failed in about two seconds with target_format_unsupported while rea doctor reported Ghidra available. Executed on this host.
  • User-visible CLI output: after the change, rea analyze <lib> --provider ghidra returned segment_count: 29, procedure_count: 63343, string_count: 134169, and rea decompile <lib> --procedure _Z23Script_1051_GetVelocityfffiff --provider ghidra returned 3,737 characters of Ghidra pseudocode with the Windows P0 limitations attached.
  • Remaining proof gaps: no source-owned ELF fixture and no verify:ghidra lane coverage, which is the gate #2186 established for Windows admission changes. ELF x86-64, ARM32, and thin Mach-O targets share the code path but were not run on a Windows host. The verified binary is proprietary and cannot be committed.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:local -- src/ghidra/GhidraProvider.behavior.test.ts — 67 passed (after rebasing onto main at 767fe0f, which mocks the native loader in the Windows diagnostics tests).
  • npm run check:fast — passed.
  • npm run docs:check — passed.
  • Real Windows 11 x64 host, Ghidra 12.1.4, JDK 21.0.12.1, released 6.4.0 native addon, REA_GHIDRA_STARTUP_TIMEOUT_MS=7200000: rea analyze on a 44 MB AArch64 ELF (sha256 94143e1c…682d52c4) completed in 8 min 47 s with the overview above; rea decompile of a named procedure completed in 8 min 40 s with pseudocode. Not run: npm run verify:ghidra.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Previously rejected targets are now admitted; previously admitted targets behave identically.
  • Real Hopper/Ghidra, browser, or OS coverage: real Ghidra 12.1.4 on Windows 11 x64 for one ELF AArch64 target, as listed above. No fixture-based coverage yet. No Hopper or IDA coverage.
  • Package or release metadata impact: none beyond the limitation string.
  • Security, privacy, process, or containment review: no change to native admission, snapshot, DACL, or Job Object handling. ELF and Mach-O targets are imported as immutable private snapshots exactly like PE targets; the read-only P0 boundary and the mutation refusal are unchanged.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. (Pending: verification bar, see above.)
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above. (No issue requests ELF on Windows specifically; #2186, #2631, and #3111 are the adjacent ones. An earlier revision of this description wrongly stated that no related issue existed; that was written without searching and is corrected here.)
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/3129 **Author:** [@dkemper-maker](https://github.com/dkemper-maker) **Created:** 10/14/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/windows-ghidra-elf-targets` --- ### 📝 Commits (1) - [`cac5bd4`](https://github.com/morluto/rea/commit/cac5bd4ead918680e50a6c828c8430cc08e683fc) feat(ghidra): admit ELF and thin Mach-O targets on Windows ### 📊 Changes **4 files changed** (+64 additions, -20 deletions) <details> <summary>View changed files</summary> 📝 `docs/windows-ghidra-p0.md` (+15 -5) 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+35 -10) 📝 `src/ghidra/GhidraProvider.ts` (+13 -4) 📝 `src/ghidra/GhidraProviderCapabilities.ts` (+1 -1) </details> ### 📄 Description > **Draft.** This widens the Windows Ghidra P0 admission boundary and follows the shape of #2186 / #2631, which set the verification gate for that kind of change (source-built fixtures with decompiler readback plus the real-provider verifier lane). This PR currently has the admission change, tests, docs, and one real-target verification on a proprietary binary. It does not yet have a source-owned ELF fixture or `verify:ghidra` coverage. Maintainer scope guidance is requested before that work is done; see "Contribution scope fit" below. ## Summary On Windows, the Ghidra provider refused every non-PE executable with `target_format_unsupported`, so an analyst on a Windows host could not open an Android, Linux, or macOS binary even with a working Ghidra installation. This PR admits ELF and thin Mach-O images on Windows through the same shared processor checks the POSIX hosts use, and verifies the path on a real Windows host with a 44 MB AArch64 Android shared library. Related: #2186 and #2631 (bounded ARM/ARM64 **PE** admission on Windows P0; adjacent lane in the same gate, kept compatible here: PE AArch64 remains rejected by this PR and is left to #2631). #3111 (Windows host blocked on Android analysis; different cause, same user need). #1048 / #2150 / #2358 (re-import cost per CLI call, which the real-target verification below hit in practice). ## Problem and expected behavior Trigger: `rea analyze libpdandroid.so --provider ghidra` on Windows 11 x64 with Ghidra 12.1.4 and JDK 21 configured. Observed: rejection in about two seconds with `target_format_unsupported`, while `rea doctor` reports the provider available. Expected: the same import, overview, and decompile workflow the provider offers for that target on Linux and macOS. The PE-only rule recorded the scope that had been verified when Windows P0 shipped, not a technical constraint. The native Windows addon under `native/windows` performs path admission, private runtime creation, snapshotting, and Job Object ownership; it does no executable-format classification. The launcher and snapshot paths are format-agnostic, and Ghidra's own importer selects the loader from the header. ## Change and scope - `inspectWindowsP0TargetSupport` now returns `null` for `elf` and `mach-o` targets so the shared MIPS/PSP, universal-slice, and supported-architecture checks decide, exactly as on other hosts. The raw NMOS 6502 lane added on main is kept. PE keeps its architecture, role, and managed checks unchanged. DOS, other raw-binary, and universal Mach-O images stay rejected on Windows, with a reason that names them. - `windowsP0Limitations` and `docs/windows-ghidra-p0.md` state the new boundary and the exact verification performed. - Not included: DOS and non-6502 raw-binary admission on Windows, PE ARM/ARM64 admission (#2631), and any change to the native addon. Follows the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope): static import and read-only analysis of a caller-selected file through an existing provider boundary. No execution, injection, mutation, or protection recovery. ## Contract and boundary impact - Semantic owner and earliest changed stage: `GhidraProvider.inspectTargetSupport` (provider adapter admission); no domain or application change. - Contribution scope fit and linked maintainer decision: existing read-only Ghidra boundary extended to additional input formats on one host. No maintainer decision linked yet; #2186 is the closest precedent and its gate (fixtures + verifier) is not yet met here. Requesting guidance on whether a separate proposal issue is wanted, and whether a source-built ELF AArch64 fixture (same shape as the x86 PE DLL fixtures: no imports, two exported functions) plus a `verify:ghidra` Windows lane is the required bar. - CLI and MCP/tool-catalog contract: none. Operation names, schemas, and error codes are unchanged; only the `reason` text of one `target_format_unsupported` rejection and one limitation string in the Ghidra capability inventory changed. - Provider, bridge, target-format, or platform compatibility: Windows Ghidra P0 now admits ELF and thin Mach-O targets on x86, x86-64, ARM, and AArch64. The MIPS PSP profile remains Linux x64 only through the existing check. - Evidence, artifact, provenance, or reconstruction contract: none. - Target selection, authority, upstream behavior, and cleanup details: unchanged. ELF and Mach-O targets pass through the same native path admission, immutable private snapshot, digest match, Job Object ownership, and ephemeral-project cleanup as PE targets. - Generated metadata, package, or installation impact: the limitation string flows into generated catalogs; `npm run docs:check` passes. No package or installation change. Expected effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. (Ghidra headless, as for every existing Ghidra-backed operation; no new launch path.) - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [x] Not sure yet; investigation or maintainer guidance needed. (On the verification bar only, not on effects.) ## Evidence and regression coverage - Tests added or updated: `GhidraProvider.behavior.test.ts` asserts that a `win32` host admits ELF x86-64, ELF AArch64, and thin Mach-O AArch64, keeps universal Mach-O rejected with `target_format_unsupported`, and keeps PE AArch64 rejected with `architecture_unsupported`. Existing PE role and managed assertions, the raw 6502 lane assertions, and the native-failure diagnostics assertions are unchanged apart from the two ELF expectations that flip to supported. - Base reproduction: on the pre-rebase base (83a4445) the same `rea analyze` call on the Android library failed in about two seconds with `target_format_unsupported` while `rea doctor` reported Ghidra available. Executed on this host. - User-visible CLI output: after the change, `rea analyze <lib> --provider ghidra` returned `segment_count: 29`, `procedure_count: 63343`, `string_count: 134169`, and `rea decompile <lib> --procedure _Z23Script_1051_GetVelocityfffiff --provider ghidra` returned 3,737 characters of Ghidra pseudocode with the Windows P0 limitations attached. - Remaining proof gaps: no source-owned ELF fixture and no `verify:ghidra` lane coverage, which is the gate #2186 established for Windows admission changes. ELF x86-64, ARM32, and thin Mach-O targets share the code path but were not run on a Windows host. The verified binary is proprietary and cannot be committed. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:local -- src/ghidra/GhidraProvider.behavior.test.ts` — 67 passed (after rebasing onto main at 767fe0f, which mocks the native loader in the Windows diagnostics tests). - `npm run check:fast` — passed. - `npm run docs:check` — passed. - Real Windows 11 x64 host, Ghidra 12.1.4, JDK 21.0.12.1, released 6.4.0 native addon, `REA_GHIDRA_STARTUP_TIMEOUT_MS=7200000`: `rea analyze` on a 44 MB AArch64 ELF (sha256 `94143e1c…682d52c4`) completed in 8 min 47 s with the overview above; `rea decompile` of a named procedure completed in 8 min 40 s with pseudocode. Not run: `npm run verify:ghidra`. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Previously rejected targets are now admitted; previously admitted targets behave identically. - Real Hopper/Ghidra, browser, or OS coverage: real Ghidra 12.1.4 on Windows 11 x64 for one ELF AArch64 target, as listed above. No fixture-based coverage yet. No Hopper or IDA coverage. - Package or release metadata impact: none beyond the limitation string. - Security, privacy, process, or containment review: no change to native admission, snapshot, DACL, or Job Object handling. ELF and Mach-O targets are imported as immutable private snapshots exactly like PE targets; the read-only P0 boundary and the mutation refusal are unchanged. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [ ] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. (Pending: verification bar, see above.) - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. (No issue requests ELF on Windows specifically; #2186, #2631, and #3111 are the adjacent ones. An earlier revision of this description wrongly stated that no related issue existed; that was written without searching and is corrected here.) - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5634
No description provided.