[PR #1342] [CLOSED] feat(ghidra): admit native x86 and x86-64 PE DLLs on Windows #2811

Closed
opened 2026-10-17 21:10:33 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1342
Author: @Wahaj18
Created: 10/9/2026
Status: ❌ Closed

Base: main ← Head: fix-1290-windows-ghidra-pe-dlls


📝 Commits (1)

  • 6f31eef feat(ghidra): admit native x86 and x86-64 PE DLLs on Windows

📊 Changes

15 files changed (+271 additions, -97 deletions)

View changed files

📝 .github/workflows/real-ghidra-windows.yml (+21 -1)
📝 AGENTS.md (+1 -1)
📝 docs/installation.md (+1 -1)
📝 docs/managed-code-analysis.md (+2 -2)
📝 docs/native-investigation.md (+1 -1)
📝 docs/provider-evaluation.md (+10 -10)
📝 docs/testing.md (+1 -1)
📝 docs/windows-ghidra-p0.md (+16 -5)
📝 scripts/create-ghidra-windows-fixture.mjs (+88 -18)
📝 scripts/verify-packaged-ghidra-windows.mjs (+15 -6)
📝 scripts/verify-real-ghidra-windows.mjs (+36 -8)
📝 src/ghidra/GhidraProvider.behavior.test.ts (+68 -37)
📝 src/ghidra/GhidraProvider.ts (+6 -3)
📝 src/ghidra/GhidraProviderCapabilities.ts (+1 -1)
📝 tests/conformance/README.md (+4 -2)

📄 Description

Closes #1290

Windows Ghidra P0 refused every PE marked as a DLL in its COFF characteristics (target_role_unsupported), even though Ghidra imports and decompiles native libraries statically through the same read-only path it uses for applications. This admits native x86 and x86-64 PE DLLs on Windows and keeps the rest of the boundary unchanged.

Behavior change

  • inspectWindowsP0TargetSupport (src/ghidra/GhidraProvider.ts) now accepts the observed shared-library role as well as application. Non-executable images, managed or unclassified PEs, unsupported architectures and malformed headers are still refused with their existing codes. Admission diagnostics keep reporting executable_role: "shared-library", so a DLL is never presented as an application.
  • The Windows P0 limitation in GhidraProviderCapabilities.ts and the refusal reasons now name DLLs.
  • No change to the Java bridge, the native addon, path admission, DACLs, Job Objects or the read-only operation set. Annotation stays unavailable on Windows.

Fixtures and verification lanes

  • scripts/create-ghidra-windows-fixture.mjs also emits rea-ghidra-windows.dll (PE32+, base 0x180000000) and rea-ghidra-windows-x86.dll (PE32, base 0x10000000). Each has no entry routine and an export table with fixture_caller (call fixture_return42, add 1, return) and fixture_return42 (return 42), matching the fixture described in the issue. The existing .exe fixtures are byte-identical to before (same SHA-256).
  • verify-real-ghidra-windows.mjs and verify-packaged-ghidra-windows.mjs accept --dll (combinable with --x86). For DLLs the real verifier also checks the shared-library role, that both exports are recovered at their addresses, that the callee decompiles to 42 and that the caller calls it and adds one.
  • real-ghidra-windows.yml runs the four DLL lanes (real and packaged, x86 and x86-64) after the existing ones. I raised the job timeout from 20 to 30 minutes since it now runs eight Ghidra lanes instead of four.
  • Docs (windows-ghidra-p0.md, provider-evaluation.md, installation.md, native-investigation.md, managed-code-analysis.md, testing.md, AGENTS.md, tests/conformance/README.md) describe DLL admission and the new lanes.

Verification

  • Rebased on main at 8c96baab. npx vitest run src/ghidra/GhidraProvider.behavior.test.ts: 30 passed. The new DLL cases fail on main and pass with this change. One test generates the fixtures and parses each with parseExecutableHeader to check format, architecture, role and managed: false before admission.
  • npm run test:fast: 329 files, 3613 passed, 4 skipped.
  • npm run check (typecheck, oxlint, oxfmt, knip, metadata) and npm run docs:check: pass.
  • Real Ghidra on Linux x64 (Ghidra 12.1.4, JDK 21): both generated DLLs opened through the MCP server. Both exports came back at base+0x1000 and base+0x1010, fixture_return42 decompiled to return 0x2a; and fixture_caller called it and added one.

Verified on Windows

These ran on a Windows x64 laptop (ordinary non-elevated user) with Ghidra 12.1.4, Temurin JDK 21.0.12.1, Node 24.13.1 and the addon built CI-style with MinGW-w64 (npm run build:windows-native). The run used the pre-rebase commit of this branch (54b5ea3b). The rebase onto current main applied cleanly, and the rebased commit passes the checks above.

  • npm run verify:windows-native:artifact: pass.
  • npm run verify:windows-native: pass. All file and process controls are true.
  • npm run verify:ghidra:windows (x64 EXE) and -- --x86 (x86 EXE): pass.
  • npm run verify:ghidra:windows -- --dll (x86-64 DLL, x86:LE:64:default) and -- --x86 --dll (x86 DLL, x86:LE:32:default): pass. executable_role: "shared-library", managed: false, all 25 read-only operations, cleanup complete, and Job Object, protected DACL and handle admission all true.
  • npm run verify:ghidra:windows:package (plain, --x86, --dll, --x86 --dll): each printed a report with "ok": true, covering the CLI, 29 MCP operations, both DLL exports found, and no runtime residue. Each process still exited 1, because the final rm(workspace) fails with EPERM: the verifier has loaded rea-windows-x64.node from inside that temporary install. This cleanup issue already exists on main and is separate from this change, so it should be fixed on its own.

There is also an open draft, #1303, for the same issue. I'm happy to consolidate this, or close it in favor of whichever approach the maintainers prefer.


🔄 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/1342 **Author:** [@Wahaj18](https://github.com/Wahaj18) **Created:** 10/9/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix-1290-windows-ghidra-pe-dlls` --- ### 📝 Commits (1) - [`6f31eef`](https://github.com/morluto/rea/commit/6f31eef67a955a999bfc1b225571dd35c7f00e8b) feat(ghidra): admit native x86 and x86-64 PE DLLs on Windows ### 📊 Changes **15 files changed** (+271 additions, -97 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/real-ghidra-windows.yml` (+21 -1) 📝 `AGENTS.md` (+1 -1) 📝 `docs/installation.md` (+1 -1) 📝 `docs/managed-code-analysis.md` (+2 -2) 📝 `docs/native-investigation.md` (+1 -1) 📝 `docs/provider-evaluation.md` (+10 -10) 📝 `docs/testing.md` (+1 -1) 📝 `docs/windows-ghidra-p0.md` (+16 -5) 📝 `scripts/create-ghidra-windows-fixture.mjs` (+88 -18) 📝 `scripts/verify-packaged-ghidra-windows.mjs` (+15 -6) 📝 `scripts/verify-real-ghidra-windows.mjs` (+36 -8) 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+68 -37) 📝 `src/ghidra/GhidraProvider.ts` (+6 -3) 📝 `src/ghidra/GhidraProviderCapabilities.ts` (+1 -1) 📝 `tests/conformance/README.md` (+4 -2) </details> ### 📄 Description Closes #1290 Windows Ghidra P0 refused every PE marked as a DLL in its COFF characteristics (`target_role_unsupported`), even though Ghidra imports and decompiles native libraries statically through the same read-only path it uses for applications. This admits native x86 and x86-64 PE DLLs on Windows and keeps the rest of the boundary unchanged. ## Behavior change - `inspectWindowsP0TargetSupport` (`src/ghidra/GhidraProvider.ts`) now accepts the observed `shared-library` role as well as `application`. Non-executable images, managed or unclassified PEs, unsupported architectures and malformed headers are still refused with their existing codes. Admission diagnostics keep reporting `executable_role: "shared-library"`, so a DLL is never presented as an application. - The Windows P0 limitation in `GhidraProviderCapabilities.ts` and the refusal reasons now name DLLs. - No change to the Java bridge, the native addon, path admission, DACLs, Job Objects or the read-only operation set. Annotation stays unavailable on Windows. ## Fixtures and verification lanes - `scripts/create-ghidra-windows-fixture.mjs` also emits `rea-ghidra-windows.dll` (PE32+, base `0x180000000`) and `rea-ghidra-windows-x86.dll` (PE32, base `0x10000000`). Each has no entry routine and an export table with `fixture_caller` (call `fixture_return42`, add 1, return) and `fixture_return42` (return 42), matching the fixture described in the issue. The existing `.exe` fixtures are byte-identical to before (same SHA-256). - `verify-real-ghidra-windows.mjs` and `verify-packaged-ghidra-windows.mjs` accept `--dll` (combinable with `--x86`). For DLLs the real verifier also checks the `shared-library` role, that both exports are recovered at their addresses, that the callee decompiles to 42 and that the caller calls it and adds one. - `real-ghidra-windows.yml` runs the four DLL lanes (real and packaged, x86 and x86-64) after the existing ones. I raised the job timeout from 20 to 30 minutes since it now runs eight Ghidra lanes instead of four. - Docs (`windows-ghidra-p0.md`, `provider-evaluation.md`, `installation.md`, `native-investigation.md`, `managed-code-analysis.md`, `testing.md`, `AGENTS.md`, `tests/conformance/README.md`) describe DLL admission and the new lanes. ## Verification - Rebased on `main` at `8c96baab`. `npx vitest run src/ghidra/GhidraProvider.behavior.test.ts`: 30 passed. The new DLL cases fail on `main` and pass with this change. One test generates the fixtures and parses each with `parseExecutableHeader` to check format, architecture, role and `managed: false` before admission. - `npm run test:fast`: 329 files, 3613 passed, 4 skipped. - `npm run check` (typecheck, oxlint, oxfmt, knip, metadata) and `npm run docs:check`: pass. - Real Ghidra on Linux x64 (Ghidra 12.1.4, JDK 21): both generated DLLs opened through the MCP server. Both exports came back at `base+0x1000` and `base+0x1010`, `fixture_return42` decompiled to `return 0x2a;` and `fixture_caller` called it and added one. ## Verified on Windows These ran on a Windows x64 laptop (ordinary non-elevated user) with Ghidra 12.1.4, Temurin JDK 21.0.12.1, Node 24.13.1 and the addon built CI-style with MinGW-w64 (`npm run build:windows-native`). The run used the pre-rebase commit of this branch (`54b5ea3b`). The rebase onto current `main` applied cleanly, and the rebased commit passes the checks above. - `npm run verify:windows-native:artifact`: pass. - `npm run verify:windows-native`: pass. All file and process controls are true. - `npm run verify:ghidra:windows` (x64 EXE) and `-- --x86` (x86 EXE): pass. - `npm run verify:ghidra:windows -- --dll` (x86-64 DLL, `x86:LE:64:default`) and `-- --x86 --dll` (x86 DLL, `x86:LE:32:default`): pass. `executable_role: "shared-library"`, `managed: false`, all 25 read-only operations, cleanup complete, and Job Object, protected DACL and handle admission all true. - `npm run verify:ghidra:windows:package` (plain, `--x86`, `--dll`, `--x86 --dll`): each printed a report with `"ok": true`, covering the CLI, 29 MCP operations, both DLL exports found, and no runtime residue. Each process still exited 1, because the final `rm(workspace)` fails with `EPERM`: the verifier has loaded `rea-windows-x64.node` from inside that temporary install. This cleanup issue already exists on `main` and is separate from this change, so it should be fixed on its own. There is also an open draft, #1303, for the same issue. I'm happy to consolidate this, or close it in favor of whichever approach the maintainers prefer. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:10:33 +00:00
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#2811
No description provided.