[PR #579] [MERGED] fix(ghidra): recover evidenced switch cases and default targets #2081

Closed
opened 2026-10-16 21:14:01 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/579
Author: @N0zoM1z0
Created: 10/5/2026
Status: ✅ Merged
Merged: 10/5/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/ghidra-switch-evidence


📝 Commits (1)

  • 857d3b2 fix(ghidra): recover evidenced switch cases and default targets

📊 Changes

26 files changed (+1955 additions, -55 deletions)

View changed files

📝 bridge/ghidra/ReaGhidraBridge.java (+184 -31)
📝 docs/native-investigation.md (+15 -0)
📝 docs/product-catalog.json (+2 -2)
📝 docs/testing.md (+20 -0)
📝 docs/verification/managed-conformance-manifest.json (+2 -2)
📝 package.json (+1 -0)
📝 scripts/verify-real-ghidra-assertions.mjs (+11 -2)
📝 scripts/verify-real-ghidra-function.mjs (+34 -0)
➕ scripts/verify-real-ghidra-switch-assertions.mjs (+420 -0)
➕ scripts/verify-real-ghidra-switch-controls.mjs (+156 -0)
➕ scripts/verify-real-ghidra-switch.mjs (+348 -0)
📝 scripts/verify-real-ghidra.mjs (+49 -14)
📝 skills/reverse-engineer-anything/SKILL.md (+1 -1)
📝 src/application/NativeApiInspection.test.ts (+65 -0)
📝 src/application/NativeApiInspection.ts (+4 -0)
📝 src/contracts/functionWorkflowToolContracts.ts (+1 -1)
📝 src/domain/hopperValues.fixture.ts (+14 -0)
📝 src/domain/nativeApiBoundary.ts (+7 -0)
📝 src/generatedMcpToolCatalog.ts (+1 -1)
📝 src/ghidra/GhidraAnalysisProfile.ts (+2 -0)

...and 6 more files

📄 Description

Summary

Recover case values from typed Ghidra case tokens, the recovered block entry, and a unique indirect dispatch predecessor. Avoid positional pairing of label/destination arrays, preserve shared targets and negative labels, and keep ambiguous or nonexact JSON integers unresolved with their original token/magnitude/address diagnostics.

Add explicit jump_tables[].default_targets; mappings[].case_value: null means an unresolved case association. Collect observed backing-table metadata separately and version the analysis profile so old cached dossiers do not imply the new coverage. Legacy records normalize absent defaults to an empty array and retain unknowns.

Generic MCP result fragment:

{
  "mappings": [{"case_value": 2, "target_address": "0x401230", "confidence": "high", "evidence": [{"kind": "jump-table", "source": "ghidra-clang-case-token", "detail": "Typed case value 2 belongs to the p-code block starting at recovered target 0x401230; its unique indirect dispatch predecessor is 0x401200."}]}],
  "default_targets": [{"target_address": "0x401250", "confidence": "high", "evidence": [{"kind": "jump-table", "source": "ghidra-clang-case-token", "detail": "Typed default label belongs to the p-code block starting at recovered target 0x401250; its unique indirect dispatch predecessor is 0x401200."}]}]
}

Verification

  • npm run check:pr:338files,1835tests passed,1skipped; all gate and generated-document tasks passed. Local process affinity selected one worker through the existing config; test deadlines/assertions were unchanged.
  • npm run check:ci:passed, including duplication/TODO checks.
  • env -u GHIDRA_INSTALL_DIR TMPDIR=/tmp npm run verify:package:passed; fresh package/install CLI and MCP116tools. Tarball content audit passed; no binary/project/private artifacts.
  • node scripts/verify-real-ghidra.mjs and REA_CC=clang node scripts/verify-real-ghidra.mjs:both full host lanes passed,40numeric cases+1typed default and zero switch residuals; actual CLI/MCP native value trace passed.
  • node scripts/verify-real-ghidra.mjs --aarch64-jump-table:passed, including relative byte/halfword fixtures.
  • node scripts/verify-real-ghidra-dos.mjs:passed with input immutability and scoped CLI/MCP parity.
  • node scripts/verify-real-ghidra-switch.mjs --compiler-oracle-only:4variants×6functions and22fault controls passed.
  • node scripts/verify-real-ghidra-switch.mjs --entrypoint <fresh-installed-package>/scripts/rea.mjs:all24functions through actual CLI/MCP,32actual bridge controls,22fault controls and cleanup passed. Installed bridge/domain/application/profile bytes match the tested source/build.

Public acceptance uses generated generic C fixtures: dense, holes/shared bodies, nonzero and negative ranges, unsafe 64-bit labels, and comparison-only control; GCC/Clang optimized and stripped variants. Independent symbols, ELF bytes, table slots, bounds branches and dispatch instruction addresses define the oracle. Debug negative labels must preserve their signed value. Stripped negatives may use exact equivalent uint32 labels only when the32-bit dispatch bytes and low-confidence undefined4 ABI are independently checked; original source signedness remains unknown. Actual CLI and stdio MCP observations must agree. The separate Ghidra model guard invokes the shipped bridge methods on detached model objects and authenticates the loaded source; it does not claim a compiler naturally emitted ambiguous predecessor graphs.

Real provider verification is Linux x64, Ghidra 12.1.4, JDK 21. AArch64 verification analyzes cross-compiled fixtures on Linux. Real Hopper, macOS and Windows hosts were not verified for this change.

All committed fixtures are source only. No target binaries or analysis projects are included.


🔄 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/579 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/5/2026 **Status:** ✅ Merged **Merged:** 10/5/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/ghidra-switch-evidence` --- ### 📝 Commits (1) - [`857d3b2`](https://github.com/morluto/rea/commit/857d3b2f7a1ab126ab226a2c9e3df08a435a236c) fix(ghidra): recover evidenced switch cases and default targets ### 📊 Changes **26 files changed** (+1955 additions, -55 deletions) <details> <summary>View changed files</summary> 📝 `bridge/ghidra/ReaGhidraBridge.java` (+184 -31) 📝 `docs/native-investigation.md` (+15 -0) 📝 `docs/product-catalog.json` (+2 -2) 📝 `docs/testing.md` (+20 -0) 📝 `docs/verification/managed-conformance-manifest.json` (+2 -2) 📝 `package.json` (+1 -0) 📝 `scripts/verify-real-ghidra-assertions.mjs` (+11 -2) 📝 `scripts/verify-real-ghidra-function.mjs` (+34 -0) ➕ `scripts/verify-real-ghidra-switch-assertions.mjs` (+420 -0) ➕ `scripts/verify-real-ghidra-switch-controls.mjs` (+156 -0) ➕ `scripts/verify-real-ghidra-switch.mjs` (+348 -0) 📝 `scripts/verify-real-ghidra.mjs` (+49 -14) 📝 `skills/reverse-engineer-anything/SKILL.md` (+1 -1) 📝 `src/application/NativeApiInspection.test.ts` (+65 -0) 📝 `src/application/NativeApiInspection.ts` (+4 -0) 📝 `src/contracts/functionWorkflowToolContracts.ts` (+1 -1) 📝 `src/domain/hopperValues.fixture.ts` (+14 -0) 📝 `src/domain/nativeApiBoundary.ts` (+7 -0) 📝 `src/generatedMcpToolCatalog.ts` (+1 -1) 📝 `src/ghidra/GhidraAnalysisProfile.ts` (+2 -0) _...and 6 more files_ </details> ### 📄 Description ## Summary Recover case values from typed Ghidra case tokens, the recovered block entry, and a unique indirect dispatch predecessor. Avoid positional pairing of label/destination arrays, preserve shared targets and negative labels, and keep ambiguous or nonexact JSON integers unresolved with their original token/magnitude/address diagnostics. Add explicit `jump_tables[].default_targets`; `mappings[].case_value: null` means an unresolved case association. Collect observed backing-table metadata separately and version the analysis profile so old cached dossiers do not imply the new coverage. Legacy records normalize absent defaults to an empty array and retain unknowns. Generic MCP result fragment: ```json { "mappings": [{"case_value": 2, "target_address": "0x401230", "confidence": "high", "evidence": [{"kind": "jump-table", "source": "ghidra-clang-case-token", "detail": "Typed case value 2 belongs to the p-code block starting at recovered target 0x401230; its unique indirect dispatch predecessor is 0x401200."}]}], "default_targets": [{"target_address": "0x401250", "confidence": "high", "evidence": [{"kind": "jump-table", "source": "ghidra-clang-case-token", "detail": "Typed default label belongs to the p-code block starting at recovered target 0x401250; its unique indirect dispatch predecessor is 0x401200."}]}] } ``` ## Verification - `npm run check:pr`:338files,1835tests passed,1skipped; all gate and generated-document tasks passed. Local process affinity selected one worker through the existing config; test deadlines/assertions were unchanged. - `npm run check:ci`:passed, including duplication/TODO checks. - `env -u GHIDRA_INSTALL_DIR TMPDIR=/tmp npm run verify:package`:passed; fresh package/install CLI and MCP116tools. Tarball content audit passed; no binary/project/private artifacts. - `node scripts/verify-real-ghidra.mjs` and `REA_CC=clang node scripts/verify-real-ghidra.mjs`:both full host lanes passed,40numeric cases+1typed default and zero switch residuals; actual CLI/MCP native value trace passed. - `node scripts/verify-real-ghidra.mjs --aarch64-jump-table`:passed, including relative byte/halfword fixtures. - `node scripts/verify-real-ghidra-dos.mjs`:passed with input immutability and scoped CLI/MCP parity. - `node scripts/verify-real-ghidra-switch.mjs --compiler-oracle-only`:4variants×6functions and22fault controls passed. - `node scripts/verify-real-ghidra-switch.mjs --entrypoint <fresh-installed-package>/scripts/rea.mjs`:all24functions through actual CLI/MCP,32actual bridge controls,22fault controls and cleanup passed. Installed bridge/domain/application/profile bytes match the tested source/build. Public acceptance uses generated generic C fixtures: dense, holes/shared bodies, nonzero and negative ranges, unsafe 64-bit labels, and comparison-only control; GCC/Clang optimized and stripped variants. Independent symbols, ELF bytes, table slots, bounds branches and dispatch instruction addresses define the oracle. Debug negative labels must preserve their signed value. Stripped negatives may use exact equivalent uint32 labels only when the32-bit dispatch bytes and low-confidence undefined4 ABI are independently checked; original source signedness remains unknown. Actual CLI and stdio MCP observations must agree. The separate Ghidra model guard invokes the shipped bridge methods on detached model objects and authenticates the loaded source; it does not claim a compiler naturally emitted ambiguous predecessor graphs. Real provider verification is Linux x64, Ghidra 12.1.4, JDK 21. AArch64 verification analyzes cross-compiled fixtures on Linux. Real Hopper, macOS and Windows hosts were not verified for this change. All committed fixtures are source only. No target binaries or analysis projects are included. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-16 21:14:01 +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#2081
No description provided.