[GH-ISSUE #8372] [Design] Correlate native addresses across provider coordinate contexts #6571

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

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

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

How should an agent explicitly correlate an address observed by one provider with the corresponding source bytes and address in a different provider's selected analysis, without silently equating their numeric addresses or assuming a single image-base adjustment?

Context and evidence

A constructed, unexecuted arm64 Mach-O has _caller call _goal, and a separate _decoy exactly 0x1000 earlier. I imported it into a disposable Ghidra 12.1.4 project and used a headless Ghidra script to rebase that project from 0x100000000 to 0x100001000. REA #8368 branch de0305d used that explicitly selected project and the unchanged original target, with public MCP and full advertised schemas.

  • Verified Kuna 1.986 trace_feature({query:"goal"}) returns the _goal match and source 0x1000012e8, with the source's containing procedure explicitly unavailable. Native symbols/disassembly establish this source is _caller in Kuna's original coordinates.
  • Reopen the same target with the rebased Ghidra project and ask resolve_containing_procedure({address:"0x1000012e8"}). It successfully reports _decoy; that answer is valid for the selected Ghidra coordinates, but is not the owner of Kuna's referenced source bytes. address_to_file_offset gives 744 for this address.
  • For this fixture I independently mapped the source using the known original and selected project mappings. The corresponding Ghidra address is 0x1000022e8; containment reports _caller, and address_to_file_offset gives 4840. REA inspect_macho reports an original __TEXT mapping starting at 0x100000000, file offset 0; Ghidra inspect_native_load_image reports its initialized project mapping, source file identity and rebased coordinates. Those facts support the mapping for this fixture. Both REA address_to_file_offset and inspect_native_load_image returned capability_unavailable while Kuna was selected; inspect_macho was available.
  • A separate non-overlapping rebase gave an explicit outside_segments result for the unadjusted address instead of a wrong-looking successful owner. binary_overview reports the selected Ghidra image base in both experiments.

The target SHA-256 was 555093057af7d58350f69f5f456eba901c7c27cea67a7b50f090c1740d32fd47; target and selected project file hashes were unchanged by REA. Project creation used an explicit script on an owned temporary project. No target was executed. The initial trace's unavailable-owner variant is from the unmerged PR; the coordinate interpretation concerns existing provider and project semantics, not a claim that resolve_containing_procedure answered the selected Ghidra address incorrectly.

Expected interaction with targets

Read explicitly selected local target/project evidence, use existing static providers, and write only caller-selected Evidence or owned temporary analysis data. No target execution or mutation is proposed.

Boundary details

Require exact target/slice identity and explicit source and destination analysis contexts. Preserve input coordinates, mapping evidence, address space and the originating provider/profile. File offsets, virtual addresses, zero-fill, overlays, transformed/decompressed bytes, relocation, duplicate mappings and modified Ghidra memory can make a mapping ambiguous or invalid; unknown must remain unknown. Do not automatically rebase an arbitrary numeric address by subtracting an image base. A later observation does not rewrite the original provider's Evidence.

Options and tradeoffs

Compare a bounded cross-context navigation workflow using explicit retained observations and unique source mappings, a format-aware manual procedure using existing evidence, or improved guidance that makes the current steps and limits clear. It may be sufficient to expose the current mapping facts more discoverably; this does not require wrapping provider APIs or automatically switching projects. Account for user-selected project and annotation lifetime (#8289).

Verification available so far

I have a prototype or observed results

Success criteria and open questions

Check the overlapping and non-overlapping cases above, matching-address fresh imports, unavailable and multiple mappings, different slices/digests and address spaces, provider-specific unmapped data, and exported/offline Evidence. Ensure a correct result identifies its mapping and that ambiguous cases do not choose an unrelated function. Real autonomous-agent behavior, other providers/OSes and transformed project memory are unverified.

References

Related #8348 (actionable Kuna references), #8288 (unavailable feature-trace owner), #8178 (decompile address vs file-offset intent), #8170 (verified Kuna byte reads), and #8232 (selected Ghidra memory vs original bytes).

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8372 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the 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 How should an agent explicitly correlate an address observed by one provider with the corresponding source bytes and address in a different provider's selected analysis, without silently equating their numeric addresses or assuming a single image-base adjustment? ### Context and evidence A constructed, unexecuted arm64 Mach-O has `_caller` call `_goal`, and a separate `_decoy` exactly `0x1000` earlier. I imported it into a disposable Ghidra 12.1.4 project and used a headless Ghidra script to rebase that project from `0x100000000` to `0x100001000`. REA #8368 branch `de0305d` used that explicitly selected project and the unchanged original target, with public MCP and full advertised schemas. - Verified Kuna 1.986 `trace_feature({query:"goal"})` returns the `_goal` match and source `0x1000012e8`, with the source's containing procedure explicitly unavailable. Native symbols/disassembly establish this source is `_caller` in Kuna's original coordinates. - Reopen the same target with the rebased Ghidra project and ask `resolve_containing_procedure({address:"0x1000012e8"})`. It **successfully** reports `_decoy`; that answer is valid for the selected Ghidra coordinates, but is not the owner of Kuna's referenced source bytes. `address_to_file_offset` gives 744 for this address. - For this fixture I independently mapped the source using the known original and selected project mappings. The corresponding Ghidra address is `0x1000022e8`; containment reports `_caller`, and `address_to_file_offset` gives 4840. REA `inspect_macho` reports an original `__TEXT` mapping starting at `0x100000000`, file offset 0; Ghidra `inspect_native_load_image` reports its initialized project mapping, source file identity and rebased coordinates. Those facts support the mapping for this fixture. Both REA `address_to_file_offset` and `inspect_native_load_image` returned `capability_unavailable` while Kuna was selected; `inspect_macho` was available. - A separate non-overlapping rebase gave an explicit `outside_segments` result for the unadjusted address instead of a wrong-looking successful owner. `binary_overview` reports the selected Ghidra image base in both experiments. The target SHA-256 was `555093057af7d58350f69f5f456eba901c7c27cea67a7b50f090c1740d32fd47`; target and selected project file hashes were unchanged by REA. Project creation used an explicit script on an owned temporary project. No target was executed. The initial trace's unavailable-owner variant is from the unmerged PR; the coordinate interpretation concerns existing provider and project semantics, not a claim that `resolve_containing_procedure` answered the selected Ghidra address incorrectly. ### Expected interaction with targets Read explicitly selected local target/project evidence, use existing static providers, and write only caller-selected Evidence or owned temporary analysis data. No target execution or mutation is proposed. ### Boundary details Require exact target/slice identity and explicit source and destination analysis contexts. Preserve input coordinates, mapping evidence, address space and the originating provider/profile. File offsets, virtual addresses, zero-fill, overlays, transformed/decompressed bytes, relocation, duplicate mappings and modified Ghidra memory can make a mapping ambiguous or invalid; unknown must remain unknown. Do not automatically rebase an arbitrary numeric address by subtracting an image base. A later observation does not rewrite the original provider's Evidence. ### Options and tradeoffs Compare a bounded cross-context navigation workflow using explicit retained observations and unique source mappings, a format-aware manual procedure using existing evidence, or improved guidance that makes the current steps and limits clear. It may be sufficient to expose the current mapping facts more discoverably; this does not require wrapping provider APIs or automatically switching projects. Account for user-selected project and annotation lifetime (#8289). ### Verification available so far I have a prototype or observed results ### Success criteria and open questions Check the overlapping and non-overlapping cases above, matching-address fresh imports, unavailable and multiple mappings, different slices/digests and address spaces, provider-specific unmapped data, and exported/offline Evidence. Ensure a correct result identifies its mapping and that ambiguous cases do not choose an unrelated function. Real autonomous-agent behavior, other providers/OSes and transformed project memory are unverified. ### References Related #8348 (actionable Kuna references), #8288 (unavailable feature-trace owner), #8178 (decompile address vs file-offset intent), #8170 (verified Kuna byte reads), and #8232 (selected Ghidra memory vs original bytes). cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

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

Existing-workflow control on this same fixture, using verified Kuna 1.986 and the selected rebased Ghidra 12.1.4 project through public MCP with full advertised schemas:

  • I obtained a Kuna analyze_function(_caller) dossier, then Ghidra dossiers for both the numerically overlapping _decoy and the mapped _caller. Each was passed as its exact retained Evidence reference to compare_functions.
  • Kuna _caller versus Ghidra _decoy returned function_match.status: "ambiguous" and overall status: "unknown", despite the same numeric entry address. The calls dimension reported changed; the identity itself was not asserted matched.
  • Kuna _caller versus the correctly mapped Ghidra _caller also returned an ambiguous function match and overall unknown; its calls dimension was unknown. The comparison cited missing common executable coordinate context and provider-specific comparison limits.

Thus the existing comparison avoids asserting the wrong function identity in this controlled case, but it does not itself choose the corresponding coordinate or prove the true pair. The explicit source-file mapping described above remains the way I selected the right pair in this fixture. Target and selected project hashes were unchanged. This is not a universal cross-provider identity guarantee or an autonomous-agent trial.

<!-- gh-comment-id:6548598432 --> @morluto commented on GitHub (Oct 31, 2026): Existing-workflow control on this same fixture, using verified Kuna 1.986 and the selected rebased Ghidra 12.1.4 project through public MCP with full advertised schemas: - I obtained a Kuna `analyze_function(_caller)` dossier, then Ghidra dossiers for both the numerically overlapping `_decoy` and the mapped `_caller`. Each was passed as its exact retained Evidence reference to `compare_functions`. - Kuna `_caller` versus Ghidra `_decoy` returned `function_match.status: "ambiguous"` and overall `status: "unknown"`, despite the same numeric entry address. The calls dimension reported `changed`; the identity itself was not asserted matched. - Kuna `_caller` versus the correctly mapped Ghidra `_caller` also returned an ambiguous function match and overall unknown; its calls dimension was unknown. The comparison cited missing common executable coordinate context and provider-specific comparison limits. Thus the existing comparison avoids asserting the wrong function identity in this controlled case, but it does not itself choose the corresponding coordinate or prove the true pair. The explicit source-file mapping described above remains the way I selected the right pair in this fixture. Target and selected project hashes were unchanged. This is not a universal cross-provider identity guarantee or an autonomous-agent trial.
Author
Owner

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

A combined rebased and edited-project control shows why a correct file-offset correlation alone cannot establish that two provider observations describe equal analyzed bytes.

I created a separate owned Ghidra 12.1.4 project from the #8372 fixture, rebased it by 0x1000, then explicitly replaced the _caller instruction at the mapped project address with an ARM64 NOP using a headless script and re-disassembled it. This was a deliberate edit to the disposable project, not a change made by REA. The source executable stayed unchanged.

Through public MCP, verified Kuna 1.986 still reported its original _goal reference source at 0x1000012e8. In the selected Ghidra project, the corresponding source-file offset remains 4840 and its mapped address is 0x1000022e8. However:

  • A direct independent read of the unchanged source file at that offset gives fefbff97 (the original call instruction).
  • Ghidra read_bytes gives 1f2003d5; inspect_native_instruction decodes nop, and resolve_native_call_targets reports not-call.
  • inspect_native_load_image reports the original and modified source-file digests separately and retains status: "unsupported" for independent Mach-O verification. The source digest is the original target digest; the modified digest differs. This one scripted edit establishes the cause in this fixture; a digest difference alone would not establish a patch in general (see #8232).

REA left the selected project's regular-file hashes and the target hash unchanged during both runs. Full advertised MCP schemas were used. The experiment supports retaining coordinate correspondence and content/analysis agreement as separate facts: the file mapping can identify where the original bytes came from, while the selected project's current instruction can differ. It does not establish a general cross-provider mapping, runtime behavior, or relocation semantics. The first project-creation attempt failed because Ghidra refused to write over a defined instruction; the successful disposable project cleared and re-disassembled that instruction before saving.

<!-- gh-comment-id:6548615107 --> @morluto commented on GitHub (Oct 31, 2026): A combined **rebased and edited-project** control shows why a correct file-offset correlation alone cannot establish that two provider observations describe equal analyzed bytes. I created a separate owned Ghidra 12.1.4 project from the #8372 fixture, rebased it by `0x1000`, then explicitly replaced the `_caller` instruction at the mapped project address with an ARM64 NOP using a headless script and re-disassembled it. This was a deliberate edit to the disposable project, not a change made by REA. The source executable stayed unchanged. Through public MCP, verified Kuna 1.986 still reported its original `_goal` reference source at `0x1000012e8`. In the selected Ghidra project, the corresponding source-file offset remains 4840 and its mapped address is `0x1000022e8`. However: - A direct independent read of the unchanged source file at that offset gives `fefbff97` (the original call instruction). - Ghidra `read_bytes` gives `1f2003d5`; `inspect_native_instruction` decodes `nop`, and `resolve_native_call_targets` reports `not-call`. - `inspect_native_load_image` reports the original and modified source-file digests separately and retains `status: "unsupported"` for independent Mach-O verification. The source digest is the original target digest; the modified digest differs. This one scripted edit establishes the cause in this fixture; a digest difference alone would not establish a patch in general (see #8232). REA left the selected project's regular-file hashes and the target hash unchanged during both runs. Full advertised MCP schemas were used. The experiment supports retaining **coordinate correspondence and content/analysis agreement as separate facts**: the file mapping can identify where the original bytes came from, while the selected project's current instruction can differ. It does not establish a general cross-provider mapping, runtime behavior, or relocation semantics. The first project-creation attempt failed because Ghidra refused to write over a defined instruction; the successful disposable project cleared and re-disassembled that instruction before saving.
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#6571
No description provided.