[GH-ISSUE #8529] [Bug] Ghidra load-image relocation omits its recorded symbol name #6634

Closed
opened 2026-11-01 21:12:50 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @morluto on GitHub (Nov 1, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8529

Before submitting

  • I searched open and closed issues and pull requests for related reports.
  • I removed credentials, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

inspect_native_load_image drops a relocation's symbol name even when the selected Ghidra program records it. The returned relocation row retains its address, Ghidra status, numeric type, values, and original/analysis-memory bytes, but cannot identify the symbol named by that relocation. An analyst can sometimes follow Ghidra's constructed analysis address separately; that is a distinct provider observation, not a runtime binding.

Reproduction

On macOS arm64, compile an unexecuted x86-64 ELF shared object:

extern int audit_external(int);
int (*volatile audit_slot)(int) = audit_external;
__attribute__((noinline, used)) int audit_keep(void) { return 42; }

Run clang -target x86_64-unknown-linux-gnu -fPIC -O0 -c external.c -o external.o and ld.lld -shared external.o -o external.so. LLVM readobj --relocations --dyn-symbols external.so reports R_X86_64_64 audit_external at 0x33e0; audit_external is undefined and audit_slot occupies that location. Addresses depend on the build.

Open the artifact with Ghidra in REA and call inspect_native_load_image({"detail":"complete"}). In this run the observed relocation at rebased 0x1033e0 had status: "APPLIED", type: 1, original_bytes_hex: "0000000000000000", and memory_bytes_hex: "0040100000000000", with no symbol field. Its overall result correctly reports independent ELF verification as unsupported. As a separate direct Ghidra 12.1.4 headless control, import the same artifact into a disposable project and iterate currentProgram.getRelocationTable().getRelocations(); for that row relocation.getSymbolName() returned audit_external. The target SHA-256 636e1d01c5d4638c3a5f72f40ff6755819c1b04ba071be65f82c3b3dbc1fa644 was unchanged; it was not executed.

Expected behavior

Preserve the Ghidra-recorded relocation symbol, including explicit unknown/absence semantics, in complete Evidence and selectable relocation pages. Do not treat the name or Ghidra's analysis-memory address as proof of a resolved runtime binding. Older retained Evidence may not have recorded this field and must not be silently assigned a value.

Impact and scope

A caller investigating a relocation can see that bytes differ but cannot attribute the row to the provider-recorded external symbol from the relocation observation itself. On this fixture, Ghidra address_name(0x104000) reports audit_external, and xrefs(0x104000) reports the slot, but interpreting the bytes as an address and following it is a separate manual, provider-specific handoff. One generated ELF, macOS arm64 host, and Ghidra version were tested; no runtime linker behavior or autonomous-agent decisions were tested.

REA version

7f344af1aa0a78fd4e331dbbc9c30d38e4cfb796 (#8509), with Ghidra provider.

Runtime and platform

Node 24.22.1, macOS arm64, Ghidra 12.1.4, JDK 21.

Target and artifact context

Source-built x86-64 ELF shared object. Static analysis; no target execution.

Interface

MCP.

Earliest failure stage

Provider output parsing/projection.

Relevant output or evidence

Direct Ghidra headless control: address=001033e0 status=APPLIED type=1 symbol=audit_external. REA Ghidra load-image row: address=0x1033e0, status=APPLIED, type=1, bytes as above, no symbol field. Independent LLVM identifies the undefined relocation symbol.

Typed outcome or recovery expected

Retain the provider-recorded symbol as a nullable observation or another explicit representation that also preserves historical unrecorded state. Test complete and paged views, no-symbol and old-Evidence cases, both MCP profiles, offline export/import, and a real provider control; avoid deriving symbol identity from a constructed address or bytes.

Analysis or suspected cause

Source inspection: bridge/ghidra/ReaGhidraBridge.java iterates Relocation and serializes address, status, type, values and bytes but does not call getSymbolName(). javap on the installed Ghidra 12.1.4 SoftwareModeling JAR confirms that method exists; the headless control observed its returned value on this fixture. The method being available does not establish every Ghidra relocation has a known name.

Additional context

Kuna 1.988 documents that import-bound pointers are excluded from its incoming pointer rows; its read command reported the relocation symbol with a null target for the same slot. That is a separate direct-provider observation, not a claim that REA currently supports Kuna byte reads. On this host inspect_binary_layout refused the ELF because its verified pwntools profile is Linux x64 only. Related relocation-backed xref omission: #8510.

@gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8529 ### Before submitting - [x] I searched open and closed issues and pull requests for related reports. - [x] I removed credentials, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior `inspect_native_load_image` drops a relocation's symbol name even when the selected Ghidra program records it. The returned relocation row retains its address, Ghidra status, numeric type, values, and original/analysis-memory bytes, but cannot identify the symbol named by that relocation. An analyst can sometimes follow Ghidra's constructed analysis address separately; that is a distinct provider observation, not a runtime binding. ### Reproduction On macOS arm64, compile an unexecuted x86-64 ELF shared object: ```c extern int audit_external(int); int (*volatile audit_slot)(int) = audit_external; __attribute__((noinline, used)) int audit_keep(void) { return 42; } ``` Run `clang -target x86_64-unknown-linux-gnu -fPIC -O0 -c external.c -o external.o` and `ld.lld -shared external.o -o external.so`. LLVM `readobj --relocations --dyn-symbols external.so` reports `R_X86_64_64 audit_external` at `0x33e0`; `audit_external` is undefined and `audit_slot` occupies that location. Addresses depend on the build. Open the artifact with Ghidra in REA and call `inspect_native_load_image({"detail":"complete"})`. In this run the observed relocation at rebased `0x1033e0` had `status: "APPLIED"`, `type: 1`, `original_bytes_hex: "0000000000000000"`, and `memory_bytes_hex: "0040100000000000"`, with no symbol field. Its overall result correctly reports independent ELF verification as unsupported. As a separate direct Ghidra 12.1.4 headless control, import the same artifact into a disposable project and iterate `currentProgram.getRelocationTable().getRelocations()`; for that row `relocation.getSymbolName()` returned `audit_external`. The target SHA-256 `636e1d01c5d4638c3a5f72f40ff6755819c1b04ba071be65f82c3b3dbc1fa644` was unchanged; it was not executed. ### Expected behavior Preserve the Ghidra-recorded relocation symbol, including explicit unknown/absence semantics, in complete Evidence and selectable relocation pages. Do not treat the name or Ghidra's analysis-memory address as proof of a resolved runtime binding. Older retained Evidence may not have recorded this field and must not be silently assigned a value. ### Impact and scope A caller investigating a relocation can see that bytes differ but cannot attribute the row to the provider-recorded external symbol from the relocation observation itself. On this fixture, Ghidra `address_name(0x104000)` reports `audit_external`, and `xrefs(0x104000)` reports the slot, but interpreting the bytes as an address and following it is a separate manual, provider-specific handoff. One generated ELF, macOS arm64 host, and Ghidra version were tested; no runtime linker behavior or autonomous-agent decisions were tested. ### REA version `7f344af1aa0a78fd4e331dbbc9c30d38e4cfb796` (#8509), with Ghidra provider. ### Runtime and platform Node 24.22.1, macOS arm64, Ghidra 12.1.4, JDK 21. ### Target and artifact context Source-built x86-64 ELF shared object. Static analysis; no target execution. ### Interface MCP. ### Earliest failure stage Provider output parsing/projection. ### Relevant output or evidence Direct Ghidra headless control: `address=001033e0 status=APPLIED type=1 symbol=audit_external`. REA Ghidra load-image row: `address=0x1033e0`, `status=APPLIED`, `type=1`, bytes as above, no symbol field. Independent LLVM identifies the undefined relocation symbol. ### Typed outcome or recovery expected Retain the provider-recorded symbol as a nullable observation or another explicit representation that also preserves historical unrecorded state. Test complete and paged views, no-symbol and old-Evidence cases, both MCP profiles, offline export/import, and a real provider control; avoid deriving symbol identity from a constructed address or bytes. ### Analysis or suspected cause Source inspection: `bridge/ghidra/ReaGhidraBridge.java` iterates `Relocation` and serializes address, status, type, values and bytes but does not call `getSymbolName()`. `javap` on the installed Ghidra 12.1.4 SoftwareModeling JAR confirms that method exists; the headless control observed its returned value on this fixture. The method being available does not establish every Ghidra relocation has a known name. ### Additional context Kuna 1.988 documents that import-bound pointers are excluded from its incoming pointer rows; its `read` command reported the relocation symbol with a null target for the same slot. That is a separate direct-provider observation, not a claim that REA currently supports Kuna byte reads. On this host `inspect_binary_layout` refused the ELF because its verified pwntools profile is Linux x64 only. Related relocation-backed xref omission: #8510. @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
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#6634
No description provided.