rea-agents 5.0.0 → 6.0.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 +157 -650
- package/bridge/mitmproxy/capture.py +210 -0
- package/bridge/native/rea_lldb_tracer.py +303 -0
- package/bridge/process/ProcessRunTokenReader.swift +263 -0
- package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
- package/bridge/pwndbg/core_context.py +101 -0
- package/bridge/pwndbg/launch.py +39 -0
- package/bridge/pwndbg/launch_impl.py +34 -0
- package/bridge/pwntools/decoder_runtime.py +59 -0
- package/bridge/pwntools/layout.py +39 -0
- package/bridge/pwntools/layout_impl.py +309 -0
- package/bridge/pwntools/recorded_crash.py +39 -0
- package/bridge/pwntools/recorded_crash_impl.py +143 -0
- package/dist/android/JadxProvider.js +1 -0
- package/dist/application/CapabilityInventory.js +21 -0
- package/dist/application/DirectAnalysis.js +97 -23
- package/dist/application/EvidenceBundleFiles.js +1 -1
- package/dist/application/ReconstructionObligationCandidates.js +5 -1
- package/dist/application/WebNetworkCapturePort.js +1 -0
- package/dist/application/WebNetworkCaptureService.js +132 -0
- package/dist/application/WindowsCapabilities.js +1 -1
- package/dist/application/binary/AnalysisSnapshotCache.js +49 -6
- package/dist/application/binary/BinarySession.js +38 -10
- package/dist/application/binary/BinarySessionOpen.js +16 -3
- package/dist/application/binary/BinarySessionRecords.js +20 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +57 -0
- package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +60 -0
- package/dist/application/evm/EvmInterfacePort.js +1 -0
- package/dist/application/evm/EvmInterfaceService.js +62 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +15 -2
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +42 -23
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +74 -24
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +23 -10
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +145 -70
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +5 -5
- package/dist/application/{ProcessCli.js → process/ProcessCli.js} +10 -10
- package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +4 -4
- package/dist/artifacts/ArtifactProvider.js +30 -3
- package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
- package/dist/artifacts/ZipArtifactReader.js +3 -0
- package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
- package/dist/artifacts/apple/MachoLoadCommandReader.js +294 -0
- package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
- package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +3 -3
- package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
- package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
- package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +3 -3
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
- package/dist/artifacts/readStableArtifact.js +20 -4
- package/dist/browser/CdpCaptureEventHandlers.js +90 -2
- package/dist/browser/CdpCaptureEvents.js +9 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +12 -3
- package/dist/browser/history/CaptureFailures.js +101 -0
- package/dist/browser/history/CaptureFormatError.js +10 -0
- package/dist/browser/history/CaptureRedaction.js +65 -0
- package/dist/browser/history/CaptureRelease.js +12 -0
- package/dist/browser/history/HarCapture.js +165 -0
- package/dist/browser/history/HarCaptureAdapter.js +20 -0
- package/dist/browser/history/HarCaptureProcess.js +57 -0
- package/dist/browser/history/HarJson.js +91 -0
- package/dist/browser/history/HarSchema.js +72 -0
- package/dist/browser/history/HistoricalCaptureDecoder.js +186 -0
- package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
- package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
- package/dist/cli/artifactCommands.js +26 -1
- package/dist/cli/binaryDiagnosticsCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +8 -8
- package/dist/cli/electronCommands.js +16 -9
- package/dist/cli/evmCommands.js +24 -0
- package/dist/cli/firmwareCommands.js +6 -3
- package/dist/cli/javascriptApplicationAnalysis.js +16 -3
- package/dist/cli/jsonOutput.js +133 -0
- package/dist/cli/nativeCallCommands.js +35 -0
- package/dist/cli/processCommands.js +1 -1
- package/dist/cli/streamedJsonOutput.js +56 -0
- package/dist/cli/utilityCommands.js +2 -0
- package/dist/cli/webNetworkCaptureCommands.js +40 -0
- package/dist/cli.js +9 -3
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +6 -0
- package/dist/cliJsonInput.js +30 -1
- package/dist/cliOutput.js +21 -6
- package/dist/composition/binaryDiagnostics.js +8 -0
- package/dist/composition/evm.js +4 -0
- package/dist/composition/webNetworkCaptures.js +6 -0
- package/dist/contracts/artifactToolContracts.js +6 -0
- package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
- package/dist/contracts/browserToolContracts.js +4 -3
- package/dist/contracts/errorSchemas.js +8 -1
- package/dist/contracts/evm/evmToolContracts.js +20 -0
- package/dist/contracts/investigationExamples.js +2 -2
- package/dist/contracts/managed/managedToolContracts.js +7 -3
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
- package/dist/contracts/native/nativeToolContracts.js +17 -1
- package/dist/contracts/officialToolContracts.js +12 -9
- package/dist/contracts/process/processCaptureExample.js +2 -0
- package/dist/contracts/sessionLifecycleInputs.js +22 -5
- package/dist/contracts/sessionStatusContract.js +10 -2
- package/dist/contracts/sessionToolContracts.js +8 -1
- package/dist/contracts/sessionToolSchemas.js +10 -3
- package/dist/contracts/toolContractExamples.js +1 -1
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +30 -0
- package/dist/contracts/toolOutputSchemaGroups.js +5 -1
- package/dist/contracts/toolOutputSchemaPrimitives.js +1 -1
- package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
- package/dist/domain/analysisErrorBase.js +15 -0
- package/dist/domain/analysisErrorCore.js +59 -5
- package/dist/domain/analysisErrorPresentation.js +29 -1
- package/dist/domain/analysisErrorProjection.js +52 -2
- package/dist/domain/analysisSnapshot.js +166 -2
- package/dist/domain/apple/dyldPaths.js +81 -0
- package/dist/domain/apple/dylibResolution.js +367 -0
- package/dist/domain/apple/dylibResolutionFindings.js +75 -0
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/browserObservation.js +1 -1
- package/dist/domain/browserObservationSchemas.js +13 -0
- package/dist/domain/browserScenarioValues.js +9 -2
- package/dist/domain/callPathSchemas.js +1 -1
- package/dist/domain/canonicalDigest.js +13 -1
- package/dist/domain/changedBehavior.js +3 -3
- package/dist/domain/comparisonStatus.js +2 -30
- package/dist/domain/conformanceTrustGate.js +0 -16
- package/dist/domain/evidence.js +17 -5
- package/dist/domain/evm/evmInterface.js +63 -0
- package/dist/domain/explicitSensitiveFailure.js +92 -0
- package/dist/domain/explicitSensitiveValues.js +10 -0
- package/dist/domain/firmware/firmwareAnalysis.js +8 -1
- package/dist/domain/javascript/electronActiveObservation.js +9 -4
- package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
- package/dist/domain/javascript/javascriptSemanticGraph.js +21 -5
- package/dist/domain/jsonValue.js +4 -0
- package/dist/domain/localPath.js +2 -0
- package/dist/domain/native/binaryLayout.js +357 -0
- package/dist/domain/native/nativeCallObservation.js +164 -0
- package/dist/domain/native/objcSwiftMetadata.js +0 -39
- package/dist/domain/native/recordedCrash.js +266 -0
- package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
- package/dist/domain/{processCapture.js → process/processCapture.js} +139 -2
- package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
- package/dist/domain/process/processCaptureParsing.js +54 -0
- package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
- package/dist/domain/{processComparison.js → process/processComparison.js} +1 -1
- package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
- package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
- package/dist/domain/providerSelectionError.js +4 -2
- package/dist/domain/reconstructionVerification.js +3 -3
- package/dist/domain/reconstructionVerificationSchemas.js +1 -1
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +3 -3
- package/dist/domain/webCaptureDiff.js +1 -0
- package/dist/domain/webNetworkCapture.js +118 -0
- package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
- package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
- package/dist/dotnet/ManagedMemberInspector.js +4 -2
- package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
- package/dist/dotnet/ManagedMemberRows.js +14 -3
- package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
- package/dist/dotnet/ManagedMetadataInventory.js +38 -28
- package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
- package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
- package/dist/dotnet/ManagedPeReader.js +11 -0
- package/dist/evm/EvmBytecodeCarrier.js +21 -0
- package/dist/evm/EvmWorkerLimits.js +40 -0
- package/dist/evm/EvmoleFailures.js +126 -0
- package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
- package/dist/evm/EvmoleInterfaceProvider.js +273 -0
- package/dist/evm/EvmoleInterfaceWorker.js +87 -0
- package/dist/evm/EvmoleRelease.js +16 -0
- package/dist/firmware/FirmwareCommand.js +1 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraLauncher.js +1 -0
- package/dist/ghidra/GhidraProvider.js +2 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +1 -1
- package/dist/hopper/BridgeLauncher.js +2 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
- package/dist/javascript/recovery/WakaruCommand.js +3 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +1 -0
- package/dist/native/CommandRunner.js +2 -1
- package/dist/native/LldbCallTracer.js +278 -0
- package/dist/native/NativeCallObservation.js +135 -0
- package/dist/native/NativeMacOSProvider.js +19 -3
- package/dist/native/NativeMacOSProviderMetadata.js +8 -3
- package/dist/native/pwndbg/PwndbgCoreContext.js +160 -0
- package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
- package/dist/native/pwntools/PwntoolsFailures.js +180 -0
- package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
- package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
- package/dist/native/pwntools/PwntoolsRelease.js +19 -0
- package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
- package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +101 -0
- package/dist/process/DarwinProcessRunTokenReader.js +294 -0
- package/dist/process/OwnedCommand.js +113 -0
- package/dist/process/ProcessOwnership.js +263 -33
- package/dist/process/ProcessOwnershipObservation.js +161 -24
- package/dist/process/ProviderProcess.js +30 -3
- package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
- package/dist/{application → process/capture}/ProcessCaptureError.js +17 -1
- package/dist/process/capture/ProcessCaptureLifecycle.js +615 -0
- package/dist/{application → process/capture}/ProcessHarness.js +195 -29
- package/dist/{application → process/capture}/ProcessSampling.js +2 -2
- package/dist/server/createServer.js +22 -0
- package/dist/server/promptCompletion.js +10 -3
- package/dist/server/registerBinaryDiagnosticsTools.js +17 -0
- package/dist/server/registerEvidenceTools.js +1 -1
- package/dist/server/registerEvmTools.js +17 -0
- package/dist/server/registerProcessComparisonTool.js +1 -1
- package/dist/server/registerRecordedCrashTools.js +17 -0
- package/dist/server/registerSessionTools.js +2 -2
- package/dist/server/registerWebNetworkCaptureTool.js +28 -0
- package/dist/server/sessionAvailabilityPolicy.js +3 -0
- package/dist/server/sessionToolPolicies.js +1 -1
- package/dist/server/toolResult.js +1 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +37 -9
- package/scripts/rea.mjs +11 -3
- package/skills/reverse-engineer-anything/SKILL.md +23 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
- package/third_party/README.md +60 -0
- package/third_party/evmole/LICENSE +21 -0
- package/third_party/evmole/README.md +22 -0
- package/third_party/pwndbg/LICENSE.md +21 -0
- package/third_party/pwndbg/README.md +23 -0
- package/third_party/pwntools/README.md +40 -0
- package/dist/application/AuthorizedArtifactInventory.js +0 -7
- package/dist/application/ProcessCaptureLifecycle.js +0 -299
- package/dist/application/StoreFileLock.js +0 -124
- package/dist/contracts/processCaptureExample.js +0 -2
- package/dist/domain/bytecodeProvider.js +0 -178
- package/dist/domain/customProtocolCapture.js +0 -137
- package/dist/domain/eventProcessTree.js +0 -225
- package/dist/domain/mobileApplicationInvestigation.js +0 -159
- package/dist/domain/packageAnalysis.js +0 -123
- package/dist/domain/peInspection.js +0 -197
- package/dist/domain/processCaptureParsing.js +0 -21
- package/dist/domain/protocolCapture.js +0 -217
- package/dist/domain/runtimeIdentification.js +0 -212
- package/dist/generatedMcpToolCatalog.js +0 -37
- /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
- /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
- /package/dist/domain/{processScenario.js → process/processScenario.js} +0 -0
- /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
- /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
- /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
- /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
- /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
- /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
- /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
- /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
- /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
|
@@ -27,7 +27,31 @@ const uniqueIssues = (issues) => [
|
|
|
27
27
|
...new Map(issues.map((issue) => [JSON.stringify(issue), issue])).values(),
|
|
28
28
|
];
|
|
29
29
|
const heapExtent = (layout) => Math.max(layout.strings.size, layout.blob.size);
|
|
30
|
-
const
|
|
30
|
+
const validateIdentityTableCounts = (layout, issues) => {
|
|
31
|
+
const moduleRows = layout.table(0)?.rowCount ?? 0;
|
|
32
|
+
if (moduleRows !== 1)
|
|
33
|
+
issues.push({
|
|
34
|
+
code: "invalid-row",
|
|
35
|
+
scope: "metadata.Module",
|
|
36
|
+
offset: layout.table(0)?.offset ?? null,
|
|
37
|
+
detail: `Module table must contain exactly one row; found ${String(moduleRows)}`,
|
|
38
|
+
});
|
|
39
|
+
const assemblyRows = layout.table(32)?.rowCount ?? 0;
|
|
40
|
+
if (assemblyRows > 1)
|
|
41
|
+
issues.push({
|
|
42
|
+
code: "invalid-row",
|
|
43
|
+
scope: "metadata.Assembly",
|
|
44
|
+
offset: layout.table(32)?.offset ?? null,
|
|
45
|
+
detail: `Assembly table can contain at most one row; found ${String(assemblyRows)}`,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const readReferences = (bytes, layout, issues) => {
|
|
49
|
+
const references = readRows(layout.table(35), (row) => safeRead(() => readAssemblyReference(bytes, layout, row, heapExtent(layout)), issues));
|
|
50
|
+
return {
|
|
51
|
+
references,
|
|
52
|
+
referenceNames: [...new Set(references.map(({ name }) => name))].sort(),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
31
55
|
const readResources = ({ bytes, layout, resourceDirectory, issues, }) => readRows(layout.table(40), (row) => safeRead(() => readResource({
|
|
32
56
|
bytes,
|
|
33
57
|
layout,
|
|
@@ -35,53 +59,39 @@ const readResources = ({ bytes, layout, resourceDirectory, issues, }) => readRow
|
|
|
35
59
|
directory: resourceDirectory,
|
|
36
60
|
issues,
|
|
37
61
|
}), issues));
|
|
38
|
-
const readAttributes = (bytes, layout, issues) =>
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const reference = safeRead(() => readAssemblyReference(bytes, layout, row, heapExtent(layout)), issues);
|
|
44
|
-
if (reference !== undefined)
|
|
45
|
-
names.push(reference.name);
|
|
46
|
-
}
|
|
47
|
-
return names;
|
|
48
|
-
};
|
|
49
|
-
const collectTargetFrameworks = (bytes, layout, issues) => {
|
|
50
|
-
const targetFrameworks = [];
|
|
51
|
-
const attributeTable = layout.table(12);
|
|
52
|
-
for (let row = 1; row <= (attributeTable?.rowCount ?? 0); row += 1) {
|
|
53
|
-
const attribute = safeRead(() => readCustomAttribute(bytes, layout, row, heapExtent(layout)), issues);
|
|
54
|
-
if (attribute?.parent_token === metadataToken(32, 1) &&
|
|
62
|
+
const readAttributes = (bytes, layout, issues) => {
|
|
63
|
+
const attributes = readRows(layout.table(12), (row) => safeRead(() => readCustomAttribute(bytes, layout, row, heapExtent(layout)), issues));
|
|
64
|
+
const targetFrameworks = new Set();
|
|
65
|
+
for (const attribute of attributes) {
|
|
66
|
+
if (attribute.parent_token === metadataToken(32, 1) &&
|
|
55
67
|
attribute.type_name ===
|
|
56
68
|
"System.Runtime.Versioning.TargetFrameworkAttribute" &&
|
|
57
|
-
attribute.decoded_fixed_string !== null
|
|
58
|
-
|
|
59
|
-
targetFrameworks.push(attribute.decoded_fixed_string);
|
|
69
|
+
attribute.decoded_fixed_string !== null)
|
|
70
|
+
targetFrameworks.add(attribute.decoded_fixed_string);
|
|
60
71
|
}
|
|
61
|
-
return targetFrameworks;
|
|
72
|
+
return { attributes, targetFrameworks: [...targetFrameworks].sort() };
|
|
62
73
|
};
|
|
63
74
|
/** Inventory identity tables without CLR reflection or execution. */
|
|
64
75
|
export const readManagedMetadataInventory = (bytes, layout, resourceDirectory) => {
|
|
65
76
|
const issues = [];
|
|
77
|
+
validateIdentityTableCounts(layout, issues);
|
|
66
78
|
const module = safeRead(() => readModule(bytes, layout, heapExtent(layout)), issues) ??
|
|
67
79
|
null;
|
|
68
80
|
const assembly = safeRead(() => readAssembly(bytes, layout, heapExtent(layout)), issues) ??
|
|
69
81
|
null;
|
|
70
|
-
const references = readReferences(bytes, layout, issues);
|
|
82
|
+
const { references, referenceNames } = readReferences(bytes, layout, issues);
|
|
71
83
|
const resources = readResources({
|
|
72
84
|
bytes,
|
|
73
85
|
layout,
|
|
74
86
|
resourceDirectory,
|
|
75
87
|
issues,
|
|
76
88
|
});
|
|
77
|
-
const attributes = readAttributes(bytes, layout, issues);
|
|
78
|
-
const referenceNames = collectReferenceNames(bytes, layout, issues);
|
|
79
|
-
const targetFrameworks = collectTargetFrameworks(bytes, layout, issues);
|
|
89
|
+
const { attributes, targetFrameworks } = readAttributes(bytes, layout, issues);
|
|
80
90
|
return {
|
|
81
91
|
module,
|
|
82
92
|
assembly,
|
|
83
|
-
targetFrameworks
|
|
84
|
-
referenceNames
|
|
93
|
+
targetFrameworks,
|
|
94
|
+
referenceNames,
|
|
85
95
|
references,
|
|
86
96
|
resources,
|
|
87
97
|
attributes,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { metadataRowOffset, } from "./ManagedMetadataLayout.js";
|
|
2
|
-
import { metadataRowCursor, metadataCodedToken, metadataToken, readMetadataBlob, readMetadataGuid, readMetadataString, sha256Bytes, strongNameToken, } from "./ManagedMetadataHeaps.js";
|
|
2
|
+
import { metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, metadataToken, readMetadataBlob, readMetadataGuid, readMetadataString, sha256Bytes, strongNameToken, } from "./ManagedMetadataHeaps.js";
|
|
3
3
|
import { managedFailure } from "./ManagedReaderFailure.js";
|
|
4
4
|
const publicKeyIdentity = (bytes, kind) => ({
|
|
5
5
|
kind: bytes.length === 0 ? "none" : kind,
|
|
@@ -212,23 +212,28 @@ const decodeFixedString = (blob) => {
|
|
|
212
212
|
export const readCustomAttribute = (bytes, layout, row, heapExtent) => {
|
|
213
213
|
const cursor = metadataRowCursor(bytes, layout, 12, row);
|
|
214
214
|
const parentRaw = cursor.readIndex(layout.codedIndexSize("HasCustomAttribute"));
|
|
215
|
+
const typeOffset = cursor.offset;
|
|
215
216
|
const typeRaw = cursor.readIndex(layout.codedIndexSize("CustomAttributeType"));
|
|
216
217
|
const value = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), heapExtent);
|
|
217
218
|
const parent = metadataCodedToken(parentRaw, 5, [
|
|
218
219
|
6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
|
|
219
220
|
44, 43,
|
|
220
|
-
]);
|
|
221
|
+
], layout.rowCounts);
|
|
222
|
+
const parentReason = metadataCodedTokenInvalidReason(parentRaw, 5, [
|
|
223
|
+
6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
|
|
224
|
+
44, 43,
|
|
225
|
+
], layout.rowCounts);
|
|
221
226
|
if (parent === null)
|
|
222
|
-
throw managedFailure("invalid-row",
|
|
227
|
+
throw managedFailure("invalid-row", `metadata.CustomAttribute:${metadataToken(12, row)}`, `CustomAttribute parent coded index 0x${parentRaw.toString(16)} is invalid${parentReason === null ? " because the required parent is null" : `: ${parentReason}`}`, cursor.start);
|
|
228
|
+
const typeReason = metadataCodedTokenInvalidReason(typeRaw, 3, [undefined, undefined, 6, 10], layout.rowCounts);
|
|
229
|
+
if (typeReason !== null || typeRaw === 0)
|
|
230
|
+
throw managedFailure("invalid-row", `metadata.CustomAttribute:${metadataToken(12, row)}`, typeReason === null
|
|
231
|
+
? "CustomAttribute constructor coded index 0x0 is null, but Type must reference a MethodDef or MemberRef row"
|
|
232
|
+
: `CustomAttribute constructor coded index 0x${typeRaw.toString(16)} is invalid: ${typeReason}`, typeOffset);
|
|
223
233
|
const typeName = attributeTypeName(bytes, layout, typeRaw, heapExtent);
|
|
224
234
|
return {
|
|
225
235
|
parent_token: parent,
|
|
226
|
-
constructor_token: metadataCodedToken(typeRaw, 3, [
|
|
227
|
-
undefined,
|
|
228
|
-
undefined,
|
|
229
|
-
6,
|
|
230
|
-
10,
|
|
231
|
-
]),
|
|
236
|
+
constructor_token: metadataCodedToken(typeRaw, 3, [undefined, undefined, 6, 10], layout.rowCounts),
|
|
232
237
|
type_name: typeName,
|
|
233
238
|
value_length: value.length,
|
|
234
239
|
value_sha256: sha256Bytes(value),
|
|
@@ -244,8 +249,17 @@ export const readResource = ({ bytes, layout, row, directory, issues, }) => {
|
|
|
244
249
|
const declaredOffset = cursor.readUInt32();
|
|
245
250
|
const flags = cursor.readUInt32();
|
|
246
251
|
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), Math.max(layout.strings.size, layout.blob.size));
|
|
252
|
+
const implementationOffset = cursor.offset;
|
|
247
253
|
const implementationRaw = cursor.readIndex(layout.codedIndexSize("Implementation"));
|
|
248
|
-
const implementationToken = metadataCodedToken(implementationRaw, 2, [38, 35, 39]);
|
|
254
|
+
const implementationToken = metadataCodedToken(implementationRaw, 2, [38, 35, 39], layout.rowCounts);
|
|
255
|
+
const implementationReason = metadataCodedTokenInvalidReason(implementationRaw, 2, [38, 35, 39], layout.rowCounts);
|
|
256
|
+
if (implementationReason !== null)
|
|
257
|
+
issues.push({
|
|
258
|
+
code: "invalid-row",
|
|
259
|
+
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
260
|
+
offset: implementationOffset,
|
|
261
|
+
detail: `ManifestResource implementation coded index 0x${implementationRaw.toString(16)} is invalid: ${implementationReason}`,
|
|
262
|
+
});
|
|
249
263
|
let dataLength = null;
|
|
250
264
|
let dataSha256 = null;
|
|
251
265
|
if (implementationRaw === 0) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decodeInstructions, parseExceptionRegions, } from "./ManagedMemberInstructionDecoder.js";
|
|
2
|
+
import { validateExceptionRegionRanges } from "./ManagedExceptionRegionValidation.js";
|
|
2
3
|
import { sha256Bytes } from "./ManagedMetadataHeaps.js";
|
|
3
4
|
const bodyStatus = (decodedIssue, truncatedInstructions, exceptionRegions) => {
|
|
4
5
|
if (decodedIssue !== null || exceptionRegions?.status === "malformed")
|
|
@@ -38,6 +39,7 @@ const readMethodBodyHeader = (bytes, offset) => {
|
|
|
38
39
|
localSig: bytes.readUInt32LE(offset + 8),
|
|
39
40
|
};
|
|
40
41
|
};
|
|
42
|
+
const readExceptionRegions = (bytes, sectionOffset, methodEnd, ilSize, instructionOffsets) => validateExceptionRegionRanges(parseExceptionRegions(bytes, sectionOffset, methodEnd), ilSize, instructionOffsets);
|
|
41
43
|
/** Decode admitted managed CIL, retaining unavailable implementation metadata as partial. */
|
|
42
44
|
export const methodBody = (bytes, pe, rva, implementation = {
|
|
43
45
|
implFlags: 0,
|
|
@@ -50,7 +52,11 @@ export const methodBody = (bytes, pe, rva, implementation = {
|
|
|
50
52
|
return emptyMethodBody(rva, "partial", "CIL decoding is unavailable for native, runtime, unmanaged, or P/Invoke implementations");
|
|
51
53
|
try {
|
|
52
54
|
const offset = pe.rvaToOffset(rva, 1, "method.body");
|
|
55
|
+
const methodExtent = pe.rvaAvailableBytes(rva, "method.body");
|
|
53
56
|
const header = readMethodBodyHeader(bytes, offset);
|
|
57
|
+
if (header.size > methodExtent ||
|
|
58
|
+
header.ilSize > methodExtent - header.size)
|
|
59
|
+
throw new RangeError("Method body leaves file-backed PE section data");
|
|
54
60
|
const ilOffset = offset + header.size;
|
|
55
61
|
if (ilOffset > bytes.length - header.ilSize)
|
|
56
62
|
throw new RangeError("Method IL bytes leave artifact");
|
|
@@ -76,7 +82,7 @@ export const methodBody = (bytes, pe, rva, implementation = {
|
|
|
76
82
|
const methodEnd = ilOffset + header.ilSize;
|
|
77
83
|
const sectionOffset = (methodEnd + 3) & ~3;
|
|
78
84
|
const exceptionRegions = header.format === "fat" && (header.flags & 8) !== 0
|
|
79
|
-
?
|
|
85
|
+
? readExceptionRegions(bytes, sectionOffset, offset + methodExtent, header.ilSize, decoded.instructionStarts)
|
|
80
86
|
: null;
|
|
81
87
|
const status = bodyStatus(decoded.issue, decoded.truncated, exceptionRegions);
|
|
82
88
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { managedNativeBoundaryInspectionSchema, } from "../domain/managed/managedArtifact.js";
|
|
2
2
|
import {} from "./ManagedMetadataLayout.js";
|
|
3
|
-
import { metadataRowCursor, metadataCodedToken, metadataToken, readMetadataString, } from "./ManagedMetadataHeaps.js";
|
|
3
|
+
import { metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, metadataToken, readMetadataString, } from "./ManagedMetadataHeaps.js";
|
|
4
4
|
import { managedTableRowCounts } from "./ManagedMetadataInventory.js";
|
|
5
5
|
const flagsHex = (value) => `0x${value.toString(16).padStart(4, "0")}`;
|
|
6
6
|
export const parseModuleRefs = (bytes, layout, heapExtent) => {
|
|
@@ -61,14 +61,26 @@ export const parseMethods = (bytes, layout, heapExtent) => {
|
|
|
61
61
|
}
|
|
62
62
|
return methods;
|
|
63
63
|
};
|
|
64
|
-
export const parseImplMaps = ({ bytes, layout, heapExtent, modules, members, }) => {
|
|
64
|
+
export const parseImplMaps = ({ bytes, layout, heapExtent, modules, members, issues, }) => {
|
|
65
65
|
const moduleNames = new Map(modules.map((module) => [module.token, module]));
|
|
66
66
|
const imports = [];
|
|
67
67
|
const table = layout.table(28);
|
|
68
68
|
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
69
69
|
const cursor = metadataRowCursor(bytes, layout, 28, row);
|
|
70
70
|
const mappingFlags = cursor.readUInt16();
|
|
71
|
-
const
|
|
71
|
+
const memberForwardedOffset = cursor.offset;
|
|
72
|
+
const memberForwardedRaw = cursor.readIndex(layout.codedIndexSize("MemberForwarded"));
|
|
73
|
+
const memberForwardedReason = metadataCodedTokenInvalidReason(memberForwardedRaw, 1, [4, 6], layout.rowCounts);
|
|
74
|
+
if (memberForwardedReason !== null || memberForwardedRaw === 0)
|
|
75
|
+
issues.push({
|
|
76
|
+
code: "invalid-row",
|
|
77
|
+
scope: `metadata.ImplMap:${metadataToken(28, row)}`,
|
|
78
|
+
offset: memberForwardedOffset,
|
|
79
|
+
detail: memberForwardedReason === null
|
|
80
|
+
? "ImplMap MemberForwarded coded index 0x0 is null, but the column must reference a Field or MethodDef row"
|
|
81
|
+
: `ImplMap MemberForwarded coded index 0x${memberForwardedRaw.toString(16)} is invalid: ${memberForwardedReason}`,
|
|
82
|
+
});
|
|
83
|
+
const memberToken = metadataCodedToken(memberForwardedRaw, 1, [4, 6], layout.rowCounts);
|
|
72
84
|
const importName = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), heapExtent);
|
|
73
85
|
const importScopeRow = cursor.readIndex(layout.tableIndexSize(26));
|
|
74
86
|
const importScopeToken = importScopeRow === 0 ? null : metadataToken(26, importScopeRow);
|
|
@@ -89,6 +89,7 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
const heapExtent = Math.max(layout.strings.size, layout.blob.size);
|
|
92
|
+
const issues = [...inventory.issues];
|
|
92
93
|
const moduleRefs = parseModuleRefs(bytes, layout, heapExtent);
|
|
93
94
|
const members = new Map([
|
|
94
95
|
...parseFields(bytes, layout, heapExtent),
|
|
@@ -100,6 +101,7 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
|
|
|
100
101
|
heapExtent,
|
|
101
102
|
modules: moduleRefs,
|
|
102
103
|
members,
|
|
104
|
+
issues,
|
|
103
105
|
});
|
|
104
106
|
const pinvokeTokens = new Set(imports
|
|
105
107
|
.map(({ member_token }) => member_token)
|
|
@@ -115,6 +117,6 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
|
|
|
115
117
|
imports,
|
|
116
118
|
implementations,
|
|
117
119
|
native: cliNative(pe),
|
|
118
|
-
issues
|
|
120
|
+
issues,
|
|
119
121
|
});
|
|
120
122
|
};
|
|
@@ -186,5 +186,16 @@ export const readManagedPeLayout = (bytes) => {
|
|
|
186
186
|
cliDirectoryPresent,
|
|
187
187
|
cliIssue,
|
|
188
188
|
rvaToOffset: (rva, size, scope) => mapRva({ bytes, sections, rva, size, scope }),
|
|
189
|
+
rvaAvailableBytes: (rva, scope) => {
|
|
190
|
+
mapRva({ bytes, sections, rva, size: 1, scope });
|
|
191
|
+
for (const section of sections) {
|
|
192
|
+
if (rva < section.virtualAddress)
|
|
193
|
+
continue;
|
|
194
|
+
const within = rva - section.virtualAddress;
|
|
195
|
+
if (within < section.rawSize)
|
|
196
|
+
return Math.min(section.rawSize - within, bytes.length - section.rawOffset - within);
|
|
197
|
+
}
|
|
198
|
+
throw managedFailure("invalid-directory", scope, `${scope} RVA is not covered by file-backed PE section data`);
|
|
199
|
+
},
|
|
189
200
|
};
|
|
190
201
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Expected carrier encoding failure, independent of the analysis engine. */
|
|
2
|
+
export class EvmCarrierFailure extends Error {
|
|
3
|
+
}
|
|
4
|
+
/** Decode only the explicitly selected representation; source carrier bytes are retained separately. */
|
|
5
|
+
export const decodeEvmBytecodeCarrier = (bytes, encoding) => {
|
|
6
|
+
if (encoding === "raw")
|
|
7
|
+
return Uint8Array.from(bytes);
|
|
8
|
+
let text;
|
|
9
|
+
try {
|
|
10
|
+
text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
11
|
+
}
|
|
12
|
+
catch (cause) {
|
|
13
|
+
throw new EvmCarrierFailure("Hex carrier must be valid UTF-8.", { cause });
|
|
14
|
+
}
|
|
15
|
+
const code = text
|
|
16
|
+
.replace(/^[\x09-\x0d\x20]+|[\x09-\x0d\x20]+$/g, "")
|
|
17
|
+
.replace(/^0x/i, "");
|
|
18
|
+
if (!/^(?:[a-fA-F0-9]{2})*$/.test(code))
|
|
19
|
+
throw new EvmCarrierFailure("Hex carrier requires complete hexadecimal byte pairs, an optional 0x prefix and outer ASCII whitespace; interior separators are invalid.");
|
|
20
|
+
return Uint8Array.from(Buffer.from(code, "hex"));
|
|
21
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { err, ok } from "../domain/result.js";
|
|
2
|
+
import { EVM_INTERFACE_LIMITS } from "./EvmoleRelease.js";
|
|
3
|
+
/** Read only the three selected Linux limits, retaining tighter soft/hard boundaries. */
|
|
4
|
+
export const selectEvmWorkerLimits = (raw) => {
|
|
5
|
+
if (typeof raw !== "string" || Buffer.byteLength(raw) > 64 * 1024)
|
|
6
|
+
return err("Linux resource limits must be text within the 64 KiB parsing budget.");
|
|
7
|
+
const selected = [];
|
|
8
|
+
for (const [name, units, maximum] of [
|
|
9
|
+
["Max address space", "bytes", EVM_INTERFACE_LIMITS.addressSpaceBytes],
|
|
10
|
+
["Max cpu time", "seconds", 30],
|
|
11
|
+
["Max file size", "bytes", EVM_INTERFACE_LIMITS.outputBytes],
|
|
12
|
+
]) {
|
|
13
|
+
const entries = raw
|
|
14
|
+
.split("\n")
|
|
15
|
+
.filter((line) => line.startsWith(name + " "));
|
|
16
|
+
if (entries.length !== 1)
|
|
17
|
+
return err(`Linux resource limits must report exactly one ${name} row.`);
|
|
18
|
+
const match = new RegExp(`^${name}\\s+(unlimited|[0-9]+)\\s+(unlimited|[0-9]+)\\s+${units}\\s*$`).exec(entries[0] ?? "");
|
|
19
|
+
if (match === null)
|
|
20
|
+
return err(`Malformed inherited Linux resource limit: ${name}.`);
|
|
21
|
+
let effective = BigInt(maximum);
|
|
22
|
+
const soft = match[1];
|
|
23
|
+
const hard = match[2];
|
|
24
|
+
if (soft === undefined || hard === undefined)
|
|
25
|
+
return err(`Missing ${name} values.`);
|
|
26
|
+
if (hard !== "unlimited" &&
|
|
27
|
+
(soft === "unlimited" || BigInt(soft) > BigInt(hard)))
|
|
28
|
+
return err(`Inherited ${name} soft limit exceeds its hard limit.`);
|
|
29
|
+
for (const value of [soft, hard])
|
|
30
|
+
if (value !== "unlimited" && BigInt(value) < effective)
|
|
31
|
+
effective = BigInt(value);
|
|
32
|
+
selected.push(Number(effective));
|
|
33
|
+
}
|
|
34
|
+
const [addressSpaceBytes, cpuSeconds, fileSizeBytes] = selected;
|
|
35
|
+
if (addressSpaceBytes === undefined ||
|
|
36
|
+
cpuSeconds === undefined ||
|
|
37
|
+
fileSizeBytes === undefined)
|
|
38
|
+
return err("Required Linux resource limits were not selected.");
|
|
39
|
+
return ok({ addressSpaceBytes, cpuSeconds, fileSizeBytes });
|
|
40
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
|
2
|
+
import { AnalysisError, } from "../domain/analysisErrorBase.js";
|
|
3
|
+
import { AnalysisAccessDeniedError, AnalysisArtifactChangedError, AnalysisCapabilityUnavailableError, AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, AnalysisResourceConstraintError, AnalysisTimeoutError, } from "../domain/analysisErrorCore.js";
|
|
4
|
+
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
|
|
5
|
+
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
|
|
6
|
+
import { OwnedCommandFailure } from "../process/OwnedCommand.js";
|
|
7
|
+
import { EVMOLE_PROVIDER_IDENTITY, EVM_INTERFACE_LIMITS, EVM_FILE_SIZE_FAILURE_EXIT, } from "./EvmoleRelease.js";
|
|
8
|
+
/** Keep carrier read, engine and owned lifecycle failures distinct. */
|
|
9
|
+
export const evmInterfaceFailure = (cause, phase, path, workerLimits, limiter = "/usr/bin/prlimit", fileFailure) => {
|
|
10
|
+
if (cause instanceof AnalysisError)
|
|
11
|
+
return cause;
|
|
12
|
+
if (cause instanceof OwnedCommandFailure) {
|
|
13
|
+
const outputOptions = cause.snapshot === null
|
|
14
|
+
? undefined
|
|
15
|
+
: { capturedOutput: capturedEvmOutput(cause.snapshot) };
|
|
16
|
+
if (cause.cleanupFailure !== null)
|
|
17
|
+
return new ProviderCleanupError(EVMOLE_PROVIDER_IDENTITY.id, cause.resources, {
|
|
18
|
+
reason: cause.cleanupFailure,
|
|
19
|
+
...(cause.snapshot === null
|
|
20
|
+
? {}
|
|
21
|
+
: { captured_output: { ...capturedEvmOutput(cause.snapshot) } }),
|
|
22
|
+
previous_error: {
|
|
23
|
+
failure_kind: cause.reason,
|
|
24
|
+
message: cause.message,
|
|
25
|
+
exit_code: cause.snapshot?.exitCode ?? null,
|
|
26
|
+
signal: cause.snapshot?.signal ?? null,
|
|
27
|
+
stdout: cause.snapshot?.stdout.text ?? null,
|
|
28
|
+
stderr: cause.snapshot?.stderr.text ?? null,
|
|
29
|
+
},
|
|
30
|
+
}, { operation: "inspect_evm_interface", cause });
|
|
31
|
+
if (cause.reason === "cancelled")
|
|
32
|
+
return new AnalysisCancelledError("inspect_evm_interface", outputOptions);
|
|
33
|
+
if (cause.reason === "timeout")
|
|
34
|
+
return new AnalysisTimeoutError("inspect_evm_interface", EVM_INTERFACE_LIMITS.timeoutMs, outputOptions);
|
|
35
|
+
if (cause.reason === "output-limit")
|
|
36
|
+
return new AnalysisOutputError("inspect_evm_interface", cause.message, outputOptions);
|
|
37
|
+
if (cause.reason === "process" &&
|
|
38
|
+
(cause.snapshot?.signal === "SIGXCPU" ||
|
|
39
|
+
cause.snapshot?.signal === "SIGXFSZ" ||
|
|
40
|
+
(fileFailure?.verified === true &&
|
|
41
|
+
cause.snapshot?.exitCode === EVM_FILE_SIZE_FAILURE_EXIT &&
|
|
42
|
+
cause.snapshot.signal === null)))
|
|
43
|
+
return new AnalysisResourceConstraintError("inspect_evm_interface", cause.snapshot.signal === "SIGXCPU" ? "cpu" : "file-size", (cause.snapshot.signal === null
|
|
44
|
+
? "Owned EVM worker reported EFBIG while writing its reply; the exact write failure cause is unknown."
|
|
45
|
+
: `Owned EVM command terminated with ${cause.snapshot.signal}; the exact signal cause is unknown.`) +
|
|
46
|
+
" Effective worker limits are unknown. Configured soft limits are retained separately.", workerLimits === undefined
|
|
47
|
+
? null
|
|
48
|
+
: {
|
|
49
|
+
configured_soft_limits: {
|
|
50
|
+
address_space_bytes: workerLimits.addressSpaceBytes,
|
|
51
|
+
cpu_seconds: workerLimits.cpuSeconds,
|
|
52
|
+
file_size_bytes: workerLimits.fileSizeBytes,
|
|
53
|
+
},
|
|
54
|
+
effective_soft_limits: null,
|
|
55
|
+
}, outputOptions);
|
|
56
|
+
}
|
|
57
|
+
if (cause instanceof Error &&
|
|
58
|
+
"code" in cause &&
|
|
59
|
+
"syscall" in cause &&
|
|
60
|
+
typeof cause.syscall === "string" &&
|
|
61
|
+
cause.syscall.startsWith("spawn ")) {
|
|
62
|
+
const reason = `Configured util-linux prlimit could not launch (${String(cause.code)}): ${limiter}. Check its executable/interpreter and host execute access.`;
|
|
63
|
+
return new AnalysisCapabilityUnavailableError(EVMOLE_PROVIDER_IDENTITY.id, "inspect_evm_interface", reason, { cause, userMessage: reason });
|
|
64
|
+
}
|
|
65
|
+
if (cause instanceof ArtifactReaderFailure) {
|
|
66
|
+
if (cause.reason === "cancelled")
|
|
67
|
+
return new AnalysisCancelledError("inspect_evm_interface");
|
|
68
|
+
if (cause.reason === "integrity")
|
|
69
|
+
return new AnalysisArtifactChangedError("inspect_evm_interface", path, cause.message, { cause });
|
|
70
|
+
if (phase === "artifact-read" &&
|
|
71
|
+
["limit", "path", "format"].includes(cause.reason))
|
|
72
|
+
return new AnalysisInputError("inspect_evm_interface", { cause }, [
|
|
73
|
+
{
|
|
74
|
+
path: ["path"],
|
|
75
|
+
reason: cause.reason === "limit" ? "out_of_range" : "invalid_format",
|
|
76
|
+
message: cause.message,
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
if (phase === "artifact-read" && cause instanceof Error && "code" in cause) {
|
|
81
|
+
if (cause.code === "EACCES" || cause.code === "EPERM")
|
|
82
|
+
return new AnalysisAccessDeniedError("inspect_evm_interface", path, cause.code, { cause });
|
|
83
|
+
if (cause.code === "ENOENT" || cause.code === "ENOTDIR")
|
|
84
|
+
return new AnalysisInputError("inspect_evm_interface", { cause }, [
|
|
85
|
+
{
|
|
86
|
+
path: ["path"],
|
|
87
|
+
reason: "invalid_value",
|
|
88
|
+
message: `Selected bytecode carrier could not be read (${String(cause.code)}): ${path}.`,
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
return new ProviderAdapterError(EVMOLE_PROVIDER_IDENTITY.id, "inspect_evm_interface", {
|
|
93
|
+
cause,
|
|
94
|
+
diagnostics: {
|
|
95
|
+
phase,
|
|
96
|
+
path,
|
|
97
|
+
...(workerLimits === undefined
|
|
98
|
+
? {}
|
|
99
|
+
: { configured_resource_limits: { ...workerLimits } }),
|
|
100
|
+
reason: cause instanceof Error ? cause.message : String(cause),
|
|
101
|
+
...(fileFailure === undefined
|
|
102
|
+
? {}
|
|
103
|
+
: { file_size_failure_marker: { ...fileFailure } }),
|
|
104
|
+
...(cause instanceof OwnedCommandFailure
|
|
105
|
+
? {
|
|
106
|
+
failure_kind: cause.reason,
|
|
107
|
+
exit_code: cause.snapshot?.exitCode ?? null,
|
|
108
|
+
signal: cause.snapshot?.signal ?? null,
|
|
109
|
+
stdout: cause.snapshot?.stdout.text ?? null,
|
|
110
|
+
stderr: cause.snapshot?.stderr.text ?? null,
|
|
111
|
+
...(cause.snapshot === null
|
|
112
|
+
? {}
|
|
113
|
+
: {
|
|
114
|
+
captured_output: { ...capturedEvmOutput(cause.snapshot) },
|
|
115
|
+
}),
|
|
116
|
+
}
|
|
117
|
+
: {}),
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
/** Preserve retained worker diagnostics with their observed truncation status. */
|
|
122
|
+
export const capturedEvmOutput = (snapshot) => ({
|
|
123
|
+
stdout: snapshot.stdout.text,
|
|
124
|
+
stderr: snapshot.stderr.text,
|
|
125
|
+
truncated: snapshot.diagnosticTruncated === true,
|
|
126
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const offset = z.number().int().nonnegative();
|
|
3
|
+
const reportedMetadata = z.strictObject({
|
|
4
|
+
bytecodeOffset: offset,
|
|
5
|
+
cborLength: offset,
|
|
6
|
+
entries: z.array(z.strictObject({
|
|
7
|
+
key: z.string(),
|
|
8
|
+
value: z.discriminatedUnion("type", [
|
|
9
|
+
z.strictObject({ type: z.literal("string"), value: z.string() }),
|
|
10
|
+
z.strictObject({ type: z.literal("integer"), value: z.number() }),
|
|
11
|
+
z.strictObject({ type: z.literal("bytes"), value: z.string() }),
|
|
12
|
+
z.strictObject({ type: z.literal("bool"), value: z.boolean() }),
|
|
13
|
+
z.strictObject({ type: z.literal("undecoded"), value: z.string() }),
|
|
14
|
+
]),
|
|
15
|
+
})),
|
|
16
|
+
});
|
|
17
|
+
/** Parse the exact producer representation before assigning portable field names. */
|
|
18
|
+
export const evmoleInterfaceReplySchema = z.strictObject({
|
|
19
|
+
// The unchanged JS binding exposes disabled facets as own undefined keys.
|
|
20
|
+
// Their JSON transport representation is absence; actual facet values are
|
|
21
|
+
// outside this interface-only profile and must still fail validation.
|
|
22
|
+
storage: z.undefined().optional(),
|
|
23
|
+
transientStorage: z.undefined().optional(),
|
|
24
|
+
disassembled: z.undefined().optional(),
|
|
25
|
+
basicBlocks: z.undefined().optional(),
|
|
26
|
+
controlFlowGraph: z.undefined().optional(),
|
|
27
|
+
// Upstream also extracts metadata when selectors are requested, regardless
|
|
28
|
+
// of its metadata flag. Retain its reported values without precision claims.
|
|
29
|
+
metadata: reportedMetadata.optional(),
|
|
30
|
+
functions: z
|
|
31
|
+
.array(z.strictObject({
|
|
32
|
+
selector: z.string().regex(/^[a-f0-9]{8}$/),
|
|
33
|
+
bytecodeOffset: offset,
|
|
34
|
+
dispatch: z.enum(["abi", "fallback"]),
|
|
35
|
+
arguments: z.string().optional(),
|
|
36
|
+
stateMutability: z.string().optional(),
|
|
37
|
+
}))
|
|
38
|
+
.optional(),
|
|
39
|
+
});
|
|
40
|
+
/** Preserve inference strings and unknown absence; selectors use the conventional 0x display prefix. */
|
|
41
|
+
export const projectEvmoleInterface = (raw) => {
|
|
42
|
+
const producer = evmoleInterfaceReplySchema.parse(raw);
|
|
43
|
+
return {
|
|
44
|
+
raw: producer,
|
|
45
|
+
functions: (producer.functions ?? []).map((fn) => ({
|
|
46
|
+
selector: `0x${fn.selector}`,
|
|
47
|
+
bytecode_offset: fn.bytecodeOffset,
|
|
48
|
+
dispatch: fn.dispatch,
|
|
49
|
+
inferred_arguments: fn.arguments ?? null,
|
|
50
|
+
inferred_state_mutability: fn.stateMutability ?? null,
|
|
51
|
+
})),
|
|
52
|
+
};
|
|
53
|
+
};
|