[GH-ISSUE #8221] [Design] Connect imported calls to explicitly selected library evidence #6497

Open
opened 2026-11-01 21:11:40 +00:00 by bsakaguchi · 6 comments
Owner

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

Before submitting

  • I searched open and closed issues and pull requests for a related discussion. #8197 covers transfers and thunks within a call trace; #8168 covers Kuna procedure inventory false positives. This asks about the boundary between an importing binary and a separately selected candidate library.
  • 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 can an agent move from a statically observed imported call to analysis of a caller-selected candidate library, while retaining both artifacts' identity and clearly distinguishing a file-level candidate from the library actually loaded at runtime?

Context and evidence

I built an unexecuted arm64 Mach-O executable importing _audit_transform from an owned @rpath/libAudit.dylib; its request function calls the import stub and adds one. The executable and library SHA-256 values were unchanged throughout the REA sessions.

  • inspect_macho on the executable reported the _audit_transform import, source: libAudit, and @rpath/libAudit.dylib dependency. The import inventory explicitly said it may omit metadata and reported a null import address. This is format Evidence, not a resolved filesystem path or proof of runtime binding.
  • Real REA/Ghidra 12.1.4 MCP identified the call from _audit_request to local address 0x1000004b4; procedure_references marked that local function a thunk to EXTERNAL:0x1. procedure_info on that external address identified @rpath/libAudit.dylib::_audit_transform and an external function with no body; its pseudocode was null. trace_call_path reached the local stub but not the external address, consistent with its call-only scope.
  • REA/Kuna 1.986 reported a call to the same local stub, but its inventory listed audit_transform twice, at the stub and the GOT address 0x100004000. Name lookup rejected the ambiguity and asked for an exact address. Stub pseudocode described a jump-as-call; requesting the GOT entry's pseudocode returned null. Kuna procedure_info and typed procedure_references were unavailable. This one fixture does not establish general provider accuracy.
  • I then explicitly opened the owned library as a separate target. Its inspect_macho export inventory contained _audit_transform at 0x2d8, and both providers decompiled that library function. The library had a different digest and address context from the importing executable. The source fixture establishes the intended association here; static equal names alone do not establish a runtime binding.

Expected interaction with targets

Read caller-selected binaries and existing static Evidence. Do not launch the target, search the filesystem implicitly, change the binary or load libraries into a process.

Boundary details (optional)

Distinguish call-site address, local stub, GOT/indirection, provider external symbol, declared dependency, candidate file, export, and actual runtime binding. Preserve both digests, architecture/slice, coordinate spaces, original symbol spelling, library names and relevant source Evidence. Rpaths, install names, weak imports, re-exports, interposition, symbol versions, missing or incomplete inventories, multiple matching candidates and changed files can make a match ambiguous or runtime resolution unknown.

Options and tradeoffs

Explore a bounded workflow that joins retained import/dependency and export facts for explicitly selected files, reports exact observed facts and candidate associations with uncertainty, and offers a follow-up function-analysis input when a provider can identify the export. Consider whether the existing single-target session and Evidence export/import are sufficient for the workflow before introducing a new tool. Keep call-only graph behavior and candidate matching separate; do not automatically follow arbitrary filesystem paths or infer runtime binding.

Verification available so far

I have a prototype or observed results.

Success criteria and open questions

Exercise duplicate names, multiple candidate libraries, missing and weak imports, re-exports, architecture/slice selection, load-path ambiguity, changed files, and provider-specific stub/alias cases. Verify identity and Evidence survive CLI/MCP session transitions and that unknown runtime resolution is not presented as fact. The test above is one Mach-O pair on macOS arm64; no PE, ELF, dynamic-loader execution or autonomous-agent success was tested.

References

Related: #8197, #8168 and #8183. REA 53a4ab78451a0654e9c3beb3d43a5e371a288fcc; macOS arm64, Ghidra 12.1.4, Kuna 1.986.

ELF visibility in candidate Evidence

Two explicitly selected, source-built x86-64 ELF shared objects export audit_target at 0x1340 with identical name, binding, type and version, but one declares default visibility and the other protected. LLVM readobj confirms R_X86_64_64 audit_target for the former pointer and R_X86_64_RELATIVE for the latter. On #8509, REA's portable inspect_native_exports returned identical function rows because it did not retain visibility (#8517). Draft #8519 retains default/protected; its real compact/full MCP controls can select the field from each retained export and recover it after offline bundle import. On this macOS host, inspect_binary_layout refused its Linux-x64-only provider, so it was not an available relocation-evidence fallback here.

This is useful candidate metadata, not an automatic join or proof of what a loader will bind. Default-visible globals can be preempted under the ELF gABI; runtime loader state remains unknown. Both targets remained byte-identical and were never executed. One controlled pair, not general platform or interposition coverage.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Default-visible call through PLT versus protected local call

Two source-built x86-64 ELF shared objects differ only in audit_target visibility. The default-visible object has an R_X86_64_JUMP_SLOT audit_target relocation; the protected object has no dynamic relocation for this call. Direct Kuna 1.988 prints the same reconstructed audit_target(a0) + 2 expression for both. On the default object, both real REA/Kuna and REA/Ghidra refused audit_target by name as ambiguous between the local entry and a PLT stub; exact-address recovery traced the caller to the stub as reached, and to the implementation as not_reached in the call-only traversal. Ghidra classified the stub as a thunk whose static target is the local definition; Kuna's stub pseudocode showed an indirect slot jump. On the protected object both providers' call-only traces reached the local entry directly. Draft #8519 independently returns the default/protected export visibility. These are provider static observations and traversal outcomes: the default-visible relocation may be interposed and no runtime selection is established.

This control makes the task-level distinction concrete: identical displayed names and decompiled expressions do not by themselves identify the declared relocation or a runtime-selected implementation. The two target SHA-256 values (741f17c72cea92c0316549c9733cdf77c528d890fde6231bdf4cc8ba325aa630, 64ceb8aa79339deb52cd010fb319f8a417b4dba79670765da1298fe65c35b273) remained unchanged; neither binary was run. One host, two constructed fixtures; not a general reachability or provider-accuracy claim.

Originally created by @morluto on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8221 ### Before submitting - [x] I searched open and closed issues and pull requests for a related discussion. #8197 covers transfers and thunks within a call trace; #8168 covers Kuna procedure inventory false positives. This asks about the boundary between an importing binary and a separately selected candidate library. - [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 can an agent move from a statically observed imported call to analysis of a caller-selected candidate library, while retaining both artifacts' identity and clearly distinguishing a file-level candidate from the library actually loaded at runtime? ### Context and evidence I built an unexecuted arm64 Mach-O executable importing `_audit_transform` from an owned `@rpath/libAudit.dylib`; its request function calls the import stub and adds one. The executable and library SHA-256 values were unchanged throughout the REA sessions. - `inspect_macho` on the executable reported the `_audit_transform` import, `source: libAudit`, and `@rpath/libAudit.dylib` dependency. The import inventory explicitly said it may omit metadata and reported a null import address. This is format Evidence, not a resolved filesystem path or proof of runtime binding. - Real REA/Ghidra 12.1.4 MCP identified the call from `_audit_request` to local address `0x1000004b4`; `procedure_references` marked that local function a thunk to `EXTERNAL:0x1`. `procedure_info` on that external address identified `@rpath/libAudit.dylib::_audit_transform` and an external function with no body; its pseudocode was null. `trace_call_path` reached the local stub but not the external address, consistent with its call-only scope. - REA/Kuna 1.986 reported a call to the same local stub, but its inventory listed `audit_transform` twice, at the stub and the GOT address `0x100004000`. Name lookup rejected the ambiguity and asked for an exact address. Stub pseudocode described a `jump-as-call`; requesting the GOT entry's pseudocode returned null. Kuna `procedure_info` and typed `procedure_references` were unavailable. This one fixture does not establish general provider accuracy. - I then explicitly opened the owned library as a separate target. Its `inspect_macho` export inventory contained `_audit_transform` at `0x2d8`, and both providers decompiled that library function. The library had a different digest and address context from the importing executable. The source fixture establishes the intended association here; static equal names alone do not establish a runtime binding. ### Expected interaction with targets Read caller-selected binaries and existing static Evidence. Do not launch the target, search the filesystem implicitly, change the binary or load libraries into a process. ### Boundary details (optional) Distinguish call-site address, local stub, GOT/indirection, provider external symbol, declared dependency, candidate file, export, and actual runtime binding. Preserve both digests, architecture/slice, coordinate spaces, original symbol spelling, library names and relevant source Evidence. Rpaths, install names, weak imports, re-exports, interposition, symbol versions, missing or incomplete inventories, multiple matching candidates and changed files can make a match ambiguous or runtime resolution unknown. ### Options and tradeoffs Explore a bounded workflow that joins retained import/dependency and export facts for *explicitly selected* files, reports exact observed facts and candidate associations with uncertainty, and offers a follow-up function-analysis input when a provider can identify the export. Consider whether the existing single-target session and Evidence export/import are sufficient for the workflow before introducing a new tool. Keep call-only graph behavior and candidate matching separate; do not automatically follow arbitrary filesystem paths or infer runtime binding. ### Verification available so far I have a prototype or observed results. ### Success criteria and open questions Exercise duplicate names, multiple candidate libraries, missing and weak imports, re-exports, architecture/slice selection, load-path ambiguity, changed files, and provider-specific stub/alias cases. Verify identity and Evidence survive CLI/MCP session transitions and that unknown runtime resolution is not presented as fact. The test above is one Mach-O pair on macOS arm64; no PE, ELF, dynamic-loader execution or autonomous-agent success was tested. ### References Related: #8197, #8168 and #8183. REA `53a4ab78451a0654e9c3beb3d43a5e371a288fcc`; macOS arm64, Ghidra 12.1.4, Kuna 1.986. ### ELF visibility in candidate Evidence Two explicitly selected, source-built x86-64 ELF shared objects export `audit_target` at `0x1340` with identical name, binding, type and version, but one declares default visibility and the other protected. LLVM readobj confirms `R_X86_64_64 audit_target` for the former pointer and `R_X86_64_RELATIVE` for the latter. On #8509, REA's portable `inspect_native_exports` returned identical function rows because it did not retain visibility (#8517). Draft #8519 retains `default`/`protected`; its real compact/full MCP controls can select the field from each retained export and recover it after offline bundle import. On this macOS host, `inspect_binary_layout` refused its Linux-x64-only provider, so it was not an available relocation-evidence fallback here. This is useful candidate metadata, not an automatic join or proof of what a loader will bind. Default-visible globals can be preempted under the [ELF gABI](https://gabi.xinuos.com/elf.pdf); runtime loader state remains unknown. Both targets remained byte-identical and were never executed. One controlled pair, not general platform or interposition coverage. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 ### Default-visible call through PLT versus protected local call Two source-built x86-64 ELF shared objects differ only in `audit_target` visibility. The default-visible object has an `R_X86_64_JUMP_SLOT audit_target` relocation; the protected object has no dynamic relocation for this call. Direct Kuna 1.988 prints the same reconstructed `audit_target(a0) + 2` expression for both. On the default object, both real REA/Kuna and REA/Ghidra refused `audit_target` by name as ambiguous between the local entry and a PLT stub; exact-address recovery traced the caller to the stub as `reached`, and to the implementation as `not_reached` in the call-only traversal. Ghidra classified the stub as a thunk whose static target is the local definition; Kuna's stub pseudocode showed an indirect slot jump. On the protected object both providers' call-only traces reached the local entry directly. Draft #8519 independently returns the default/protected export visibility. These are provider static observations and traversal outcomes: the default-visible relocation may be interposed and no runtime selection is established. This control makes the task-level distinction concrete: identical displayed names and decompiled expressions do not by themselves identify the declared relocation or a runtime-selected implementation. The two target SHA-256 values (`741f17c72cea92c0316549c9733cdf77c528d890fde6231bdf4cc8ba325aa630`, `64ceb8aa79339deb52cd010fb319f8a417b4dba79670765da1298fe65c35b273`) remained unchanged; neither binary was run. One host, two constructed fixtures; not a general reachability or provider-accuracy claim.
Author
Owner

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

A follow-up tested multiple caller-selected candidates and existing Evidence retention. I built a second arm64 dylib with the same declared install name @rpath/libAudit.dylib and the same _audit_transform export at the same displayed address, but a different SHA-256 and a different implementation. The original executable, original dylib and alternative dylib were not executed and all three digests stayed unchanged. The original fixture links against the first library; this test does not establish that the alternative would be selected by the dynamic loader.

Using real REA/Ghidra MCP, I opened the three artifacts sequentially, captured inspect_macho summary and analyze_function Evidence for each, exported a separate bundle and closed each session. In a fresh server I imported all three bundles. A filtered get_evidence_bundle summary found all three inspection records with distinct artifact paths and digests; inspect_analysis_view paged the executable's import and dependency rows, both libraries' export rows, and each library function's pseudocode without starting a provider. Both export pages contained the same name and address, while the retained pseudocode pages differed. Import/export inventory limitations remained explicit and non-exhaustive.

This demonstrates a useful existing building block: an agent can preserve and inspect evidence for multiple explicit targets across session changes. It also demonstrates that symbol name, install-name text and displayed address alone cannot select a unique candidate. The scripted caller retained the Evidence IDs and chose which pages to inspect; no automatic association, runtime binding, cross-platform behavior or autonomous agent success was established. Any candidate workflow should retain alternatives rather than silently picking a first match.

<!-- gh-comment-id:6534431785 --> @morluto commented on GitHub (Oct 30, 2026): A follow-up tested multiple caller-selected candidates and existing Evidence retention. I built a second arm64 dylib with the same declared install name `@rpath/libAudit.dylib` and the same `_audit_transform` export at the same displayed address, but a different SHA-256 and a different implementation. The original executable, original dylib and alternative dylib were not executed and all three digests stayed unchanged. The original fixture links against the first library; this test does not establish that the alternative would be selected by the dynamic loader. Using real REA/Ghidra MCP, I opened the three artifacts sequentially, captured `inspect_macho` summary and `analyze_function` Evidence for each, exported a separate bundle and closed each session. In a fresh server I imported all three bundles. A filtered `get_evidence_bundle` summary found all three inspection records with distinct artifact paths and digests; `inspect_analysis_view` paged the executable's import and dependency rows, both libraries' export rows, and each library function's pseudocode without starting a provider. Both export pages contained the same name and address, while the retained pseudocode pages differed. Import/export inventory limitations remained explicit and non-exhaustive. This demonstrates a useful existing building block: an agent can preserve and inspect evidence for multiple explicit targets across session changes. It also demonstrates that symbol name, install-name text and displayed address alone cannot select a unique candidate. The scripted caller retained the Evidence IDs and chose which pages to inspect; no automatic association, runtime binding, cross-platform behavior or autonomous agent success was established. Any candidate workflow should retain alternatives rather than silently picking a first match.
Author
Owner

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

An independent, unexecuted x86-64 PE control shows a different import shape and exercises a forwarded-export case. REA/Kuna still refuses PE at its documented admission boundary; direct Kuna 1.986 listed the caller and reported its indirect call through IAT address 0x140002038 to audit_transform.

Real REA/Ghidra 12.1.4 on the same PE returned a computed call from the caller directly to external AUDIT.DLL::audit_transform, alongside a separate data-read reference at the same instruction to 0x140002038. trace_call_path reached the external address. inspect_pe_imports identified audit.dll, the named import and IAT RVA 0x2038; inspect_native_exports on the explicitly selected DLL identified its named ordinal-1 export. Opening that DLL separately returned the function's pseudocode. These are static observations, not evidence of the DLL selected or called at runtime.

I also built a distinct audit.dll whose export forwards audit_transform to audit_real.audit_transform, plus a separately selected audit_real.dll with a body. inspect_native_exports correctly represented the first row with address: null and the forwarder string, and the second with an actual export address; it does not resolve the other file automatically. Ghidra exposed a local thunk at 0x180003000 and an external symbol; the name was ambiguous until an exact entry was chosen. On this fixture the thunk address had no initialized file-backed mapping, no listed instruction, and pseudocode warned about bad instruction data. Direct Kuna's function inventory for the forwarder was empty; its separate real DLL listed the exported function. These observations argue against treating every matching export or Ghidra entry as a file-backed implementation. All tested target digests were unchanged; no Windows execution, ordinal-only import, delay import or loader resolution was tested.

<!-- gh-comment-id:6534506462 --> @morluto commented on GitHub (Oct 30, 2026): An independent, unexecuted x86-64 PE control shows a different import shape and exercises a forwarded-export case. REA/Kuna still refuses PE at its documented admission boundary; direct Kuna 1.986 listed the caller and reported its indirect call through IAT address `0x140002038` to `audit_transform`. Real REA/Ghidra 12.1.4 on the same PE returned a computed call from the caller directly to external `AUDIT.DLL::audit_transform`, alongside a separate data-read reference at the same instruction to `0x140002038`. `trace_call_path` reached the external address. `inspect_pe_imports` identified `audit.dll`, the named import and IAT RVA `0x2038`; `inspect_native_exports` on the explicitly selected DLL identified its named ordinal-1 export. Opening that DLL separately returned the function's pseudocode. These are static observations, not evidence of the DLL selected or called at runtime. I also built a distinct `audit.dll` whose export forwards `audit_transform` to `audit_real.audit_transform`, plus a separately selected `audit_real.dll` with a body. `inspect_native_exports` correctly represented the first row with `address: null` and the forwarder string, and the second with an actual export address; it does not resolve the other file automatically. Ghidra exposed a local thunk at `0x180003000` and an external symbol; the name was ambiguous until an exact entry was chosen. On this fixture the thunk address had no initialized file-backed mapping, no listed instruction, and pseudocode warned about bad instruction data. Direct Kuna's function inventory for the forwarder was empty; its separate real DLL listed the exported function. These observations argue against treating every matching export or Ghidra entry as a file-backed implementation. All tested target digests were unchanged; no Windows execution, ordinal-only import, delay import or loader resolution was tested.
Author
Owner

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

A self-built, unexecuted x86-64 ELF control illustrates the symbol-version boundary. The PIE imports audit_transform@AUDIT_1 from libaudit.so, as observed independently with llvm-readelf. I built two caller-selected libraries with the same SONAME, export name, displayed address and identical function instructions, but different digests and version definitions AUDIT_1 and AUDIT_2. The source and linker inputs establish which one the executable was linked against; no dynamic loader was run.

REA inspect_native_exports on each library preserved the respective version name and reported complete coverage on this fixture. Both REA/Ghidra 12.1.4 and REA/Kuna 1.986 decompiled the same function text from both libraries, and both found the importing function's call to a local PLT entry. Ghidra's inventory classified two successive thunks leading to an external entry; its image coordinates differed from Kuna's (for the first PLT entry 0x101360 versus 0x1360). The inspected provider inventory and pseudocode did not expose the required AUDIT_1 version in this run. The versioned import observation above comes from llvm-readelf, not from those REA provider calls.

The existing inspect_binary_layout operation returned its documented Linux-x64-host capability refusal on this macOS host, so this probe does not establish whether its Linux output exposes the needed import version. This is one fixture, not a complete version-resolution rule or a claim about runtime binding. It demonstrates that same name, SONAME, address and even identical pseudocode are insufficient to discard version identity; a cross-file candidate workflow should preserve both required and provided version facts when actually observed, or retain unknown. All three file SHA-256 values stayed unchanged.

<!-- gh-comment-id:6534530629 --> @morluto commented on GitHub (Oct 30, 2026): A self-built, unexecuted x86-64 ELF control illustrates the symbol-version boundary. The PIE imports `audit_transform@AUDIT_1` from `libaudit.so`, as observed independently with `llvm-readelf`. I built two caller-selected libraries with the same SONAME, export name, displayed address and identical function instructions, but different digests and version definitions `AUDIT_1` and `AUDIT_2`. The source and linker inputs establish which one the executable was linked against; no dynamic loader was run. REA `inspect_native_exports` on each library preserved the respective version name and reported complete coverage on this fixture. Both REA/Ghidra 12.1.4 and REA/Kuna 1.986 decompiled the same function text from both libraries, and both found the importing function's call to a local PLT entry. Ghidra's inventory classified two successive thunks leading to an external entry; its image coordinates differed from Kuna's (for the first PLT entry `0x101360` versus `0x1360`). The inspected provider inventory and pseudocode did not expose the required `AUDIT_1` version in this run. The versioned import observation above comes from `llvm-readelf`, not from those REA provider calls. The existing `inspect_binary_layout` operation returned its documented Linux-x64-host capability refusal on this macOS host, so this probe does not establish whether its Linux output exposes the needed import version. This is one fixture, not a complete version-resolution rule or a claim about runtime binding. It demonstrates that same name, SONAME, address and even identical pseudocode are insufficient to discard version identity; a cross-file candidate workflow should preserve both required and provided version facts when actually observed, or retain unknown. All three file SHA-256 values stayed unchanged.
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:6538801253 --> @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.
Author
Owner

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

The existing trace_dylib_resolution workflow is an important building block that the earlier report did not exercise. On main e6d061897, I put the same unexecuted importing Mach-O into three disposable directories. Its LC_RPATH is @loader_path and its required load is @rpath/libAudit.dylib. Directory one held the original library; directory two held the previously tested different-digest library with the same install name and export; directory three had no library.

Real CLI and MCP results agreed on the normalized trace for each directory:

  • In the first two roots, the trace resolved the relative libAudit.dylib candidate, reported its distinct image SHA-256 and matching install name, and retained the same executable digest.
  • In the missing root, it reported the candidate absent, the required load unresolved and an associated finding. System paths outside the selected root remained undetermined.
  • In the first MCP session, a real Ghidra procedure_references call separately identified the call site and local thunk to the external symbol. The load-path trace and the call/reference Evidence were separate records; I did not observe an automatic symbol-to-candidate join.

This narrows the proposal: for Mach-O, agents can already inspect a bounded static load-path candidate and digest rather than relying only on equal names. The candidate can still change with the selected filesystem root, and this trace does not prove the library actually loaded or the call's runtime binding. An explicit cross-Evidence handoff should reuse these observations, preserve unresolved/outside-root cases and selected artifact identity, and avoid duplicating the existing resolver. All copied files' digests were unchanged; no target was run. This is one Mach-O setup, not PE/ELF or every dyld configuration.

<!-- gh-comment-id:6541000467 --> @morluto commented on GitHub (Oct 31, 2026): The existing `trace_dylib_resolution` workflow is an important building block that the earlier report did not exercise. On main `e6d061897`, I put the **same unexecuted importing Mach-O** into three disposable directories. Its `LC_RPATH` is `@loader_path` and its required load is `@rpath/libAudit.dylib`. Directory one held the original library; directory two held the previously tested different-digest library with the same install name and export; directory three had no library. Real CLI and MCP results agreed on the normalized trace for each directory: * In the first two roots, the trace resolved the relative `libAudit.dylib` candidate, reported its distinct image SHA-256 and matching install name, and retained the same executable digest. * In the missing root, it reported the candidate absent, the required load unresolved and an associated finding. System paths outside the selected root remained undetermined. * In the first MCP session, a real Ghidra `procedure_references` call separately identified the call site and local thunk to the external symbol. The load-path trace and the call/reference Evidence were separate records; I did not observe an automatic symbol-to-candidate join. This narrows the proposal: for Mach-O, agents can already inspect a bounded static load-path candidate and digest rather than relying only on equal names. The candidate can still change with the selected filesystem root, and this trace does not prove the library actually loaded or the call's runtime binding. An explicit cross-Evidence handoff should reuse these observations, preserve unresolved/outside-root cases and selected artifact identity, and avoid duplicating the existing resolver. All copied files' digests were unchanged; no target was run. This is one Mach-O setup, not PE/ELF or every dyld configuration.
Author
Owner

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

Follow-up on the versioned ELF control: I checked existing REA/Ghidra evidence before proposing another format surface. search_strings found AUDIT_1, and the retained inspect_native_load_image mappings included .dynsym, .gnu.version, .gnu.version_r, and .dynstr; list_names identified __DT_VERSYM, __DT_VERNEED, and the unversioned external audit_transform. Its relocation page returned two rows but did not name the required version. These observations locate relevant material, but in the calls tested do not connect the version string to the imported symbol or select either library. llvm-readelf independently confirmed that the import required AUDIT_1 in the fixture.

This is one source-built x86-64 ELF on macOS arm64 with real Ghidra 12.1.4 through MCP, not a proof that other available REA workflows cannot recover the association. It supports evaluating existing format-aware parsing or another explicit evidence handoff before adding a provider-specific wrapper. Neither names nor a matching version string establish runtime binding; the target was not executed and its digest was unchanged. A separate coverage inconsistency observed in the load-image view is tracked in #8276.

<!-- gh-comment-id:6541041175 --> @morluto commented on GitHub (Oct 31, 2026): Follow-up on the versioned ELF control: I checked existing REA/Ghidra evidence before proposing another format surface. `search_strings` found `AUDIT_1`, and the retained `inspect_native_load_image` mappings included `.dynsym`, `.gnu.version`, `.gnu.version_r`, and `.dynstr`; `list_names` identified `__DT_VERSYM`, `__DT_VERNEED`, and the unversioned external `audit_transform`. Its relocation page returned two rows but did not name the required version. These observations locate relevant material, but in the calls tested do not connect the version string to the imported symbol or select either library. `llvm-readelf` independently confirmed that the import required `AUDIT_1` in the fixture. This is one source-built x86-64 ELF on macOS arm64 with real Ghidra 12.1.4 through MCP, not a proof that other available REA workflows cannot recover the association. It supports evaluating existing format-aware parsing or another explicit evidence handoff before adding a provider-specific wrapper. Neither names nor a matching version string establish runtime binding; the target was not executed and its digest was unchanged. A separate coverage inconsistency observed in the load-image view is tracked in #8276.
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#6497
No description provided.