53 lines
2.0 KiB
JavaScript
53 lines
2.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
|
|
const NEGATIVE_REASONS = new Set(["not_in_procedure", "outside_segments"]);
|
|
|
|
/**
|
|
* Assert the `trace_feature` result of the real IDA lane for one selected
|
|
* procedure. The query is a substring search, so the trace may also match other
|
|
* procedures and strings; each reference is checked against its own matched
|
|
* target, and a source outside every function (a data reference) is valid.
|
|
*/
|
|
export function assertFeatureTrace(trace, procedure) {
|
|
assert.ok(
|
|
trace.matches.some(
|
|
({ type, address }) =>
|
|
type === "procedure" && address === procedure.address,
|
|
),
|
|
"The trace omitted the selected procedure's match.",
|
|
);
|
|
assert.equal(typeof trace.truncated, "boolean");
|
|
const matched = new Set(trace.matches.map(({ address }) => address));
|
|
for (const reference of trace.references) {
|
|
assert.ok(
|
|
matched.has(reference.target_address),
|
|
`A reference targets ${reference.target_address}, which is not a match.`,
|
|
);
|
|
const { containing_procedure: containing } = reference;
|
|
if (containing.found)
|
|
assert.equal(typeof containing.procedure.address, "string");
|
|
else assert.ok(NEGATIVE_REASONS.has(containing.reason));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find a string that IDA maps outside every function. A string inside a
|
|
* function chunk (inline data in code) is valid and skipped, so the strings are
|
|
* tried in order. Any other answer must be "not in a procedure": IDA lists only
|
|
* mapped strings, so an unmapped answer is a containment defect and fails the
|
|
* lane. Returns the address, or undefined when every string is inside a function.
|
|
*/
|
|
export async function findMappedNonFunction(strings, resolveAt) {
|
|
for (const { address } of strings) {
|
|
const resolved = await resolveAt(address);
|
|
if (resolved.found) continue;
|
|
assert.equal(
|
|
resolved.reason,
|
|
"not_in_procedure",
|
|
`The listed string at ${address} resolved as ${resolved.reason}.`,
|
|
);
|
|
return address;
|
|
}
|
|
return undefined;
|
|
}
|