rea-agents 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import canonicalize from "canonicalize";
|
|
4
|
+
import { parseEvidence } from "./evidence.js";
|
|
5
|
+
import { functionDossierSchema } from "./hopperValues.js";
|
|
6
|
+
import { inspectMachoSchema } from "./nativeInspection.js";
|
|
7
|
+
import { pinvokeVerificationSchema, } from "./managedNativeVerificationSchemas.js";
|
|
8
|
+
const digest = (value) => {
|
|
9
|
+
const serialized = canonicalize(value);
|
|
10
|
+
if (serialized === undefined)
|
|
11
|
+
throw new TypeError("Managed/native verification canonicalization failed");
|
|
12
|
+
return createHash("sha256").update(serialized).digest("hex");
|
|
13
|
+
};
|
|
14
|
+
const moduleName = (evidence) => evidence.subject?.name ?? null;
|
|
15
|
+
const modulePath = (evidence) => evidence.subject?.local_path ?? null;
|
|
16
|
+
const symbolsForEvidence = (evidence) => {
|
|
17
|
+
if (evidence.operation === "inspect_macho") {
|
|
18
|
+
const result = inspectMachoSchema.parse(evidence.normalized_result);
|
|
19
|
+
return {
|
|
20
|
+
supported: true,
|
|
21
|
+
symbols: result.exports.items.map((symbol) => ({
|
|
22
|
+
evidence_id: evidence.evidence_id,
|
|
23
|
+
operation: evidence.operation,
|
|
24
|
+
name: symbol.name,
|
|
25
|
+
address: symbol.address,
|
|
26
|
+
module_name: moduleName(evidence),
|
|
27
|
+
module_path: modulePath(evidence),
|
|
28
|
+
source: "macho-export",
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (evidence.operation === "analyze_function") {
|
|
33
|
+
const dossier = functionDossierSchema.parse(evidence.normalized_result);
|
|
34
|
+
return {
|
|
35
|
+
supported: true,
|
|
36
|
+
symbols: [
|
|
37
|
+
{
|
|
38
|
+
evidence_id: evidence.evidence_id,
|
|
39
|
+
operation: evidence.operation,
|
|
40
|
+
name: dossier.procedure.name,
|
|
41
|
+
address: dossier.procedure.address,
|
|
42
|
+
module_name: moduleName(evidence),
|
|
43
|
+
module_path: modulePath(evidence),
|
|
44
|
+
source: "function-dossier",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return { supported: false, symbols: [] };
|
|
50
|
+
};
|
|
51
|
+
export const collectNativeSymbols = (observations) => {
|
|
52
|
+
const symbols = [];
|
|
53
|
+
let accepted = 0;
|
|
54
|
+
let unsupported = 0;
|
|
55
|
+
for (const raw of observations) {
|
|
56
|
+
const evidence = parseEvidence(raw);
|
|
57
|
+
const extracted = symbolsForEvidence(evidence);
|
|
58
|
+
if (!extracted.supported) {
|
|
59
|
+
unsupported += 1;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
accepted += 1;
|
|
63
|
+
symbols.push(...extracted.symbols);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { symbols, accepted, unsupported };
|
|
67
|
+
};
|
|
68
|
+
const normalizeSymbol = (value) => value.replace(/^_+/u, "").replace(/@\d+$/u, "").toLowerCase();
|
|
69
|
+
const sameSymbolName = (left, right) => normalizeSymbol(left) === normalizeSymbol(right);
|
|
70
|
+
const normalizeModule = (value) => basename(value)
|
|
71
|
+
.toLowerCase()
|
|
72
|
+
.replace(/^lib/u, "")
|
|
73
|
+
.replace(/\.(dll|dylib|so|node|exe)$/u, "");
|
|
74
|
+
const moduleCompatible = (scope, symbol) => {
|
|
75
|
+
if (scope === null)
|
|
76
|
+
return true;
|
|
77
|
+
const expected = normalizeModule(scope);
|
|
78
|
+
return [symbol.module_name, symbol.module_path]
|
|
79
|
+
.filter((value) => value !== null)
|
|
80
|
+
.map(normalizeModule)
|
|
81
|
+
.some((value) => value === expected);
|
|
82
|
+
};
|
|
83
|
+
const candidateNames = (managed) => {
|
|
84
|
+
const names = new Set([managed.import_name]);
|
|
85
|
+
if (!managed.no_mangle) {
|
|
86
|
+
if (managed.char_set === "unicode")
|
|
87
|
+
names.add(`${managed.import_name}W`);
|
|
88
|
+
if (managed.char_set === "ansi")
|
|
89
|
+
names.add(`${managed.import_name}A`);
|
|
90
|
+
if (managed.call_convention === "stdcall") {
|
|
91
|
+
names.add(`_${managed.import_name}`);
|
|
92
|
+
names.add(`_${managed.import_name}@0`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return [...names];
|
|
96
|
+
};
|
|
97
|
+
const selectCandidates = (managed, symbols, maxCandidates) => {
|
|
98
|
+
const names = candidateNames(managed);
|
|
99
|
+
const allCandidates = symbols.filter((symbol) => names.some((name) => sameSymbolName(name, symbol.name)));
|
|
100
|
+
const candidates = allCandidates.slice(0, maxCandidates);
|
|
101
|
+
const exact = candidates.find((symbol) => sameSymbolName(managed.import_name, symbol.name) &&
|
|
102
|
+
moduleCompatible(managed.import_scope_name, symbol));
|
|
103
|
+
const decorated = candidates.find((symbol) => moduleCompatible(managed.import_scope_name, symbol));
|
|
104
|
+
const selected = exact ?? decorated ?? candidates[0] ?? null;
|
|
105
|
+
return { allCandidates, candidates, selected, exact, decorated };
|
|
106
|
+
};
|
|
107
|
+
const basisAndStatus = (managed, selection, hasSupportedNativeEvidence) => {
|
|
108
|
+
const { selected, exact } = selection;
|
|
109
|
+
if (selected === null)
|
|
110
|
+
return {
|
|
111
|
+
basis: hasSupportedNativeEvidence
|
|
112
|
+
? "no-native-candidate"
|
|
113
|
+
: "unsupported-native-evidence",
|
|
114
|
+
status: "unresolved",
|
|
115
|
+
confidence: "unknown",
|
|
116
|
+
};
|
|
117
|
+
if (!moduleCompatible(managed.import_scope_name, selected))
|
|
118
|
+
return {
|
|
119
|
+
basis: "module-mismatch",
|
|
120
|
+
status: "contradicted",
|
|
121
|
+
confidence: "unknown",
|
|
122
|
+
};
|
|
123
|
+
if (exact !== undefined)
|
|
124
|
+
return {
|
|
125
|
+
basis: selected.source === "macho-export"
|
|
126
|
+
? "exact-export-name"
|
|
127
|
+
: "exact-function-name",
|
|
128
|
+
status: "verified",
|
|
129
|
+
confidence: "observed",
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
basis: "decorated-name-candidate",
|
|
133
|
+
status: "inferred",
|
|
134
|
+
confidence: "inferred",
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const pinvokeLimitations = (status, managed) => [
|
|
138
|
+
...(managed.import_scope_name === null
|
|
139
|
+
? ["Managed declaration does not name an import scope/module."]
|
|
140
|
+
: []),
|
|
141
|
+
...(status === "inferred"
|
|
142
|
+
? [
|
|
143
|
+
"Native symbol matched a decorated candidate rather than the exact declared import name.",
|
|
144
|
+
]
|
|
145
|
+
: []),
|
|
146
|
+
...(status === "contradicted"
|
|
147
|
+
? [
|
|
148
|
+
"A symbol name candidate exists, but the supplied native Evidence module identity does not match the managed import scope.",
|
|
149
|
+
]
|
|
150
|
+
: []),
|
|
151
|
+
...(status === "unresolved"
|
|
152
|
+
? [
|
|
153
|
+
"No supplied native export/function Evidence matched this declared import.",
|
|
154
|
+
]
|
|
155
|
+
: []),
|
|
156
|
+
];
|
|
157
|
+
export const verifyPinvoke = ({ item, managedEvidenceId, symbols, hasSupportedNativeEvidence, input, }) => {
|
|
158
|
+
const managed = {
|
|
159
|
+
token: item.token,
|
|
160
|
+
member_token: item.member_token,
|
|
161
|
+
member_name: item.member_name,
|
|
162
|
+
import_name: item.import_name,
|
|
163
|
+
import_scope_name: item.import_scope_name,
|
|
164
|
+
no_mangle: item.no_mangle,
|
|
165
|
+
char_set: item.char_set,
|
|
166
|
+
call_convention: item.call_convention,
|
|
167
|
+
declaration_verification: item.verification,
|
|
168
|
+
};
|
|
169
|
+
const selection = selectCandidates(item, symbols, input.limits.max_candidates_per_import);
|
|
170
|
+
const { status, basis, confidence } = basisAndStatus(item, selection, hasSupportedNativeEvidence);
|
|
171
|
+
const limitations = pinvokeLimitations(status, item);
|
|
172
|
+
return {
|
|
173
|
+
verification: pinvokeVerificationSchema.parse({
|
|
174
|
+
item_id: `mnv_pinvoke_${digest({
|
|
175
|
+
managedEvidenceId,
|
|
176
|
+
token: item.token,
|
|
177
|
+
importName: item.import_name,
|
|
178
|
+
importScope: item.import_scope_name,
|
|
179
|
+
candidates: [...selection.candidates],
|
|
180
|
+
})}`,
|
|
181
|
+
managed,
|
|
182
|
+
status,
|
|
183
|
+
basis,
|
|
184
|
+
confidence,
|
|
185
|
+
matched_native: selection.selected,
|
|
186
|
+
candidates: selection.candidates,
|
|
187
|
+
evidence_links: [
|
|
188
|
+
managedEvidenceId,
|
|
189
|
+
...new Set(selection.candidates.map(({ evidence_id: id }) => id)),
|
|
190
|
+
],
|
|
191
|
+
limitations,
|
|
192
|
+
}),
|
|
193
|
+
omittedCandidates: Math.max(0, selection.allCandidates.length - selection.candidates.length),
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
const countStatuses = (items) => ({
|
|
197
|
+
verified: items.filter(({ status }) => status === "verified").length,
|
|
198
|
+
inferred: items.filter(({ status }) => status === "inferred").length,
|
|
199
|
+
unresolved: items.filter(({ status }) => status === "unresolved").length,
|
|
200
|
+
contradicted: items.filter(({ status }) => status === "contradicted").length,
|
|
201
|
+
});
|
|
202
|
+
export const buildVerificationResult = ({ managedEvidence, managed, native, pinvokeImports, verifiedPinvokes, input, }) => {
|
|
203
|
+
const counts = countStatuses(pinvokeImports);
|
|
204
|
+
const omittedNativeObservations = Math.max(0, input.native_observations.length - input.limits.max_native_observations);
|
|
205
|
+
const omittedCandidates = verifiedPinvokes.reduce((sum, item) => sum + item.omittedCandidates, 0);
|
|
206
|
+
const nativeBodyUnresolved = managed.native_implementations.items.filter(({ boundary_kind: kind }) => kind !== "pinvoke").length;
|
|
207
|
+
const coverageStatus = omittedNativeObservations > 0 || omittedCandidates > 0
|
|
208
|
+
? "truncated"
|
|
209
|
+
: managed.coverage.state === "complete" && native.unsupported === 0
|
|
210
|
+
? "complete-within-inputs"
|
|
211
|
+
: "partial";
|
|
212
|
+
return {
|
|
213
|
+
schema_version: 1,
|
|
214
|
+
algorithm: {
|
|
215
|
+
name: "rea-managed-native-verification",
|
|
216
|
+
version: 1,
|
|
217
|
+
token_identity: "build-local",
|
|
218
|
+
token_to_address_mapping: "not-inferred",
|
|
219
|
+
},
|
|
220
|
+
managed_boundary: {
|
|
221
|
+
evidence_id: managedEvidence.evidence_id,
|
|
222
|
+
artifact_sha256: managed.artifact.sha256,
|
|
223
|
+
artifact_path: managed.artifact.path,
|
|
224
|
+
mvid: managed.module?.mvid ?? null,
|
|
225
|
+
metadata_status: managed.metadata.status,
|
|
226
|
+
pinvoke_imports_total: managed.pinvoke_imports.total,
|
|
227
|
+
native_implementations_total: managed.native_implementations.total,
|
|
228
|
+
coverage_state: managed.coverage.state,
|
|
229
|
+
},
|
|
230
|
+
native_observations: {
|
|
231
|
+
total: input.native_observations.length,
|
|
232
|
+
accepted: native.accepted,
|
|
233
|
+
unsupported: native.unsupported,
|
|
234
|
+
symbols: native.symbols.length,
|
|
235
|
+
truncated: omittedNativeObservations > 0,
|
|
236
|
+
},
|
|
237
|
+
summary: {
|
|
238
|
+
...counts,
|
|
239
|
+
native_body_unresolved: nativeBodyUnresolved,
|
|
240
|
+
},
|
|
241
|
+
pinvoke_imports: [...pinvokeImports],
|
|
242
|
+
native_implementations: {
|
|
243
|
+
unresolved: nativeBodyUnresolved,
|
|
244
|
+
reason: "Managed metadata tokens and RVAs are not translated to native provider addresses by this workflow; C++/CLI, ReadyToRun, and native-body mappings require explicit provider-supported bridge evidence.",
|
|
245
|
+
},
|
|
246
|
+
coverage: {
|
|
247
|
+
status: coverageStatus,
|
|
248
|
+
omitted_native_observations: omittedNativeObservations,
|
|
249
|
+
omitted_candidates: omittedCandidates,
|
|
250
|
+
},
|
|
251
|
+
evidence_links: [
|
|
252
|
+
managedEvidence.evidence_id,
|
|
253
|
+
...input.native_observations
|
|
254
|
+
.slice(0, input.limits.max_native_observations)
|
|
255
|
+
.map(({ evidence_id: id }) => id),
|
|
256
|
+
],
|
|
257
|
+
limitations: [
|
|
258
|
+
"P/Invoke verification checks declared import names against supplied native export or function-name Evidence only.",
|
|
259
|
+
"A matching native symbol verifies that a candidate export/function was observed; it does not prove CLR binding, marshaling behavior, call reachability, or runtime loading.",
|
|
260
|
+
"Missing supplied native symbols are reported as unresolved, not proof that a dependency cannot exist.",
|
|
261
|
+
"Managed metadata tokens and method RVAs are not interpreted as native addresses.",
|
|
262
|
+
...(managed.coverage.state === "complete"
|
|
263
|
+
? []
|
|
264
|
+
: ["Managed boundary input is partial or unavailable."]),
|
|
265
|
+
...(native.unsupported === 0
|
|
266
|
+
? []
|
|
267
|
+
: [
|
|
268
|
+
"Some native Evidence operations were unsupported by this workflow.",
|
|
269
|
+
]),
|
|
270
|
+
],
|
|
271
|
+
};
|
|
272
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { evidenceSchema } from "./evidence.js";
|
|
3
|
+
import { cliMetadataGuidSchema } from "./managedArtifact.js";
|
|
4
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
5
|
+
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
6
|
+
const tokenSchema = z.string().regex(/^0x[0-9a-f]{8}$/u);
|
|
7
|
+
const boundedTextSchema = z.string().min(1).max(4_096);
|
|
8
|
+
const matchStatusSchema = z.enum([
|
|
9
|
+
"verified",
|
|
10
|
+
"inferred",
|
|
11
|
+
"unresolved",
|
|
12
|
+
"contradicted",
|
|
13
|
+
]);
|
|
14
|
+
const matchBasisSchema = z.enum([
|
|
15
|
+
"exact-export-name",
|
|
16
|
+
"exact-function-name",
|
|
17
|
+
"decorated-name-candidate",
|
|
18
|
+
"module-mismatch",
|
|
19
|
+
"no-native-candidate",
|
|
20
|
+
"unsupported-native-evidence",
|
|
21
|
+
]);
|
|
22
|
+
const nativeVerificationLimitsSchema = z.strictObject({
|
|
23
|
+
max_native_observations: z.number().int().min(1).max(50).default(20),
|
|
24
|
+
max_candidates_per_import: z.number().int().min(1).max(100).default(25),
|
|
25
|
+
});
|
|
26
|
+
const nativeSymbolSchema = z.strictObject({
|
|
27
|
+
evidence_id: evidenceIdSchema,
|
|
28
|
+
operation: z.string().min(1),
|
|
29
|
+
name: z.string().min(1),
|
|
30
|
+
address: z.string().nullable(),
|
|
31
|
+
module_name: z.string().nullable(),
|
|
32
|
+
module_path: z.string().nullable(),
|
|
33
|
+
source: z.enum(["macho-export", "function-dossier"]),
|
|
34
|
+
});
|
|
35
|
+
export const pinvokeVerificationSchema = z.strictObject({
|
|
36
|
+
item_id: z.string().regex(/^mnv_pinvoke_[a-f0-9]{64}$/u),
|
|
37
|
+
managed: z.strictObject({
|
|
38
|
+
token: tokenSchema,
|
|
39
|
+
member_token: tokenSchema.nullable(),
|
|
40
|
+
member_name: z.string().nullable(),
|
|
41
|
+
import_name: z.string().min(1),
|
|
42
|
+
import_scope_name: z.string().nullable(),
|
|
43
|
+
no_mangle: z.boolean(),
|
|
44
|
+
char_set: z.enum(["not-specified", "ansi", "unicode", "auto", "unknown"]),
|
|
45
|
+
call_convention: z.enum([
|
|
46
|
+
"not-specified",
|
|
47
|
+
"winapi",
|
|
48
|
+
"cdecl",
|
|
49
|
+
"stdcall",
|
|
50
|
+
"thiscall",
|
|
51
|
+
"fastcall",
|
|
52
|
+
"unknown",
|
|
53
|
+
]),
|
|
54
|
+
declaration_verification: z.literal("managed-declaration-only"),
|
|
55
|
+
}),
|
|
56
|
+
status: matchStatusSchema,
|
|
57
|
+
basis: matchBasisSchema,
|
|
58
|
+
confidence: z.enum(["observed", "inferred", "unknown"]),
|
|
59
|
+
matched_native: nativeSymbolSchema.nullable(),
|
|
60
|
+
candidates: z.array(nativeSymbolSchema).max(100),
|
|
61
|
+
evidence_links: z.array(evidenceIdSchema).min(1).max(51),
|
|
62
|
+
limitations: z.array(boundedTextSchema).max(100),
|
|
63
|
+
});
|
|
64
|
+
/** Authenticated managed boundary Evidence plus native observations. */
|
|
65
|
+
export const managedNativeVerificationInputSchema = z
|
|
66
|
+
.strictObject({
|
|
67
|
+
managed_boundaries: evidenceSchema,
|
|
68
|
+
native_observations: z.array(evidenceSchema).min(1).max(50),
|
|
69
|
+
limits: nativeVerificationLimitsSchema.default({
|
|
70
|
+
max_native_observations: 20,
|
|
71
|
+
max_candidates_per_import: 25,
|
|
72
|
+
}),
|
|
73
|
+
unknown_registry_approved: z.literal(true).optional(),
|
|
74
|
+
})
|
|
75
|
+
.superRefine((input, context) => {
|
|
76
|
+
const ids = new Set();
|
|
77
|
+
for (const [index, evidence] of input.native_observations.entries()) {
|
|
78
|
+
if (evidence.evidence_id === input.managed_boundaries.evidence_id) {
|
|
79
|
+
context.addIssue({
|
|
80
|
+
code: "custom",
|
|
81
|
+
path: ["native_observations", index],
|
|
82
|
+
message: "Native observation Evidence must be distinct from managed boundary Evidence",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (ids.has(evidence.evidence_id)) {
|
|
86
|
+
context.addIssue({
|
|
87
|
+
code: "custom",
|
|
88
|
+
path: ["native_observations", index],
|
|
89
|
+
message: "Native observation Evidence IDs must be unique",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
ids.add(evidence.evidence_id);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
/** Provider-neutral managed/native verification result. */
|
|
96
|
+
export const managedNativeVerificationResultSchema = z.strictObject({
|
|
97
|
+
schema_version: z.literal(1),
|
|
98
|
+
verification_id: z.string().regex(/^mnv_[a-f0-9]{64}$/u),
|
|
99
|
+
algorithm: z.strictObject({
|
|
100
|
+
name: z.literal("rea-managed-native-verification"),
|
|
101
|
+
version: z.literal(1),
|
|
102
|
+
token_identity: z.literal("build-local"),
|
|
103
|
+
token_to_address_mapping: z.literal("not-inferred"),
|
|
104
|
+
}),
|
|
105
|
+
managed_boundary: z.strictObject({
|
|
106
|
+
evidence_id: evidenceIdSchema,
|
|
107
|
+
artifact_sha256: digestSchema,
|
|
108
|
+
artifact_path: z.string().min(1),
|
|
109
|
+
mvid: cliMetadataGuidSchema.nullable(),
|
|
110
|
+
metadata_status: z.enum(["absent", "complete", "partial", "malformed"]),
|
|
111
|
+
pinvoke_imports_total: z.number().int().min(0),
|
|
112
|
+
native_implementations_total: z.number().int().min(0),
|
|
113
|
+
coverage_state: z.enum(["complete", "partial", "unavailable"]),
|
|
114
|
+
}),
|
|
115
|
+
native_observations: z.strictObject({
|
|
116
|
+
total: z.number().int().min(1),
|
|
117
|
+
accepted: z.number().int().min(0),
|
|
118
|
+
unsupported: z.number().int().min(0),
|
|
119
|
+
symbols: z.number().int().min(0),
|
|
120
|
+
truncated: z.boolean(),
|
|
121
|
+
}),
|
|
122
|
+
summary: z.strictObject({
|
|
123
|
+
verified: z.number().int().min(0),
|
|
124
|
+
inferred: z.number().int().min(0),
|
|
125
|
+
unresolved: z.number().int().min(0),
|
|
126
|
+
contradicted: z.number().int().min(0),
|
|
127
|
+
native_body_unresolved: z.number().int().min(0),
|
|
128
|
+
}),
|
|
129
|
+
pinvoke_imports: z.array(pinvokeVerificationSchema).max(50_000),
|
|
130
|
+
native_implementations: z.strictObject({
|
|
131
|
+
unresolved: z.number().int().min(0),
|
|
132
|
+
reason: boundedTextSchema,
|
|
133
|
+
}),
|
|
134
|
+
coverage: z.strictObject({
|
|
135
|
+
status: z.enum(["complete-within-inputs", "partial", "truncated"]),
|
|
136
|
+
omitted_native_observations: z.number().int().min(0),
|
|
137
|
+
omitted_candidates: z.number().int().min(0),
|
|
138
|
+
}),
|
|
139
|
+
evidence_links: z.array(evidenceIdSchema).min(2).max(51),
|
|
140
|
+
limitations: z.array(boundedTextSchema).max(1_000),
|
|
141
|
+
});
|
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import canonicalize from "canonicalize";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { evidenceSchema, parseEvidence } from "./evidence.js";
|
|
5
|
-
import { managedMemberInspectionSchema } from "./managedArtifact.js";
|
|
5
|
+
import { cliMetadataGuidSchema, managedMemberInspectionSchema, } from "./managedArtifact.js";
|
|
6
6
|
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
7
7
|
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
8
8
|
const tokenSchema = z.string().regex(/^0x[0-9a-f]{8}$/u);
|
|
@@ -73,7 +73,7 @@ export const managedReconstructionImportResultSchema = z.strictObject({
|
|
|
73
73
|
artifact_path: z.string().min(1),
|
|
74
74
|
byte_length: z.number().int().min(0),
|
|
75
75
|
module_name: z.string().nullable(),
|
|
76
|
-
mvid:
|
|
76
|
+
mvid: cliMetadataGuidSchema.nullable(),
|
|
77
77
|
metadata_status: z.enum(["absent", "complete", "partial", "malformed"]),
|
|
78
78
|
}),
|
|
79
79
|
decompiler: decompilerSchema.extend({
|
|
@@ -98,6 +98,82 @@ const sha256Json = (value) => {
|
|
|
98
98
|
throw new TypeError("Managed reconstruction canonicalization failed");
|
|
99
99
|
return createHash("sha256").update(serialized).digest("hex");
|
|
100
100
|
};
|
|
101
|
+
const countLines = (text) => text.length === 0 ? 0 : text.split(/\r\n|\r|\n/u).length;
|
|
102
|
+
const findObservedMethod = (members, candidate) => members.methods.items.find((item) => item.token === candidate.token &&
|
|
103
|
+
item.signature.raw_sha256 === candidate.signature_sha256 &&
|
|
104
|
+
item.body.status === "present" &&
|
|
105
|
+
item.body.normalized_il_sha256 !== null &&
|
|
106
|
+
candidate.normalized_il_sha256 !== null &&
|
|
107
|
+
item.body.normalized_il_sha256 === candidate.normalized_il_sha256);
|
|
108
|
+
const verifyTextSha256 = (candidate, textSha256) => {
|
|
109
|
+
if (candidate.reconstruction.text_sha256 !== undefined &&
|
|
110
|
+
candidate.reconstruction.text_sha256 !== textSha256)
|
|
111
|
+
throw new TypeError(`Reconstruction text hash mismatch for ${candidate.token}`);
|
|
112
|
+
};
|
|
113
|
+
const buildImportedMethod = (observed, candidate, textSha256) => ({
|
|
114
|
+
token: observed.token,
|
|
115
|
+
declaring_type: observed.declaring_type,
|
|
116
|
+
name: observed.name,
|
|
117
|
+
signature_sha256: observed.signature.raw_sha256,
|
|
118
|
+
normalized_il_sha256: observed.body.normalized_il_sha256,
|
|
119
|
+
body_sha256: observed.body.il_sha256,
|
|
120
|
+
il_size: observed.body.il_size,
|
|
121
|
+
reconstruction: {
|
|
122
|
+
kind: candidate.reconstruction.kind,
|
|
123
|
+
language: candidate.reconstruction.language,
|
|
124
|
+
text: candidate.reconstruction.text,
|
|
125
|
+
text_sha256: textSha256,
|
|
126
|
+
text_length: candidate.reconstruction.text.length,
|
|
127
|
+
line_count: countLines(candidate.reconstruction.text),
|
|
128
|
+
source_path: candidate.reconstruction.source_path ?? null,
|
|
129
|
+
start_line: candidate.reconstruction.start_line ?? null,
|
|
130
|
+
end_line: candidate.reconstruction.end_line ?? null,
|
|
131
|
+
},
|
|
132
|
+
validation: {
|
|
133
|
+
matched_static_member: true,
|
|
134
|
+
exact_build_required: true,
|
|
135
|
+
canonical_observation: false,
|
|
136
|
+
confidence_floor: "inference",
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
const buildReconstructionSummary = (methods) => ({
|
|
140
|
+
imported_methods: methods.length,
|
|
141
|
+
decompiled_csharp_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "decompiled-csharp").length,
|
|
142
|
+
decompiled_il_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "decompiled-il").length,
|
|
143
|
+
pseudocode_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "semantic-pseudocode").length,
|
|
144
|
+
total_text_bytes: methods.reduce((total, { reconstruction }) => total + reconstruction.text_length, 0),
|
|
145
|
+
});
|
|
146
|
+
const buildStaticObservation = (staticEvidence, members) => ({
|
|
147
|
+
evidence_id: staticEvidence.evidence_id,
|
|
148
|
+
artifact_sha256: members.artifact.sha256,
|
|
149
|
+
artifact_path: members.artifact.path,
|
|
150
|
+
byte_length: members.artifact.byte_length,
|
|
151
|
+
module_name: members.module?.name ?? null,
|
|
152
|
+
mvid: members.module?.mvid ?? null,
|
|
153
|
+
metadata_status: members.metadata.status,
|
|
154
|
+
});
|
|
155
|
+
const buildDecompilerRecord = (decompiler) => ({
|
|
156
|
+
...decompiler,
|
|
157
|
+
options_sha256: sha256Json(decompiler.options),
|
|
158
|
+
});
|
|
159
|
+
const RECONSTRUCTION_LIMITATIONS = [
|
|
160
|
+
"Decompiler output is imported as reconstruction evidence and analyst inference; metadata and IL observations remain canonical.",
|
|
161
|
+
"This operation did not execute, load, reflect over, debug, instrument, patch, or decompile the target artifact.",
|
|
162
|
+
"The imported reconstruction is valid only for the exact artifact SHA-256, MVID, method signature, and normalized IL shape recorded here.",
|
|
163
|
+
"Obfuscated names, decompiler variables, and control-flow restructuring are not treated as proof without separate validation.",
|
|
164
|
+
];
|
|
165
|
+
const buildReconstructionWithoutId = (input, staticEvidence, members, methods) => ({
|
|
166
|
+
schema_version: 1,
|
|
167
|
+
phase: "reconstruction-import",
|
|
168
|
+
executed: false,
|
|
169
|
+
static_observation: buildStaticObservation(staticEvidence, members),
|
|
170
|
+
decompiler: buildDecompilerRecord(input.decompiler),
|
|
171
|
+
summary: buildReconstructionSummary(methods),
|
|
172
|
+
methods: [...methods],
|
|
173
|
+
notes: input.notes,
|
|
174
|
+
evidence_links: [staticEvidence.evidence_id],
|
|
175
|
+
limitations: RECONSTRUCTION_LIMITATIONS,
|
|
176
|
+
});
|
|
101
177
|
/** Authenticate decompiler reconstruction against static IL Evidence. */
|
|
102
178
|
export const importManagedReconstruction = (input) => {
|
|
103
179
|
const staticEvidence = parseEvidence(input.static_members);
|
|
@@ -105,79 +181,16 @@ export const importManagedReconstruction = (input) => {
|
|
|
105
181
|
throw new TypeError("Evidence operation is not inspect_managed_members");
|
|
106
182
|
const members = managedMemberInspectionSchema.parse(staticEvidence.normalized_result);
|
|
107
183
|
const methods = input.methods.map((candidate) => {
|
|
108
|
-
const observed = members
|
|
109
|
-
item.signature.raw_sha256 === candidate.signature_sha256 &&
|
|
110
|
-
item.body.normalized_il_sha256 === candidate.normalized_il_sha256);
|
|
184
|
+
const observed = findObservedMethod(members, candidate);
|
|
111
185
|
if (observed === undefined)
|
|
112
186
|
throw new TypeError(`Reconstruction method lock ${candidate.token} does not match a static managed member observation`);
|
|
113
187
|
const textSha256 = sha256Text(candidate.reconstruction.text);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
throw new TypeError(`Reconstruction text hash mismatch for ${candidate.token}`);
|
|
117
|
-
return {
|
|
118
|
-
token: observed.token,
|
|
119
|
-
declaring_type: observed.declaring_type,
|
|
120
|
-
name: observed.name,
|
|
121
|
-
signature_sha256: observed.signature.raw_sha256,
|
|
122
|
-
normalized_il_sha256: observed.body.normalized_il_sha256,
|
|
123
|
-
body_sha256: observed.body.il_sha256,
|
|
124
|
-
il_size: observed.body.il_size,
|
|
125
|
-
reconstruction: {
|
|
126
|
-
kind: candidate.reconstruction.kind,
|
|
127
|
-
language: candidate.reconstruction.language,
|
|
128
|
-
text: candidate.reconstruction.text,
|
|
129
|
-
text_sha256: textSha256,
|
|
130
|
-
text_length: candidate.reconstruction.text.length,
|
|
131
|
-
line_count: countLines(candidate.reconstruction.text),
|
|
132
|
-
source_path: candidate.reconstruction.source_path ?? null,
|
|
133
|
-
start_line: candidate.reconstruction.start_line ?? null,
|
|
134
|
-
end_line: candidate.reconstruction.end_line ?? null,
|
|
135
|
-
},
|
|
136
|
-
validation: {
|
|
137
|
-
matched_static_member: true,
|
|
138
|
-
exact_build_required: true,
|
|
139
|
-
canonical_observation: false,
|
|
140
|
-
confidence_floor: "inference",
|
|
141
|
-
},
|
|
142
|
-
};
|
|
188
|
+
verifyTextSha256(candidate, textSha256);
|
|
189
|
+
return buildImportedMethod(observed, candidate, textSha256);
|
|
143
190
|
});
|
|
144
|
-
const withoutId =
|
|
145
|
-
schema_version: 1,
|
|
146
|
-
phase: "reconstruction-import",
|
|
147
|
-
executed: false,
|
|
148
|
-
static_observation: {
|
|
149
|
-
evidence_id: staticEvidence.evidence_id,
|
|
150
|
-
artifact_sha256: members.artifact.sha256,
|
|
151
|
-
artifact_path: members.artifact.path,
|
|
152
|
-
byte_length: members.artifact.byte_length,
|
|
153
|
-
module_name: members.module?.name ?? null,
|
|
154
|
-
mvid: members.module?.mvid ?? null,
|
|
155
|
-
metadata_status: members.metadata.status,
|
|
156
|
-
},
|
|
157
|
-
decompiler: {
|
|
158
|
-
...input.decompiler,
|
|
159
|
-
options_sha256: sha256Json(input.decompiler.options),
|
|
160
|
-
},
|
|
161
|
-
summary: {
|
|
162
|
-
imported_methods: methods.length,
|
|
163
|
-
decompiled_csharp_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "decompiled-csharp").length,
|
|
164
|
-
decompiled_il_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "decompiled-il").length,
|
|
165
|
-
pseudocode_methods: methods.filter(({ reconstruction }) => reconstruction.kind === "semantic-pseudocode").length,
|
|
166
|
-
total_text_bytes: methods.reduce((total, { reconstruction }) => total + reconstruction.text_length, 0),
|
|
167
|
-
},
|
|
168
|
-
methods,
|
|
169
|
-
notes: input.notes,
|
|
170
|
-
evidence_links: [staticEvidence.evidence_id],
|
|
171
|
-
limitations: [
|
|
172
|
-
"Decompiler output is imported as reconstruction evidence and analyst inference; metadata and IL observations remain canonical.",
|
|
173
|
-
"This operation did not execute, load, reflect over, debug, instrument, patch, or decompile the target artifact.",
|
|
174
|
-
"The imported reconstruction is valid only for the exact artifact SHA-256, MVID, method signature, and normalized IL shape recorded here.",
|
|
175
|
-
"Obfuscated names, decompiler variables, and control-flow restructuring are not treated as proof without separate validation.",
|
|
176
|
-
],
|
|
177
|
-
};
|
|
191
|
+
const withoutId = buildReconstructionWithoutId(input, staticEvidence, members, methods);
|
|
178
192
|
return managedReconstructionImportResultSchema.parse({
|
|
179
193
|
...withoutId,
|
|
180
194
|
reconstruction_id: `mre_${sha256Json(withoutId)}`,
|
|
181
195
|
});
|
|
182
196
|
};
|
|
183
|
-
const countLines = (text) => text.length === 0 ? 0 : text.split(/\r\n|\r|\n/u).length;
|
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import canonicalize from "canonicalize";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { evidenceSchema, parseEvidence } from "./evidence.js";
|
|
5
|
-
import { managedMemberInspectionSchema } from "./managedArtifact.js";
|
|
5
|
+
import { cliMetadataGuidSchema, managedMemberInspectionSchema, } from "./managedArtifact.js";
|
|
6
6
|
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
7
7
|
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
8
8
|
const tokenSchema = z.string().regex(/^0x[0-9a-f]{8}$/u);
|
|
@@ -61,7 +61,7 @@ export const managedRuntimeCorrelationResultSchema = z.strictObject({
|
|
|
61
61
|
artifact_path: z.string().min(1),
|
|
62
62
|
byte_length: z.number().int().min(0),
|
|
63
63
|
module_name: z.string().nullable(),
|
|
64
|
-
mvid:
|
|
64
|
+
mvid: cliMetadataGuidSchema.nullable(),
|
|
65
65
|
metadata_status: z.enum(["absent", "complete", "partial", "malformed"]),
|
|
66
66
|
}),
|
|
67
67
|
method_lock: z.strictObject({
|
|
@@ -72,7 +72,13 @@ export const managedRuntimeCorrelationResultSchema = z.strictObject({
|
|
|
72
72
|
normalized_il_sha256: digestSchema.nullable(),
|
|
73
73
|
body_sha256: digestSchema.nullable(),
|
|
74
74
|
il_size: z.number().int().min(0),
|
|
75
|
-
body_status: z.enum([
|
|
75
|
+
body_status: z.enum([
|
|
76
|
+
"present",
|
|
77
|
+
"partial",
|
|
78
|
+
"absent",
|
|
79
|
+
"malformed",
|
|
80
|
+
"too-large",
|
|
81
|
+
]),
|
|
76
82
|
exact_build_required: z.literal(true),
|
|
77
83
|
}),
|
|
78
84
|
requested_runtime: z.strictObject({
|
|
@@ -109,6 +115,9 @@ export const planManagedRuntimeCorrelation = (input, executablePath, permissionG
|
|
|
109
115
|
const members = managedMemberInspectionSchema.parse(staticEvidence.normalized_result);
|
|
110
116
|
const method = members.methods.items.find((item) => item.token === input.method.token &&
|
|
111
117
|
item.signature.raw_sha256 === input.method.signature_sha256 &&
|
|
118
|
+
item.body.status === "present" &&
|
|
119
|
+
item.body.normalized_il_sha256 !== null &&
|
|
120
|
+
input.method.normalized_il_sha256 !== null &&
|
|
112
121
|
item.body.normalized_il_sha256 === input.method.normalized_il_sha256);
|
|
113
122
|
if (method === undefined)
|
|
114
123
|
throw new TypeError("Requested method lock does not match a static managed member observation");
|