[GH-ISSUE #8175] [Design] Consider Kuna support for caller-described raw binaries #6462

Open
opened 2026-11-01 21:11:19 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Oct 30, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8175

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

Should an analyst who selects Kuna be able to analyze a caller-described headerless binary through the existing open_binary workflow, and what verified subset of architecture and load semantics should be supported?

Context and evidence

On macOS arm64 with REA 47fa6ab3795d547207001ffb01643c0aa39dcad8, Ghidra 12.1.4, and official Kuna 1.833, I created the six x86-64 bytes b8 2a 00 00 00 c3 without executing them. Direct Kuna functions --raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000 --json found one function; direct decompile ... --raw-image --target x86:LE:64:default --base 0x400000 --define-function 0x400000=audit_answer --json returned a function returning 0x2a. REA MCP open_binary with format=raw-binary, architecture=x86_64, entry_point=0x400000, and provider_id=kuna returned capability_unavailable; the same REA request selecting Ghidra opened, listed, and decompiled the fixture.

This is a capability gap, not evidence that REA promised Kuna support or that all raw images work. Ghidra is a working alternative when installed. The experiment covers one six-byte fixture, one host and one Kuna version, not other architectures, malformed images, or cache and lifecycle behavior.

Additional 1.988 workflow control (macOS arm64). Using official Kuna 1.988 and REA ae8223ccdfa0d5dbc659ddcbb7d6acf360343c3f (an unmerged branch), I analyzed a caller-created, unexecuted 12-byte x86-64 image e8 01 00 00 00 c3 b8 2a 00 00 00 c3, base and entry 0x400000 (SHA-256 1e5485cf1a26f5a853c48b476fc31ba9afd2d5597f7c061a957cfd7c088da295). Its first function calls 0x400006; the second returns 42. The file digest was unchanged.

  • Direct Kuna functions with --raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000 found both functions. decompile with the raw target/base and --define-function 0x400006=audit_answer returned 0x2a. decompile-project with raw target/base/entry exported pseudocode and assembly containing the call and return.
  • Direct decompile-graph explicitly rejected --raw-image; xrefs, strings, read, and disassemble reported it as an unknown option. These observations do not rule out another supported invocation or future releases. REA currently uses decompile-graph, xrefs, and strings for distinct workflows, so project export alone does not establish those workflows' coverage.
  • In both compact and full stdio MCP schema profiles, the same REA open_binary request with explicit Kuna returned capability_unavailable. Selecting Ghidra 12.1.4 opened the image; list_procedures found both addresses, procedure_pseudo_code returned 0x2a, procedure_callees and xrefs returned the call relationship, and read_bytes returned the original 12 bytes. Successful outputs validated against the advertised output schemas.

This evidence suggests that admitting raw input requires per-workflow capability and coverage decisions, not simply passing raw flags to every existing Kuna command. It does not establish broader raw-image support, cache behavior, or other architectures.

Expected interaction with targets

Read the selected local file and launch a caller-supplied Kuna process. No target execution is proposed. Output and cache effects would need to follow the existing Kuna provider contract.

Boundary details (optional)

Preserve the exact architecture, load mapping, entry and provider identity in the analysis profile and cache keys. Check raw-image support on every producer invoked by the actual REA workflows; do not assume that all Kuna commands accept the same flags, inventory or reference semantics. Returning an empty inventory or silently switching providers would misrepresent coverage.

Options and tradeoffs

Compare supporting only the current REA raw contract and separately verified per-architecture profiles, versus requiring Ghidra for this task. Do not expose unvalidated upstream target IDs simply because Kuna accepts them. Independent load-base and entry selection is already under discussion in #4246 and should remain a shared contract question rather than a Kuna-only flag.

Verification available so far

I have a prototype or observed results

Success criteria and open questions

If admitted, exercise actual CLI and MCP open, inventory, pseudocode, references, failure diagnostics and cache reuse on representative raw fixtures; test mismatched or invalid architecture and entry and preserve coverage limitations. Establish any required scope decision and report unverified configurations.

References

Existing raw import design: https://github.com/morluto/rea/issues/4246
Kuna CLI documentation: https://github.com/Noelo-Lab/kuna/blob/v1.833/docs/cli.md

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

AArch64 / Kuna 1.989 control

On macOS arm64 with Kuna 1.989, Ghidra 12.1.4 and REA checkout 9ebbe67e0, I created the unexecuted 16-byte AArch64 image 02 00 00 94 c0 03 5f d6 40 05 80 52 c0 03 5f d6 (SHA-256 26b06308b7da056ef20f1e938d173d5119651c773d56b337d3713d5b73a4da96), mapped at and seeded from 0x400000. Direct Kuna functions --raw-image --target AARCH64:LE:64:v8A:default --base 0x400000 --entry 0x400000 --json found entries at 0x400000 and 0x400008; direct raw decompile with a defined function at the latter returned 0x2a. An entry at 0x400100 failed as outside the mapped range. The target digest remained unchanged.

In compact and full real stdio MCP profiles, REA explicitly rejected a Kuna raw-binary open as capability_unavailable with the Kuna target-format reason. Ghidra opened the same caller-selected mapping, listed both entries, decompiled the second to a return of 0x2a, found the first function's call to the second, and returned all 16 original bytes. Successful replies validated against the advertised output schemas. As with the prior x86-64 control, direct Kuna 1.989 rejects --raw-image for decompile-graph, and reports that option unknown for xrefs, strings, read, disassemble, and raw-pcode; this is a check of that invocation shape, not proof that no other route exists.

The AArch64 control strengthens the case for investigating a bounded raw decompilation route but does not establish parity for REA's separate reference, byte-read, and graph workflows. Ghidra remains the exercised REA alternative. Raw Thumb, independent base/entry selection, cache isolation, malformed images, other hosts, and future Kuna versions remain outside this control.

Raw discovery does not establish entry reachability

Kuna 1.989's embedded raw-image documentation says the default rawdiscover sweeps executable bytes for direct-call targets. I checked the distinction with an unexecuted, caller-created AArch64 raw image c0 03 5f d6 03 00 00 94 00 00 00 00 00 00 00 00 c0 03 5f d6, mapped and seeded at 0x400000 (SHA-256 acf2f8b5ad05684adf009910adecedef31ab110efbc1b78b31649c0fb8e7a7d4). The entry instruction is ret; bytes at 0x400004 encode a direct call to 0x400010 but follow that return. Default direct Kuna functions reported entries at 0x400000 and 0x400010; --option rawdiscover off reported only the seeded entry. Both inventories gave sizes spanning bytes beyond the entry's return, so these sizes should not be interpreted as independently verified function bodies. This does not prove the second location cannot be a separate entry.

As an independent control, REA with Ghidra 12.1.4 listed only the seeded entry, showed its assembly as ret, and returned no callees for it; outputs passed their advertised MCP schemas. The file digest remained unchanged. These are different static discovery policies, not a universal verdict about which inventory is correct. Any future Kuna raw integration should expose discovery method and its coverage limitations, retain caller seeds and configuration in identity, and avoid describing sweep-discovered targets as proven reachable from the entry. The direct Kuna raw project export for the prior 16-byte control included labeled assembly with the direct call, but a formatted assembly line alone does not supply a validated general call-graph or xref contract.

Originally created by @morluto on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8175 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed Should an analyst who selects Kuna be able to analyze a caller-described headerless binary through the existing `open_binary` workflow, and what verified subset of architecture and load semantics should be supported? ### Context and evidence On macOS arm64 with REA `47fa6ab3795d547207001ffb01643c0aa39dcad8`, Ghidra 12.1.4, and official Kuna 1.833, I created the six x86-64 bytes `b8 2a 00 00 00 c3` without executing them. Direct Kuna `functions --raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000 --json` found one function; direct `decompile ... --raw-image --target x86:LE:64:default --base 0x400000 --define-function 0x400000=audit_answer --json` returned a function returning `0x2a`. REA MCP `open_binary` with `format=raw-binary`, `architecture=x86_64`, `entry_point=0x400000`, and `provider_id=kuna` returned `capability_unavailable`; the same REA request selecting Ghidra opened, listed, and decompiled the fixture. This is a capability gap, not evidence that REA promised Kuna support or that all raw images work. Ghidra is a working alternative when installed. The experiment covers one six-byte fixture, one host and one Kuna version, not other architectures, malformed images, or cache and lifecycle behavior. **Additional 1.988 workflow control (macOS arm64).** Using official Kuna 1.988 and REA `ae8223ccdfa0d5dbc659ddcbb7d6acf360343c3f` (an unmerged branch), I analyzed a caller-created, unexecuted 12-byte x86-64 image `e8 01 00 00 00 c3 b8 2a 00 00 00 c3`, base and entry `0x400000` (SHA-256 `1e5485cf1a26f5a853c48b476fc31ba9afd2d5597f7c061a957cfd7c088da295`). Its first function calls `0x400006`; the second returns 42. The file digest was unchanged. - Direct Kuna `functions` with `--raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000` found both functions. `decompile` with the raw target/base and `--define-function 0x400006=audit_answer` returned `0x2a`. `decompile-project` with raw target/base/entry exported pseudocode and assembly containing the call and return. - Direct `decompile-graph` explicitly rejected `--raw-image`; `xrefs`, `strings`, `read`, and `disassemble` reported it as an unknown option. These observations do not rule out another supported invocation or future releases. REA currently uses `decompile-graph`, `xrefs`, and `strings` for distinct workflows, so project export alone does not establish those workflows' coverage. - In both compact and full stdio MCP schema profiles, the same REA `open_binary` request with explicit Kuna returned `capability_unavailable`. Selecting Ghidra 12.1.4 opened the image; `list_procedures` found both addresses, `procedure_pseudo_code` returned `0x2a`, `procedure_callees` and `xrefs` returned the call relationship, and `read_bytes` returned the original 12 bytes. Successful outputs validated against the advertised output schemas. This evidence suggests that admitting raw input requires per-workflow capability and coverage decisions, not simply passing raw flags to every existing Kuna command. It does not establish broader raw-image support, cache behavior, or other architectures. ### Expected interaction with targets Read the selected local file and launch a caller-supplied Kuna process. No target execution is proposed. Output and cache effects would need to follow the existing Kuna provider contract. ### Boundary details (optional) Preserve the exact architecture, load mapping, entry and provider identity in the analysis profile and cache keys. Check raw-image support on every producer invoked by the actual REA workflows; do not assume that all Kuna commands accept the same flags, inventory or reference semantics. Returning an empty inventory or silently switching providers would misrepresent coverage. ### Options and tradeoffs Compare supporting only the current REA raw contract and separately verified per-architecture profiles, versus requiring Ghidra for this task. Do not expose unvalidated upstream target IDs simply because Kuna accepts them. Independent load-base and entry selection is already under discussion in #4246 and should remain a shared contract question rather than a Kuna-only flag. ### Verification available so far I have a prototype or observed results ### Success criteria and open questions If admitted, exercise actual CLI and MCP open, inventory, pseudocode, references, failure diagnostics and cache reuse on representative raw fixtures; test mismatched or invalid architecture and entry and preserve coverage limitations. Establish any required scope decision and report unverified configurations. ### References Existing raw import design: https://github.com/morluto/rea/issues/4246 Kuna CLI documentation: https://github.com/Noelo-Lab/kuna/blob/v1.833/docs/cli.md cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 ### AArch64 / Kuna 1.989 control On macOS arm64 with Kuna 1.989, Ghidra 12.1.4 and REA checkout `9ebbe67e0`, I created the unexecuted 16-byte AArch64 image `02 00 00 94 c0 03 5f d6 40 05 80 52 c0 03 5f d6` (SHA-256 `26b06308b7da056ef20f1e938d173d5119651c773d56b337d3713d5b73a4da96`), mapped at and seeded from `0x400000`. Direct Kuna `functions --raw-image --target AARCH64:LE:64:v8A:default --base 0x400000 --entry 0x400000 --json` found entries at `0x400000` and `0x400008`; direct raw `decompile` with a defined function at the latter returned `0x2a`. An entry at `0x400100` failed as outside the mapped range. The target digest remained unchanged. In compact and full real stdio MCP profiles, REA explicitly rejected a Kuna raw-binary open as `capability_unavailable` with the Kuna target-format reason. Ghidra opened the same caller-selected mapping, listed both entries, decompiled the second to a return of `0x2a`, found the first function's call to the second, and returned all 16 original bytes. Successful replies validated against the advertised output schemas. As with the prior x86-64 control, direct Kuna 1.989 rejects `--raw-image` for `decompile-graph`, and reports that option unknown for `xrefs`, `strings`, `read`, `disassemble`, and `raw-pcode`; this is a check of that invocation shape, not proof that no other route exists. The AArch64 control strengthens the case for investigating a bounded raw decompilation route but does not establish parity for REA's separate reference, byte-read, and graph workflows. Ghidra remains the exercised REA alternative. Raw Thumb, independent base/entry selection, cache isolation, malformed images, other hosts, and future Kuna versions remain outside this control. ### Raw discovery does not establish entry reachability Kuna 1.989's embedded raw-image documentation says the default `rawdiscover` sweeps executable bytes for direct-call targets. I checked the distinction with an unexecuted, caller-created AArch64 raw image `c0 03 5f d6 03 00 00 94 00 00 00 00 00 00 00 00 c0 03 5f d6`, mapped and seeded at `0x400000` (SHA-256 `acf2f8b5ad05684adf009910adecedef31ab110efbc1b78b31649c0fb8e7a7d4`). The entry instruction is `ret`; bytes at `0x400004` encode a direct call to `0x400010` but follow that return. Default direct Kuna `functions` reported entries at `0x400000` and `0x400010`; `--option rawdiscover off` reported only the seeded entry. Both inventories gave sizes spanning bytes beyond the entry's return, so these sizes should not be interpreted as independently verified function bodies. This does not prove the second location cannot be a separate entry. As an independent control, REA with Ghidra 12.1.4 listed only the seeded entry, showed its assembly as `ret`, and returned no callees for it; outputs passed their advertised MCP schemas. The file digest remained unchanged. These are different static discovery policies, not a universal verdict about which inventory is correct. Any future Kuna raw integration should expose discovery method and its coverage limitations, retain caller seeds and configuration in identity, and avoid describing sweep-discovered targets as proven reachable from the entry. The direct Kuna raw project export for the prior 16-byte control included labeled assembly with the direct call, but a formatted assembly line alone does not supply a validated general call-graph or xref contract.
Author
Owner

@morluto commented on GitHub (Oct 30, 2026):

A further real-provider check on macOS arm64 with Kuna 1.986 clarifies why raw admission needs operation-level capability decisions, not just a loader flag.

On a self-built, unexecuted 12-byte x86-64 raw image, the first function contains a direct call to a second function, which returns 0x2a. With --raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000, direct kuna functions discovered both entries; individually decompiling each worked. With both entries supplied, decompile-project --jobs 1 exported two bodies and assembly containing the expected direct call, reporting zero failures. These are provider observations on one small image; the assembly is a human-readable listing, not a verified replacement for typed reference Evidence.

In separate direct invocations, decompile-graph rejected --raw-image explicitly (exit 2); xrefs, disassemble, and read rejected it as an unknown option (exit 2). On a separate three-entry raw fixture, functions --reachable-from and decompile-all --reachable-from explicitly rejected that combination because raw input lacks required object metadata. Thus the current REA/Kuna call-graph/xref producers cannot simply receive the same raw arguments as the project-export producer. This is not a blanket claim that no upstream raw reference analysis is possible through any other interface.

For the 12-byte fixture, real REA/Kuna open_binary correctly returned capability_unavailable under today's contract. REA/Ghidra on the same explicit raw configuration found both functions, returned the original 12 bytes, reported the call and incoming reference, and traversed a two-node graph. Neither binary was executed and their SHA-256 values stayed unchanged. This supports a potential partial Kuna lane only if unavailable graph/reference operations are clearly represented and all admitted workflows, cache identities and controls are separately verified; it does not establish full parity or suggest silently falling back to Ghidra.

<!-- gh-comment-id:6534919468 --> @morluto commented on GitHub (Oct 30, 2026): A further real-provider check on macOS arm64 with Kuna 1.986 clarifies why raw admission needs operation-level capability decisions, not just a loader flag. On a self-built, unexecuted 12-byte x86-64 raw image, the first function contains a direct call to a second function, which returns `0x2a`. With `--raw-image --target x86:LE:64:default --base 0x400000 --entry 0x400000`, direct `kuna functions` discovered both entries; individually decompiling each worked. With both entries supplied, `decompile-project --jobs 1` exported two bodies and assembly containing the expected direct call, reporting zero failures. These are provider observations on one small image; the assembly is a human-readable listing, not a verified replacement for typed reference Evidence. In separate direct invocations, `decompile-graph` rejected `--raw-image` explicitly (exit 2); `xrefs`, `disassemble`, and `read` rejected it as an unknown option (exit 2). On a separate three-entry raw fixture, `functions --reachable-from` and `decompile-all --reachable-from` explicitly rejected that combination because raw input lacks required object metadata. Thus the current REA/Kuna call-graph/xref producers cannot simply receive the same raw arguments as the project-export producer. This is not a blanket claim that no upstream raw reference analysis is possible through any other interface. For the 12-byte fixture, real REA/Kuna `open_binary` correctly returned `capability_unavailable` under today's contract. REA/Ghidra on the same explicit raw configuration found both functions, returned the original 12 bytes, reported the call and incoming reference, and traversed a two-node graph. Neither binary was executed and their SHA-256 values stayed unchanged. This supports a potential partial Kuna lane only if unavailable graph/reference operations are clearly represented and all admitted workflows, cache identities and controls are separately verified; it does not establish full parity or suggest silently falling back to Ghidra.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the Ghidra, Kuna, and REA tool-design investigation.

<!-- gh-comment-id:6538785863 --> @morluto commented on GitHub (Oct 31, 2026): Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the Ghidra, Kuna, and REA tool-design investigation.
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#6462
No description provided.