fix(ghidra): select exact packaged bridge scripts (#800)

This commit is contained in:
N0zoM1z0 2026-10-07 04:54:52 +08:00 committed by GitHub
parent f9eaf056ef
commit 894c30ef02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 5 deletions

View File

@ -32,6 +32,10 @@ REA does not install or upgrade Ghidra, Java, Python, npm, Node.js, Hopper, or a
compiler. The adapter uses the packaged Java `HeadlessScript`; Python and
PyGhidra are not prerequisites. Users do not build the native addon.
REA selects its packaged bridge scripts by explicit path. Same-named files or
directories in the caller's working directory do not select a different
script or require users to clean that directory before analysis.
## Configuration
```powershell

View File

@ -108,6 +108,10 @@ try {
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
const runtimeParent = join(workspace, "runtime with spaces");
await mkdir(runtimeParent);
const callerDirectory = join(workspace, "caller cwd with spaces");
const scriptCollisions = ["ReaGhidraBridge.java", "ReaGhidraPrepareCom.java"];
await mkdir(callerDirectory);
for (const name of scriptCollisions) await mkdir(join(callerDirectory, name));
const environment = {
...Object.fromEntries(
Object.entries(process.env).filter(
@ -158,6 +162,7 @@ try {
(
await exec(process.execPath, [entry, "providers", "--json"], {
env: environment,
cwd: callerDirectory,
timeout: 30_000,
})
).stdout,
@ -167,7 +172,12 @@ try {
const inspected = await exec(
process.execPath,
[entry, "inspect", target, "--provider", "ghidra", "--format", "json"],
{ env: environment, timeout: 360_000, maxBuffer: 8 * 1024 * 1024 },
{
env: environment,
cwd: callerDirectory,
timeout: 360_000,
maxBuffer: 8 * 1024 * 1024,
},
);
const inspection = JSON.parse(inspected.stdout);
assert.ok(inspection.error === undefined);
@ -177,6 +187,7 @@ try {
command: process.execPath,
args: [entry, "mcp"],
env: environment,
cwd: callerDirectory,
stderr: "pipe",
});
const client = new Client({
@ -290,6 +301,10 @@ try {
token,
"Analysis changed caller token authority.",
);
assert.deepEqual((await readdir(callerDirectory)).sort(), scriptCollisions);
for (const name of scriptCollisions)
assert.deepEqual(await readdir(join(callerDirectory, name)), []);
report.callerScriptCollisionsPreserved = true;
report.runtimeCleanup = true;
report.ok = true;
if (process.argv[4] !== undefined)

View File

@ -322,10 +322,15 @@ export const ghidraHeadlessArguments = (
"-scriptPath",
dirname(options.bridgeScriptPath),
...(options.dosCom === true
? ["-preScript", "ReaGhidraPrepareCom.java"]
? [
"-preScript",
join(dirname(options.bridgeScriptPath), "ReaGhidraPrepareCom.java"),
]
: []),
"-postScript",
basename(options.bridgeScriptPath),
// Ghidra checks the caller's cwd before scriptPath for a basename. Select
// the packaged source explicitly so unrelated entries cannot shadow it.
options.bridgeScriptPath,
options.descriptorPath,
];

View File

@ -95,7 +95,9 @@ describe("Ghidra COM loader", () => {
"default",
]);
const prepare = arguments_.indexOf("-preScript");
expect(arguments_[prepare + 1]).toBe("ReaGhidraPrepareCom.java");
expect(arguments_[prepare + 1]).toBe(
join("/package/bridge", "ReaGhidraPrepareCom.java"),
);
expect(prepare).toBeLessThan(arguments_.indexOf("-postScript"));
expect(arguments_).toContain("-readOnly");
expect(arguments_).toContain("-deleteProject");
@ -148,7 +150,7 @@ describe("Ghidra headless launcher", () => {
"-scriptPath",
"/package/bridge",
"-postScript",
"ReaGhidraBridge.java",
"/package/bridge/ReaGhidraBridge.java",
"/tmp/session.json",
]);
});