mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 14:26:07 +00:00
Universal Mach-O admission reported the selected slice architecture while the IDA provider's private input copy handed the whole FAT container to upstream idalib, which then picked its own slice (x86_64 for /bin/cat) while Evidence labeled the session arm64. FAT parsing now exports the selected slice's byte range as universalSlice, and the private input copy writes exactly those bytes: the whole source digest still anchors the copy against admission-time changes, and the thinned result anchors the post-operation identity check. Thin targets keep the whole-file copy, and mach-o-universal remains the container format across Evidence, snapshots, and provider routing. Validation: typecheck, oxlint (no new warnings), oxfmt, and targeted vitest runs — ida adapters 12 files/116 tests, domain and services projects 60 files/736 tests, ghidra/hopper behavior 2 files/50 tests, filesystem and universal-extraction boundary 2 files/49 tests, native signature MCP 1 file/2 tests, plus a new thinning suite (5 tests, red before the fix: 3 failed). The thinned product was verified byte-identical to the `clang -arch arm64` input of a `lipo -create` universal fixture. Controlled fixtures only; no live IDA analysis was performed for this change. Closes #2139
153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
/** Provider-neutral CPU families detected from supported executable headers. */
|
|
export const BINARY_ARCHITECTURES = [
|
|
"x86",
|
|
"x86_64",
|
|
"arm",
|
|
"arm64",
|
|
"mips",
|
|
] as const;
|
|
export type BinaryArchitecture = (typeof BINARY_ARCHITECTURES)[number];
|
|
|
|
/** Raw ELF facts; family recognition does not establish ISA or ABI support. */
|
|
export interface MipsElfMetadata {
|
|
readonly elfClass: 32 | 64;
|
|
readonly byteOrder: "little" | "big";
|
|
readonly type: number;
|
|
readonly flags: number;
|
|
/** Undefined until inspected; null means no ABI record was observed. */
|
|
readonly abiFlags?: MipsAbiFlags | null;
|
|
/** Unavailable declaration sources; missing records there remain unknown. */
|
|
readonly limitations?: readonly string[];
|
|
/** Complete dynamic REL declarations, or the reason they could not be inspected. */
|
|
readonly sharedLoad?:
|
|
| {
|
|
readonly status: "complete";
|
|
readonly relocationCount: number;
|
|
readonly relocationTypes: readonly number[];
|
|
readonly symbolRelativeCount: number;
|
|
}
|
|
| { readonly status: "unavailable"; readonly reason: string };
|
|
}
|
|
|
|
/** Declared fields of the 24-byte MIPS ABI flags record, not inferred semantics. */
|
|
export interface MipsAbiFlags {
|
|
readonly version: number;
|
|
readonly isaLevel: number;
|
|
readonly isaRevision: number;
|
|
readonly gprSize: number;
|
|
readonly cpr1Size: number;
|
|
readonly cpr2Size: number;
|
|
readonly fpAbi: number;
|
|
readonly isaExtension: number;
|
|
readonly ases: number;
|
|
readonly flags1: number;
|
|
readonly flags2: number;
|
|
}
|
|
|
|
/** Byte range of the selected slice inside its universal Mach-O container. */
|
|
export interface UniversalMachOSlice {
|
|
readonly offset: number;
|
|
readonly size: number;
|
|
}
|
|
|
|
interface BinaryTargetIdentity {
|
|
readonly path: string;
|
|
readonly sourcePath?: string;
|
|
/** Info.plist of the app bundle the target was resolved from. */
|
|
readonly bundleInfoPlist?: string;
|
|
readonly sha256: string;
|
|
}
|
|
|
|
type NonExecutableMetadata = {
|
|
readonly architecture?: never;
|
|
readonly availableArchitectures?: never;
|
|
readonly executableRole?: never;
|
|
readonly managed?: never;
|
|
};
|
|
|
|
type ExecutableTarget = BinaryTargetIdentity & {
|
|
readonly kind: "executable";
|
|
readonly architecture: Exclude<BinaryArchitecture, "mips">;
|
|
readonly availableArchitectures: readonly Exclude<
|
|
BinaryArchitecture,
|
|
"mips"
|
|
>[];
|
|
};
|
|
|
|
/**
|
|
* Canonical local target identity and provider-neutral file classification.
|
|
* Each variant carries only metadata established for that exact file kind.
|
|
*/
|
|
export type BinaryTarget =
|
|
| (BinaryTargetIdentity & {
|
|
readonly kind: "executable";
|
|
readonly format: "elf";
|
|
readonly architecture: "mips";
|
|
readonly availableArchitectures: readonly "mips"[];
|
|
readonly mips: MipsElfMetadata;
|
|
readonly executableRole?: never;
|
|
readonly managed?: never;
|
|
})
|
|
| (ExecutableTarget & {
|
|
readonly format: "mach-o" | "elf" | "dos-mz" | "dos-com";
|
|
readonly universalSlice?: never;
|
|
readonly executableRole?: never;
|
|
readonly managed?: never;
|
|
})
|
|
| (ExecutableTarget & {
|
|
readonly format: "mach-o-universal";
|
|
/** Selected slice range a provider must analyze instead of the container. */
|
|
readonly universalSlice: UniversalMachOSlice;
|
|
readonly executableRole?: never;
|
|
readonly managed?: never;
|
|
})
|
|
| (ExecutableTarget & {
|
|
readonly format: "raw-binary";
|
|
readonly entryPoint: string;
|
|
readonly entryPointSource: string;
|
|
readonly executableRole?: never;
|
|
readonly managed?: never;
|
|
})
|
|
| (ExecutableTarget & {
|
|
readonly format: "pe";
|
|
/** Provider-neutral PE image role observed from COFF characteristics. */
|
|
readonly executableRole:
|
|
| "application"
|
|
| "shared-library"
|
|
| "non-executable";
|
|
/** Whether the PE declares a non-empty CLI header data-directory entry. */
|
|
readonly managed: boolean;
|
|
})
|
|
| (BinaryTargetIdentity &
|
|
NonExecutableMetadata & {
|
|
readonly kind: "database";
|
|
readonly format: "analysis-database";
|
|
})
|
|
| (BinaryTargetIdentity &
|
|
NonExecutableMetadata & {
|
|
readonly kind: "archive";
|
|
readonly format:
|
|
| "zip"
|
|
| "ipa"
|
|
| "apk"
|
|
| "msix"
|
|
| "appx"
|
|
| "hap"
|
|
| "hsp"
|
|
| "app-pack"
|
|
| "asar"
|
|
| "dmg"
|
|
| "pkg";
|
|
})
|
|
| (BinaryTargetIdentity &
|
|
NonExecutableMetadata & {
|
|
readonly kind: "artifact";
|
|
readonly format: "plist" | "javascript" | "source-map";
|
|
});
|
|
|
|
/** Whether an executable target contains a thin or universal Mach-O image. */
|
|
export const isMachOFormat = (
|
|
format: unknown,
|
|
): format is "mach-o" | "mach-o-universal" =>
|
|
format === "mach-o" || format === "mach-o-universal";
|