mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
test(ghidra): preserve metadata in interior-label fixture
Place the imported control label inside a valid multi-byte NOP instead of suppressing Mach-O function-start metadata. Encode the supported ARM64 and x86-64 instructions explicitly and retain the load dependency so the control remains past the function entry. Assert that Ghidra imports a label and no procedure at the control address before checking name rejection and address containment. Two real arm64 Ghidra 12.1.4 imports confirmed both fixture strategies produce labels; only default linking retains LC_FUNCTION_STARTS. The full native-value CLI/MCP verifier passed with 349 successful and 52 expected rejected boundary calls, including imported aliases, complete exports, and startup cancellation cleanup. Host ARM64 and Apple x86-64 fixture compilation passed; x86 provider execution remains unverified.
This commit is contained in:
1 parent
c7345512ea
commit
926c2d6ba7
2 files changed
+33
-18
No files matched your search
@@ -22,20 +22,10 @@ export async function verifyGhidraEntryAliases({
|
||||
);
|
||||
const path = join(workspace, "entry-aliases");
|
||||
try {
|
||||
// Mach-O function-start metadata would promote the interior control label.
|
||||
await exec(
|
||||
compiler,
|
||||
[
|
||||
"-O0",
|
||||
"-g",
|
||||
"-fno-inline",
|
||||
...(process.platform === "darwin" ? ["-Wl,-no_function_starts"] : []),
|
||||
source,
|
||||
"-o",
|
||||
path,
|
||||
],
|
||||
{ env, timeout: 30000 },
|
||||
);
|
||||
await exec(compiler, ["-O0", "-g", "-fno-inline", source, "-o", path], {
|
||||
env,
|
||||
timeout: 30000,
|
||||
});
|
||||
const bytes = await readFile(path);
|
||||
await call("close_binary");
|
||||
const imported = await call("open_binary", { path, provider_id: "ghidra" });
|
||||
@@ -101,6 +91,18 @@ export async function verifyGhidraEntryAliases({
|
||||
);
|
||||
assert.ok(interior);
|
||||
assert.notEqual(interior.address, alias.address);
|
||||
assert.equal(
|
||||
interior.symbol.type,
|
||||
"label",
|
||||
"Fixture interior control must remain an imported label",
|
||||
);
|
||||
assert.equal(
|
||||
(await call("list_procedures")).some(
|
||||
({ address }) => address === interior.address,
|
||||
),
|
||||
false,
|
||||
"Fixture interior control must not be a Ghidra procedure entry",
|
||||
);
|
||||
const failure = await reject("procedure_address", {
|
||||
procedure: interior.value,
|
||||
});
|
||||
|
||||
@@ -9,10 +9,23 @@ volatile int rea_xrefs_data = 17;
|
||||
__attribute__((used)) volatile int rea_xrefs_unreferenced = 41;
|
||||
|
||||
__attribute__((noinline, used)) int rea_alias_target(void) {
|
||||
// ARM64 leaf functions may have no prologue; keep the control past entry.
|
||||
__asm__ volatile("nop\n.globl " REA_SYMBOL("rea_interior") "\n"
|
||||
REA_SYMBOL("rea_interior") ":");
|
||||
return rea_xrefs_data;
|
||||
int value = rea_xrefs_data;
|
||||
// Preserve normal function-start metadata. Imported symbols at instruction
|
||||
// boundaries can become procedure entries, so keep this label inside a NOP.
|
||||
#if defined(__aarch64__)
|
||||
__asm__ volatile(".globl " REA_SYMBOL("rea_interior") "\n"
|
||||
".byte 0x1f\n"
|
||||
REA_SYMBOL("rea_interior") ":\n"
|
||||
".byte 0x20,0x03,0xd5\n" : : "r"(value));
|
||||
#elif defined(__x86_64__)
|
||||
__asm__ volatile(".byte 0x0f\n"
|
||||
".globl " REA_SYMBOL("rea_interior") "\n"
|
||||
REA_SYMBOL("rea_interior") ":\n"
|
||||
".byte 0x1f,0x00\n" : : "r"(value));
|
||||
#else
|
||||
#error "The Ghidra entry-alias fixture supports only x86_64 and arm64"
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
__asm__(".globl " REA_SYMBOL("rea_entry_alias") "\n"
|
||||
|
||||
Reference in new issue
Block a user