85 lines
2.9 KiB
JavaScript
85 lines
2.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
|
|
const limitationPattern = /Borland\/Delphi-style SEH frame registration/u;
|
|
|
|
/** Verify Ghidra reports, and does not absorb, the fixture's handler region. */
|
|
export async function verifyGhidraBorlandSeh(functionObservation, x86) {
|
|
assert.equal(x86, true, "The SEH control exists only in the x86 PE fixture");
|
|
const caller = "0x401015";
|
|
const procedure = "0x401080";
|
|
const handler = "0x4010c0";
|
|
|
|
const ordinary = await functionObservation("procedure_info", {
|
|
procedure: "0x401010",
|
|
});
|
|
assert.ok(
|
|
!ordinary.limitations.some((item) => limitationPattern.test(item)),
|
|
"The ordinary return-42 control unexpectedly reports an SEH limitation",
|
|
);
|
|
|
|
const info = await functionObservation("procedure_info", { procedure });
|
|
assert.ok(info.limitations.some((item) => limitationPattern.test(item)));
|
|
|
|
const outgoing = await functionObservation("procedure_references", {
|
|
procedure,
|
|
direction: "outgoing",
|
|
});
|
|
assert.equal(outgoing.value.direction, "outgoing");
|
|
assert.ok(outgoing.limitations.some((item) => limitationPattern.test(item)));
|
|
assert.ok(
|
|
outgoing.value.references.some(
|
|
(reference) =>
|
|
reference.source_address === "0x401083" &&
|
|
reference.target_address === handler &&
|
|
reference.kind.available &&
|
|
reference.kind.data &&
|
|
!reference.kind.call,
|
|
),
|
|
"The pushed handler address must remain an observed data reference, without inventing a call",
|
|
);
|
|
|
|
const incoming = await functionObservation("procedure_references", {
|
|
procedure,
|
|
direction: "incoming",
|
|
});
|
|
assert.equal(incoming.value.direction, "incoming");
|
|
assert.ok(incoming.limitations.some((item) => limitationPattern.test(item)));
|
|
assert.ok(
|
|
incoming.value.references.some(
|
|
(reference) =>
|
|
reference.source_address === caller &&
|
|
reference.target_address === procedure,
|
|
),
|
|
"The caller-to-registration procedure reference was not observed",
|
|
);
|
|
|
|
const dossier = await functionObservation("analyze_function", {
|
|
procedure,
|
|
});
|
|
assert.ok(dossier.limitations.some((item) => limitationPattern.test(item)));
|
|
assert.ok(
|
|
dossier.value.limitations.some((item) => limitationPattern.test(item)),
|
|
"The normalized function dossier lost the SEH limitation",
|
|
);
|
|
assert.equal(dossier.value.procedure.body.available, true);
|
|
assert.ok(dossier.value.procedure.body.ranges.length > 0);
|
|
assert.ok(
|
|
!dossier.value.procedure.body.ranges.some(
|
|
(range) =>
|
|
BigInt(range.start) <= BigInt(handler) &&
|
|
BigInt(range.end) >= BigInt(handler),
|
|
),
|
|
"The handler was incorrectly claimed as part of the procedure body",
|
|
);
|
|
|
|
return {
|
|
limitation: true,
|
|
ordinary_control: true,
|
|
procedure_references_incoming_and_outgoing: true,
|
|
handler_data_reference: true,
|
|
caller_reference: true,
|
|
dossier_limitation: true,
|
|
handler_body_not_claimed: true,
|
|
};
|
|
}
|