Add trace_dylib_resolution (CLI trace-dylib-resolution) to the artifact family. For the active Mach-O, or every executable in the active .app (the main app, XPC services, extensions, login items, helpers), it reports which file each dylib load reaches and how. A pure TypeScript reader decodes FAT and Mach-O load commands: LC_LOAD/WEAK/REEXPORT/LAZY/UPWARD_DYLIB, including the newer dylib_use_command encoding with weak, re-export, upward and delayed-init flags, plus LC_ID_DYLIB, LC_RPATH, LC_DYLD_ENVIRONMENT and code-signature presence. Malformed tables are reported with the failing command instead of being guessed. Resolution follows dyld: - @executable_path comes from each process root; - @loader_path comes from the loading image, or from the owner of the LC_RPATH entry being expanded; - @rpath searches the loader's rpaths first, then up the load chain; - dependencies load dependents-first in load-command order, once per process, and a matching install name reuses an already loaded image; - symlinks are followed inside the analyzed root, and escapes stop. Every candidate path is reported with its outcome. Each edge resolves to resolved, conditional (an outside-root candidate such as /usr/lib/swift precedes), unresolved, or undetermined. Absolute and shared-cache system paths are never checked against the host. Derived findings cover unresolved required or weak loads, absent earlier @rpath candidates (with library validation left unknown), and LC_DYLD_ENVIRONMENT. verify:macos-bundle now also: - checks every traced image against otool -l; - asserts each resolution status on a clang-built fixture that adds a missing Overrides rpath, an absolute rpath, and a delay-init library; - compares the predicted load order of two process roots with what dyld loads under DYLD_PRINT_LIBRARIES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
import type {
|
|
CapabilityDescriptor,
|
|
ProviderIdentity,
|
|
} from "../application/AnalysisProvider.js";
|
|
import { ARTIFACT_GRAPH_PROVIDER } from "../application/InvestigationProviders.js";
|
|
import { ARTIFACT_ANALYSIS_OPERATIONS } from "../contracts/artifactToolContracts.js";
|
|
|
|
/** Identity of artifact inventory and owned extraction observations. */
|
|
export const ARTIFACT_PROVIDER_IDENTITY: ProviderIdentity = Object.freeze(
|
|
ARTIFACT_GRAPH_PROVIDER,
|
|
);
|
|
const IDENTITY = ARTIFACT_PROVIDER_IDENTITY;
|
|
|
|
/** Declare artifact coverage without constructing readers or acquiring resources. */
|
|
export const artifactCapabilities = (
|
|
platform: NodeJS.Platform = process.platform,
|
|
): readonly CapabilityDescriptor[] =>
|
|
Object.freeze(
|
|
ARTIFACT_ANALYSIS_OPERATIONS.map((operation) => {
|
|
const common = {
|
|
provider: IDENTITY,
|
|
operation,
|
|
effects: Object.freeze({
|
|
mutatesArtifact: false,
|
|
launchesProcess:
|
|
operation !== "decode_interface_builder" &&
|
|
operation !== "inspect_keyed_archive" &&
|
|
operation !== "trace_dylib_resolution",
|
|
mayShowUi: false,
|
|
mayAccessNetwork: false,
|
|
mayWriteFilesystem:
|
|
operation === "extract_artifact" ||
|
|
operation === "inspect_artifact" ||
|
|
operation === "inventory_artifact",
|
|
changesPermissions: false,
|
|
requiresRoot: false,
|
|
}),
|
|
limitations: Object.freeze([
|
|
"DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.",
|
|
"ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only.",
|
|
]),
|
|
};
|
|
return Object.freeze(
|
|
operation === "inspect_asset_catalog" && platform !== "darwin"
|
|
? {
|
|
...common,
|
|
available: false as const,
|
|
availabilityCode: "unsupported_host" as const,
|
|
reason: "Apple asset catalogs require macOS assetutil.",
|
|
}
|
|
: { ...common, available: true as const, reason: null },
|
|
);
|
|
}),
|
|
);
|