[GH-ISSUE #8241] [Design] Resolve a byte-search hit to its containing instruction #6509

Open
opened 2026-11-01 21:11:46 +00:00 by bsakaguchi · 3 comments
Owner

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

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

When a byte search finds bytes inside a listed machine instruction, should the existing instruction-inspection workflow optionally return the containing instruction's exact start and extent, without silently changing the caller's selected address?

Context and evidence

In an owned x86-64 ELF, a function contains mov eax, 0x9e3779b9 at 0x201164, encoded as b8 b9 79 37 9e. search_bytes for the caller-supplied little-endian four-byte pattern returned 0x201165 in .text, associated with audit_constant at 0x201160; it also found the same bytes in a distinct data object. The fixture simply returns the constant and contains no TEA implementation. A table match or immediate value is not evidence of an algorithm or runtime use.

In real REA/Ghidra MCP, inspect_native_instruction({"address":"0x201165"}) returned not-instruction-boundary, the containing procedure address, and null instruction bytes/length; it did not return the containing instruction's start. read_function_instructions for the reported procedure returned a full text listing including 0x201164: MOV EAX, 0x9e3779b9. A follow-up exact instruction query at 0x201164 returned the five bytes, length and typed immediate operand, establishing that the search hit lies within that instruction. xrefs on the immediate-byte address returned empty, while a separate xref and typed outgoing reference identified an instruction reading the data object; these are different relations and an empty xref is not proof of no use.

Direct Kuna 1.986 crypto --algorithm TEA labeled the immediate as a TEA/XTEA-related candidate and identified its enclosing function when xref enrichment was enabled; --no-xrefs left the functions list empty. A one-byte-changed ELF control had no matching TEA candidate. REA/Kuna returned typed capability unavailability for search_bytes, containing-procedure and instruction inspection in this fixture. The binaries were not executed and their digests stayed unchanged. This is one architecture, provider combination and immediate—not a model-selection study or general crypto accuracy claim.

Expected interaction with targets

Read selected static provider analysis and local bytes. No target execution or mutation is proposed.

Boundary details (optional)

Preserve the caller's exact matched byte address and the provider-observed containing instruction start/end, address space, bytes, mode and provenance separately. A signature can span multiple instructions or data; overlapping/alternative instruction contexts and unknown mode must not be collapsed into a unique finding. Do not decode unlisted bytes implicitly or make runtime/algorithm claims. Continue to distinguish not-instruction-boundary, data, not-in-listing and outside memory.

Options and tradeoffs

Compare documenting the existing containing-procedure → full instruction list → exact instruction query, adding a small containing-instruction identity to the existing exact inspection result, or an explicit bounded address-context selection. Reuse current contracts and retained Evidence where possible; avoid a new provider-only wrapper. Full function listings may be unnecessarily large for a local question, but no token or performance measurement was made here.

Verification available so far

I have a prototype or observed results

Success criteria and open questions

Test instruction start/interior/end, patterns spanning instructions, defined data, unlisted/uninitialized memory, unmapped and non-default address spaces, instruction mode contexts and partial bodies; preserve unknowns for providers without trustworthy containment. Verify real CLI/MCP and SDK schemas and bound any additional data. No architecture-wide, Hopper, Windows or autonomous-agent claims are established.

References

Related #8194 (algorithm candidate evidence), #8240 (containing typed data), #7490 (unlisted bytes must not be called undecodable). At revision 53a4ab78451a0654e9c3beb3d43a5e371a288fcc, Ghidra inspection already tests whether an instruction contains the address to classify the non-boundary result; exposing a verified extent would need its own contract.

Additional AArch64 instruction-boundary control

On REA 9ebbe67e05af08b567e215340da993c08dae378f with real Ghidra 12.1.4 and the full public MCP schema profile, a self-built AArch64 Mach-O exposed a four-byte sub at 0x100000328 (ff4300d1) and the next instruction at 0x10000032c. Inspection of each interior byte 0x100000329 through 0x10000032b returned not-instruction-boundary, the containing procedure at 0x100000328, and null instruction bytes and length. The procedure happened to begin at the instruction in this fixture, but the current result does not identify it as the containing instruction. read_function_instructions showed the two starts; an exact query at each returned its own decoded instruction. This is a boundary control, not a separate byte-search reproduction or proof for other architectures or address spaces. The unexecuted target's SHA-256 ae0f2a349b22332113ab60ab4c78024eb18153c76bdeefb01c4b1d89a26c0003 was unchanged.

Overlay without a containing procedure

A separate disposable Ghidra 12.1.4 headless project added an initialized executable AArch64 overlay at the same offsets as the fixture's original code, wrote ff4300d1 e00f00b9, and disassembled it. Direct Ghidra listing getInstructionContaining at overlay offset 0x100000329 reported the four-byte instruction at REA_CONTAINING_OVERLAY::100000328; getInstructionAt at the interior byte returned none. This script changed only the disposable project, not the target executable.

REA 9ebbe67e05af08b567e215340da993c08dae378f then opened that selected project through its existing-project workflow and queried the full-profile MCP tool. inspect_native_instruction at REA_CONTAINING_OVERLAY:0x100000329 and :0x10000032b reported not-instruction-boundary with procedure: null, while querying REA_CONTAINING_OVERLAY:0x100000328 returned decoded, bytes ff4300d1, length 4. The corresponding default-space interior query returned its separate default-space procedure. The executable SHA-256 remained ae0f2a349b22332113ab60ab4c78024eb18153c76bdeefb01c4b1d89a26c0003.

In this case the containing-procedure → function-listing workaround cannot locate the overlay instruction, because no containing function was reported. This does not establish that every overlay or non-default address space behaves the same. Any containing identity needs to keep the exact space-qualified query and observed instruction start distinct; it must not imply a function, alternative decode, or runtime execution.

Originally created by @morluto on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8241 ### 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 When a byte search finds bytes inside a listed machine instruction, should the existing instruction-inspection workflow optionally return the containing instruction's exact start and extent, without silently changing the caller's selected address? ### Context and evidence In an owned x86-64 ELF, a function contains `mov eax, 0x9e3779b9` at `0x201164`, encoded as `b8 b9 79 37 9e`. `search_bytes` for the caller-supplied little-endian four-byte pattern returned `0x201165` in `.text`, associated with `audit_constant` at `0x201160`; it also found the same bytes in a distinct data object. The fixture simply returns the constant and contains no TEA implementation. A table match or immediate value is not evidence of an algorithm or runtime use. In real REA/Ghidra MCP, `inspect_native_instruction({"address":"0x201165"})` returned `not-instruction-boundary`, the containing procedure address, and null instruction bytes/length; it did not return the containing instruction's start. `read_function_instructions` for the reported procedure returned a full text listing including `0x201164: MOV EAX, 0x9e3779b9`. A follow-up exact instruction query at `0x201164` returned the five bytes, length and typed immediate operand, establishing that the search hit lies within that instruction. `xrefs` on the immediate-byte address returned empty, while a separate xref and typed outgoing reference identified an instruction reading the data object; these are different relations and an empty xref is not proof of no use. Direct Kuna 1.986 `crypto --algorithm TEA` labeled the immediate as a TEA/XTEA-related candidate and identified its enclosing function when xref enrichment was enabled; `--no-xrefs` left the functions list empty. A one-byte-changed ELF control had no matching TEA candidate. REA/Kuna returned typed capability unavailability for `search_bytes`, containing-procedure and instruction inspection in this fixture. The binaries were not executed and their digests stayed unchanged. This is one architecture, provider combination and immediate—not a model-selection study or general crypto accuracy claim. ### Expected interaction with targets Read selected static provider analysis and local bytes. No target execution or mutation is proposed. ### Boundary details (optional) Preserve the caller's exact matched byte address and the provider-observed containing instruction start/end, address space, bytes, mode and provenance separately. A signature can span multiple instructions or data; overlapping/alternative instruction contexts and unknown mode must not be collapsed into a unique finding. Do not decode unlisted bytes implicitly or make runtime/algorithm claims. Continue to distinguish `not-instruction-boundary`, `data`, `not-in-listing` and outside memory. ### Options and tradeoffs Compare documenting the existing containing-procedure → full instruction list → exact instruction query, adding a small containing-instruction identity to the existing exact inspection result, or an explicit bounded address-context selection. Reuse current contracts and retained Evidence where possible; avoid a new provider-only wrapper. Full function listings may be unnecessarily large for a local question, but no token or performance measurement was made here. ### Verification available so far I have a prototype or observed results ### Success criteria and open questions Test instruction start/interior/end, patterns spanning instructions, defined data, unlisted/uninitialized memory, unmapped and non-default address spaces, instruction mode contexts and partial bodies; preserve unknowns for providers without trustworthy containment. Verify real CLI/MCP and SDK schemas and bound any additional data. No architecture-wide, Hopper, Windows or autonomous-agent claims are established. ### References Related #8194 (algorithm candidate evidence), #8240 (containing typed data), #7490 (unlisted bytes must not be called undecodable). At revision `53a4ab78451a0654e9c3beb3d43a5e371a288fcc`, [Ghidra inspection](https://github.com/morluto/rea/blob/53a4ab78451a0654e9c3beb3d43a5e371a288fcc/bridge/ghidra/ReaGhidraBridge.java#L1280-L1320) already tests whether an instruction contains the address to classify the non-boundary result; exposing a verified extent would need its own contract. ### Additional AArch64 instruction-boundary control On REA `9ebbe67e05af08b567e215340da993c08dae378f` with real Ghidra 12.1.4 and the full public MCP schema profile, a self-built AArch64 Mach-O exposed a four-byte `sub` at `0x100000328` (`ff4300d1`) and the next instruction at `0x10000032c`. Inspection of each interior byte `0x100000329` through `0x10000032b` returned `not-instruction-boundary`, the containing procedure at `0x100000328`, and null instruction bytes and length. The procedure happened to begin at the instruction in this fixture, but the current result does not identify it as the containing instruction. `read_function_instructions` showed the two starts; an exact query at each returned its own decoded instruction. This is a boundary control, not a separate byte-search reproduction or proof for other architectures or address spaces. The unexecuted target's SHA-256 `ae0f2a349b22332113ab60ab4c78024eb18153c76bdeefb01c4b1d89a26c0003` was unchanged. ### Overlay without a containing procedure A separate disposable Ghidra 12.1.4 headless project added an initialized executable AArch64 overlay at the same offsets as the fixture's original code, wrote `ff4300d1 e00f00b9`, and disassembled it. Direct Ghidra listing `getInstructionContaining` at overlay offset `0x100000329` reported the four-byte instruction at `REA_CONTAINING_OVERLAY::100000328`; `getInstructionAt` at the interior byte returned none. This script changed only the disposable project, not the target executable. REA `9ebbe67e05af08b567e215340da993c08dae378f` then opened that selected project through its existing-project workflow and queried the full-profile MCP tool. `inspect_native_instruction` at `REA_CONTAINING_OVERLAY:0x100000329` and `:0x10000032b` reported `not-instruction-boundary` with `procedure: null`, while querying `REA_CONTAINING_OVERLAY:0x100000328` returned `decoded`, bytes `ff4300d1`, length 4. The corresponding default-space interior query returned its separate default-space procedure. The executable SHA-256 remained `ae0f2a349b22332113ab60ab4c78024eb18153c76bdeefb01c4b1d89a26c0003`. In this case the containing-procedure → function-listing workaround cannot locate the overlay instruction, because no containing function was reported. This does not establish that every overlay or non-default address space behaves the same. Any containing identity needs to keep the exact space-qualified query and observed instruction start distinct; it must not imply a function, alternative decode, or runtime execution.
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:6538807879 --> @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):

Real paged search and cursor controls

On REA b43c329df779708e43ae297f498a844e45d9c923 with Ghidra 12.1.4, the source-owned ELF above was searched through real stdio MCP with pattern: "B9 79 37 9E", limit: 1. The first page returned the immediate-byte hit 0x201165 in audit_constant, complete: false, and a cursor. Resuming with the semantically equivalent lowercase pattern and explicit all-ones mask returned the separate .data hit 0x20219c and complete: true.

Reusing that cursor with a different byte pattern failed with a cursor/query mismatch. After closing the positive fixture and opening the independently built negative fixture, reusing it with the original pattern also failed with the same mismatch. REA/Kuna 1.986 reported capability_unavailable for the byte-search request. These are one real host/provider run, not a general cursor-security or architecture claim. Both target hashes remained unchanged and neither target was executed.

This preserves the distinction in the original report: the first result identifies an instruction-interior byte plus its containing procedure, while the second is data; a match does not establish algorithm semantics or runtime use.

<!-- gh-comment-id:6541759546 --> @morluto commented on GitHub (Oct 31, 2026): ### Real paged search and cursor controls On REA `b43c329df779708e43ae297f498a844e45d9c923` with Ghidra 12.1.4, the source-owned ELF above was searched through real stdio MCP with `pattern: "B9 79 37 9E", limit: 1`. The first page returned the immediate-byte hit `0x201165` in `audit_constant`, `complete: false`, and a cursor. Resuming with the semantically equivalent lowercase pattern and explicit all-ones mask returned the separate `.data` hit `0x20219c` and `complete: true`. Reusing that cursor with a different byte pattern failed with a cursor/query mismatch. After closing the positive fixture and opening the independently built negative fixture, reusing it with the original pattern also failed with the same mismatch. REA/Kuna 1.986 reported `capability_unavailable` for the byte-search request. These are one real host/provider run, not a general cursor-security or architecture claim. Both target hashes remained unchanged and neither target was executed. This preserves the distinction in the original report: the first result identifies an instruction-interior byte plus its containing procedure, while the second is data; a match does not establish algorithm semantics or runtime use.
Author
Owner

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

Additional real REA/Ghidra MCP control for a pattern spanning instructions and function bodies. An unexecuted 17-byte x86-64 raw fixture, opened at 0x1000, contained:

0x1000: e8 06 00 00 00  CALL 0x100b
0x1005: b8 78 56 34 12  MOV EAX,0x12345678
0x100a: c3              RET
0x100b: b8 21 43 65 87  MOV EAX,0x87654321
0x1010: c3              RET

search_bytes({"pattern":"56 34 12 c3 b8"}) found 0x1007 and identified the start as belonging to function 0x1000. read_bytes confirmed all five matched bytes. inspect_native_instruction(0x1007) returned not-instruction-boundary and procedure 0x1000; exact queries at 0x1005, 0x100a and 0x100b confirmed the three instructions and the second function. inspect_address_context(0x1007) correctly returned the first function body ending at 0x100a, while xrefs(0x1007) was empty. Neither the starting procedure nor the empty xref describes the entire five-byte match.

This supports the existing issue's proposed requirement to preserve the original byte range and avoid assigning a multi-instruction match wholesale to a single instruction or function. It does not imply search is wrong or a runtime path exists. Calls used the advertised full MCP output schemas with SDK validation, Ghidra 12.1.4 and REA d54a4661da20382ad8456564a08569fdd24131c5; target SHA-256 58658a4b21d7ffc610f7123d0f4e9435c3ba63b54facea49da1bb9bb51cd8cc5 was unchanged. This is one raw x86-64 fixture, not broad architecture coverage.

<!-- gh-comment-id:6548068043 --> @morluto commented on GitHub (Oct 31, 2026): Additional real REA/Ghidra MCP control for a pattern spanning instructions **and function bodies**. An unexecuted 17-byte x86-64 raw fixture, opened at `0x1000`, contained: ```text 0x1000: e8 06 00 00 00 CALL 0x100b 0x1005: b8 78 56 34 12 MOV EAX,0x12345678 0x100a: c3 RET 0x100b: b8 21 43 65 87 MOV EAX,0x87654321 0x1010: c3 RET ``` `search_bytes({"pattern":"56 34 12 c3 b8"})` found `0x1007` and identified the **start** as belonging to function `0x1000`. `read_bytes` confirmed all five matched bytes. `inspect_native_instruction(0x1007)` returned `not-instruction-boundary` and procedure `0x1000`; exact queries at `0x1005`, `0x100a` and `0x100b` confirmed the three instructions and the second function. `inspect_address_context(0x1007)` correctly returned the first function body ending at `0x100a`, while `xrefs(0x1007)` was empty. Neither the starting procedure nor the empty xref describes the entire five-byte match. This supports the existing issue's proposed requirement to preserve the original byte range and avoid assigning a multi-instruction match wholesale to a single instruction or function. It does not imply search is wrong or a runtime path exists. Calls used the advertised full MCP output schemas with SDK validation, Ghidra 12.1.4 and REA `d54a4661da20382ad8456564a08569fdd24131c5`; target SHA-256 `58658a4b21d7ffc610f7123d0f4e9435c3ba63b54facea49da1bb9bb51cd8cc5` was unchanged. This is one raw x86-64 fixture, not broad architecture coverage.
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#6509
No description provided.