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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { digestSchema } from "./../domain/digests.js";
|
|
3
3
|
import { prefixedDigestSchema } from "./../domain/digests.js";
|
|
4
|
-
import { PROCESS_COMPARISON_DIMENSIONS } from "./processComparison.js";
|
|
4
|
+
import { PROCESS_COMPARISON_DIMENSIONS } from "./process/processComparison.js";
|
|
5
5
|
const evidenceIdSchema = prefixedDigestSchema("ev");
|
|
6
6
|
const unknownIdSchema = prefixedDigestSchema("unk");
|
|
7
7
|
const claimIdSchema = z.string().regex(/^[A-Za-z][A-Za-z0-9._-]*$/u);
|
|
@@ -147,9 +147,10 @@ export const recordUnknownInputSchema = residualUnknownObjectSchema
|
|
|
147
147
|
.extend({
|
|
148
148
|
supporting_evidence_ids: z.array(evidenceIdSchema).default([]),
|
|
149
149
|
contradicting_evidence_ids: z.array(evidenceIdSchema).default([]),
|
|
150
|
-
})
|
|
150
|
+
})
|
|
151
|
+
.strict();
|
|
151
152
|
/** Explicit optimistic-concurrency update command for one unknown. */
|
|
152
|
-
export const updateUnknownInputSchema = z.
|
|
153
|
+
export const updateUnknownInputSchema = z.strictObject({
|
|
153
154
|
unknown_id: unknownIdSchema,
|
|
154
155
|
expected_revision: z.number().int().min(1),
|
|
155
156
|
status: residualUnknownObjectSchema.shape.status,
|
|
@@ -5,9 +5,9 @@ import { artifactComparisonResultSchema } from "./artifactComparison.js";
|
|
|
5
5
|
import { uniqueSorted } from "./canonicalOrdering.js";
|
|
6
6
|
import { evidenceSchema, parseEvidence } from "./evidence.js";
|
|
7
7
|
import { functionComparisonResultSchema } from "./functionComparison.js";
|
|
8
|
-
import { PROCESS_PROVIDER, isProcessEvidenceProvider, } from "./processEvidenceProvider.js";
|
|
9
|
-
import { comparisonStatusSchema, processCaptureComparisonSchema, } from "./processCapture.js";
|
|
10
|
-
import { PROCESS_COMPARISON_DIMENSIONS } from "./processComparison.js";
|
|
8
|
+
import { PROCESS_PROVIDER, isProcessEvidenceProvider, } from "./process/processEvidenceProvider.js";
|
|
9
|
+
import { comparisonStatusSchema, processCaptureComparisonSchema, } from "./process/processCapture.js";
|
|
10
|
+
import { PROCESS_COMPARISON_DIMENSIONS } from "./process/processComparison.js";
|
|
11
11
|
import { prefixedDigestSchema } from "./../domain/digests.js";
|
|
12
12
|
const evidenceIdSchema = prefixedDigestSchema("ev");
|
|
13
13
|
const functionDimensionSchema = z.enum([
|
|
@@ -118,6 +118,7 @@ const networkMap = (inspection) => {
|
|
|
118
118
|
status: request.status,
|
|
119
119
|
mime_type: request.mime_type,
|
|
120
120
|
encoded_data_length: request.encoded_data_length,
|
|
121
|
+
redirects: (request.redirects ?? []).map(({ request_timestamp: _requestTimestamp, redirect_event_timestamp: _redirectEventTimestamp, ...redirect }) => redirect),
|
|
121
122
|
initiator: request.initiator,
|
|
122
123
|
body_shapes: request.body_shapes,
|
|
123
124
|
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonValueSchema } from "./jsonValue.js";
|
|
3
|
+
/** Complete historical evidence budgets; exceeding a budget returns no partial capture. */
|
|
4
|
+
export const WEB_NETWORK_CAPTURE_LIMITS = {
|
|
5
|
+
inputBytes: 32 * 1024 * 1024,
|
|
6
|
+
outputBytes: 96 * 1024 * 1024,
|
|
7
|
+
timeoutMs: 30_000,
|
|
8
|
+
depth: 64,
|
|
9
|
+
};
|
|
10
|
+
/** Inspect an explicit retained capture without contacting its recorded destinations. */
|
|
11
|
+
export const inspectWebNetworkCaptureInputSchema = z.strictObject({
|
|
12
|
+
capture_path: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.describe("Absolute local HAR or mitmproxy capture path."),
|
|
16
|
+
format: z.enum(["har", "mitmproxy"]),
|
|
17
|
+
record_ordinals: z
|
|
18
|
+
.array(z.number().int().nonnegative())
|
|
19
|
+
.min(1)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Zero-based producer record ordinals, in caller-selected order. Omit to inspect every record."),
|
|
22
|
+
sensitive_values: z
|
|
23
|
+
.array(z.string().min(1))
|
|
24
|
+
.default([])
|
|
25
|
+
.describe("Literal text excluded from capture payloads, byte/numeric projections, producer coordinates, artifact paths/digests and diagnostic text. Declaration strings are never persisted in Evidence parameters. Canonical contract keys, enums and provider identities remain intact."),
|
|
26
|
+
});
|
|
27
|
+
const pointerSchema = z
|
|
28
|
+
.string()
|
|
29
|
+
.describe("RFC 6901 pointer in the producer's reported object.");
|
|
30
|
+
const redactionSchema = z.union([
|
|
31
|
+
z.strictObject({
|
|
32
|
+
pointer: pointerSchema,
|
|
33
|
+
reason: z.enum(["transport-credential", "explicit-sensitive-value"]),
|
|
34
|
+
}),
|
|
35
|
+
z.strictObject({
|
|
36
|
+
pointer: pointerSchema,
|
|
37
|
+
reason: z.literal("explicit-sensitive-value"),
|
|
38
|
+
scope: z
|
|
39
|
+
.literal("property-name")
|
|
40
|
+
.describe("An omitted property name; pointer identifies its actual parent, not an invented child coordinate."),
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
const binaryBase = {
|
|
44
|
+
pointer: pointerSchema,
|
|
45
|
+
representation: z.enum(["producer-bytes", "har-base64-content"]),
|
|
46
|
+
};
|
|
47
|
+
const binarySchema = z.discriminatedUnion("state", [
|
|
48
|
+
z.strictObject({
|
|
49
|
+
...binaryBase,
|
|
50
|
+
state: z.literal("retained"),
|
|
51
|
+
content_base64: z.string(),
|
|
52
|
+
bytes: z.number().int().nonnegative(),
|
|
53
|
+
sha256: z.string().regex(/^[0-9a-f]{64}$/),
|
|
54
|
+
}),
|
|
55
|
+
z.strictObject({
|
|
56
|
+
...binaryBase,
|
|
57
|
+
state: z.literal("redacted"),
|
|
58
|
+
content_base64: z.null(),
|
|
59
|
+
bytes: z.null(),
|
|
60
|
+
sha256: z.null(),
|
|
61
|
+
}),
|
|
62
|
+
]);
|
|
63
|
+
const numberSchema = z.strictObject({
|
|
64
|
+
pointer: pointerSchema,
|
|
65
|
+
producer_type: z.enum(["json-number", "integer", "float"]),
|
|
66
|
+
literal: z.string(),
|
|
67
|
+
});
|
|
68
|
+
/** Preserve producer representations with independent sidecars rather than invented browser IDs. */
|
|
69
|
+
export const webNetworkCaptureRecordSchema = z.strictObject({
|
|
70
|
+
ordinal: z.number().int().nonnegative(),
|
|
71
|
+
location: z.discriminatedUnion("kind", [
|
|
72
|
+
z.strictObject({
|
|
73
|
+
kind: z.literal("unknown"),
|
|
74
|
+
reason: z.literal("explicit-sensitive-value"),
|
|
75
|
+
}),
|
|
76
|
+
z.strictObject({ kind: z.literal("json-pointer"), pointer: pointerSchema }),
|
|
77
|
+
z.strictObject({
|
|
78
|
+
kind: z.literal("byte-range"),
|
|
79
|
+
offset: z.number().int().nonnegative(),
|
|
80
|
+
bytes: z.number().int().positive(),
|
|
81
|
+
}),
|
|
82
|
+
]),
|
|
83
|
+
reported: jsonValueSchema,
|
|
84
|
+
binary_fields: z.array(binarySchema),
|
|
85
|
+
numeric_literals: z.array(numberSchema),
|
|
86
|
+
redactions: z.array(redactionSchema),
|
|
87
|
+
limitations: z.array(z.string()),
|
|
88
|
+
});
|
|
89
|
+
/** Historical capture inspection has file identity, producer provenance and explicit unknowns. */
|
|
90
|
+
export const webNetworkCaptureSchema = z.strictObject({
|
|
91
|
+
artifact: z.strictObject({
|
|
92
|
+
path: z
|
|
93
|
+
.string()
|
|
94
|
+
.describe("Selected artifact path; empty when explicitly excluded from Evidence."),
|
|
95
|
+
sha256: z
|
|
96
|
+
.string()
|
|
97
|
+
.regex(/^[0-9a-f]{64}$/)
|
|
98
|
+
.nullable()
|
|
99
|
+
.describe("Observed artifact SHA-256; null only when explicitly excluded by a sensitive declaration."),
|
|
100
|
+
bytes: z.number().int().nonnegative(),
|
|
101
|
+
}),
|
|
102
|
+
format: z.enum(["har", "mitmproxy"]),
|
|
103
|
+
decoder: z.strictObject({
|
|
104
|
+
id: z.string().min(1),
|
|
105
|
+
name: z.string().min(1),
|
|
106
|
+
version: z.string().min(1),
|
|
107
|
+
}),
|
|
108
|
+
container: z.strictObject({
|
|
109
|
+
reported: jsonValueSchema,
|
|
110
|
+
numeric_literals: z.array(numberSchema),
|
|
111
|
+
redactions: z.array(redactionSchema),
|
|
112
|
+
records_pointer: pointerSchema.nullable(),
|
|
113
|
+
}),
|
|
114
|
+
total_records: z.number().int().nonnegative(),
|
|
115
|
+
records: z.array(webNetworkCaptureRecordSchema),
|
|
116
|
+
runtime_attribution: z.literal("unknown"),
|
|
117
|
+
limitations: z.array(z.string()),
|
|
118
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { redactExplicitText } from "./explicitSensitiveValues.js";
|
|
2
|
+
/** Exclude marked source coordinates without inventing a substitute record identity. */
|
|
3
|
+
export const excludeCaptureCoordinates = (value, sensitiveValues) => {
|
|
4
|
+
if (sensitiveValues.length === 0)
|
|
5
|
+
return value;
|
|
6
|
+
let excluded = false;
|
|
7
|
+
const sensitive = (pointer) => sensitiveValues.some((literal) => pointer.includes(literal));
|
|
8
|
+
const sidecars = (items) => items.filter((item) => {
|
|
9
|
+
if (!sensitive(item.pointer))
|
|
10
|
+
return true;
|
|
11
|
+
excluded = true;
|
|
12
|
+
return false;
|
|
13
|
+
});
|
|
14
|
+
const records = value.records.map((record) => {
|
|
15
|
+
const location = (record.location.kind === "json-pointer" &&
|
|
16
|
+
sensitive(record.location.pointer)) ||
|
|
17
|
+
(record.location.kind === "byte-range" &&
|
|
18
|
+
(sensitive(String(record.location.offset)) ||
|
|
19
|
+
sensitive(String(record.location.bytes))))
|
|
20
|
+
? {
|
|
21
|
+
kind: "unknown",
|
|
22
|
+
reason: "explicit-sensitive-value",
|
|
23
|
+
}
|
|
24
|
+
: record.location;
|
|
25
|
+
if (location !== record.location)
|
|
26
|
+
excluded = true;
|
|
27
|
+
return {
|
|
28
|
+
...record,
|
|
29
|
+
location,
|
|
30
|
+
binary_fields: sidecars(record.binary_fields),
|
|
31
|
+
numeric_literals: sidecars(record.numeric_literals),
|
|
32
|
+
redactions: sidecars(record.redactions),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const recordsPointer = value.container.records_pointer;
|
|
36
|
+
const records_pointer = recordsPointer !== null && sensitive(recordsPointer)
|
|
37
|
+
? null
|
|
38
|
+
: recordsPointer;
|
|
39
|
+
if (records_pointer !== recordsPointer)
|
|
40
|
+
excluded = true;
|
|
41
|
+
const container = {
|
|
42
|
+
...value.container,
|
|
43
|
+
records_pointer,
|
|
44
|
+
numeric_literals: sidecars(value.container.numeric_literals),
|
|
45
|
+
redactions: sidecars(value.container.redactions),
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
...value,
|
|
49
|
+
container,
|
|
50
|
+
records,
|
|
51
|
+
limitations: excluded
|
|
52
|
+
? [
|
|
53
|
+
...value.limitations,
|
|
54
|
+
redactExplicitText("Marked source coordinates and their sidecars are excluded; affected record locations remain unknown.", sensitiveValues),
|
|
55
|
+
]
|
|
56
|
+
: value.limitations,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const clauseFlagsIssue = (region) => [0, 1, 2, 4].includes(region.flags)
|
|
2
|
+
? null
|
|
3
|
+
: `Exception clause has unsupported flags 0x${region.flags.toString(16)}`;
|
|
4
|
+
const methodExtentIssue = (start, length, ilSize, name) => start <= ilSize && length <= ilSize - start
|
|
5
|
+
? null
|
|
6
|
+
: `Exception clause ${name} range leaves the method IL body`;
|
|
7
|
+
const instructionBoundaryIssue = (start, length, boundaries, name) => {
|
|
8
|
+
const end = start + length;
|
|
9
|
+
return boundaries.has(start) && boundaries.has(end)
|
|
10
|
+
? null
|
|
11
|
+
: `Exception clause ${name} range does not align with CIL instruction boundaries`;
|
|
12
|
+
};
|
|
13
|
+
const filterOrderingIssue = (region, ilSize) => {
|
|
14
|
+
if (region.flags !== 1)
|
|
15
|
+
return null;
|
|
16
|
+
const offset = region.filter_offset;
|
|
17
|
+
return offset !== null && offset < ilSize && offset < region.handler_offset
|
|
18
|
+
? null
|
|
19
|
+
: "Exception clause filter must start before its handler within the method IL body";
|
|
20
|
+
};
|
|
21
|
+
const clauseIssue = (region, ilSize, boundaries) => clauseFlagsIssue(region) ??
|
|
22
|
+
methodExtentIssue(region.try_offset, region.try_length, ilSize, "try") ??
|
|
23
|
+
instructionBoundaryIssue(region.try_offset, region.try_length, boundaries, "try") ??
|
|
24
|
+
methodExtentIssue(region.handler_offset, region.handler_length, ilSize, "handler") ??
|
|
25
|
+
instructionBoundaryIssue(region.handler_offset, region.handler_length, boundaries, "handler") ??
|
|
26
|
+
(region.flags === 1 && region.filter_offset !== null
|
|
27
|
+
? instructionBoundaryIssue(region.filter_offset, 0, boundaries, "filter")
|
|
28
|
+
: null) ??
|
|
29
|
+
filterOrderingIssue(region, ilSize);
|
|
30
|
+
/** Validate EH extents and instruction boundaries while retaining each clause. */
|
|
31
|
+
export const validateExceptionRegionRanges = (parsed, ilSize, instructionOffsets) => {
|
|
32
|
+
if (parsed.status === "malformed")
|
|
33
|
+
return parsed;
|
|
34
|
+
const boundaries = new Set([...instructionOffsets, ilSize]);
|
|
35
|
+
for (const region of parsed.regions) {
|
|
36
|
+
const issue = clauseIssue(region, ilSize, boundaries);
|
|
37
|
+
if (issue !== null)
|
|
38
|
+
return { status: "malformed", regions: parsed.regions, issue };
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
};
|
|
@@ -68,9 +68,11 @@ export const inspectManagedMembersBytes = (bytes, target) => {
|
|
|
68
68
|
const { layout, inventory } = readMemberInventory(bytes, pe);
|
|
69
69
|
issues.push(...inventory.issues);
|
|
70
70
|
const ranges = typeRanges(bytes, layout);
|
|
71
|
-
const
|
|
71
|
+
const parsedTypes = parseTypes(bytes, layout, ranges);
|
|
72
|
+
issues.push(...parsedTypes.issues);
|
|
72
73
|
const fields = parseFields(bytes, layout, ranges);
|
|
73
74
|
const memberRefs = parseMemberRefs(bytes, layout);
|
|
75
|
+
issues.push(...memberRefs.issues);
|
|
74
76
|
const methods = parseMethods({
|
|
75
77
|
bytes,
|
|
76
78
|
layout,
|
|
@@ -97,7 +99,7 @@ export const inspectManagedMembersBytes = (bytes, target) => {
|
|
|
97
99
|
requires_artifact_sha256: target.sha256,
|
|
98
100
|
requires_mvid: inventory.module?.mvid ?? null,
|
|
99
101
|
},
|
|
100
|
-
types,
|
|
102
|
+
types: parsedTypes.types,
|
|
101
103
|
fields: fields.fields,
|
|
102
104
|
methods: methods.methods,
|
|
103
105
|
member_refs: memberRefs.refs,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { managedFailure, ManagedReaderFailure, } from "./ManagedReaderFailure.js";
|
|
2
2
|
import {} from "./ManagedMetadataLayout.js";
|
|
3
|
-
import { metadataRowCursor, metadataCodedToken, metadataToken, readMetadataString, sha256Bytes, } from "./ManagedMetadataHeaps.js";
|
|
3
|
+
import { metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, metadataToken, readMetadataString, sha256Bytes, } from "./ManagedMetadataHeaps.js";
|
|
4
4
|
const rowRange = (table, start, nextStart) => {
|
|
5
5
|
const total = table?.rowCount ?? 0;
|
|
6
6
|
if (total === 0 || start === 0)
|
|
@@ -97,17 +97,27 @@ export const parseTypes = (bytes, layout, ranges) => {
|
|
|
97
97
|
const fields = layout.table(4);
|
|
98
98
|
const methods = layout.table(6);
|
|
99
99
|
const items = [];
|
|
100
|
+
const issues = [];
|
|
100
101
|
for (let row = 1; row <= (typeTable?.rowCount ?? 0); row += 1) {
|
|
101
102
|
const cursor = metadataRowCursor(bytes, layout, 2, row);
|
|
102
103
|
const flags = cursor.readUInt32();
|
|
103
104
|
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), layout.strings.size);
|
|
104
105
|
const namespace = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), layout.strings.size);
|
|
106
|
+
const extendsOffset = cursor.offset;
|
|
105
107
|
const extendsRaw = cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
|
|
106
108
|
const fieldStart = cursor.readIndex(layout.tableIndexSize(4));
|
|
107
109
|
const methodStart = cursor.readIndex(layout.tableIndexSize(6));
|
|
108
110
|
const nextRange = ranges[row] ?? null;
|
|
109
111
|
const fieldRange = rowRange(fields, fieldStart, nextRange?.fieldStart ?? 0);
|
|
110
112
|
const methodRange = rowRange(methods, methodStart, nextRange?.methodStart ?? 0);
|
|
113
|
+
const extendsReason = metadataCodedTokenInvalidReason(extendsRaw, 2, [2, 1, 27], layout.rowCounts);
|
|
114
|
+
if (extendsReason !== null)
|
|
115
|
+
issues.push({
|
|
116
|
+
code: "invalid-row",
|
|
117
|
+
scope: `metadata.TypeDef:${metadataToken(2, row)}`,
|
|
118
|
+
offset: extendsOffset,
|
|
119
|
+
detail: `TypeDef Extends coded index 0x${extendsRaw.toString(16)} is invalid: ${extendsReason}`,
|
|
120
|
+
});
|
|
111
121
|
items.push({
|
|
112
122
|
token: metadataToken(2, row),
|
|
113
123
|
row_offset: cursor.start,
|
|
@@ -115,7 +125,7 @@ export const parseTypes = (bytes, layout, ranges) => {
|
|
|
115
125
|
name,
|
|
116
126
|
full_name: fullName(namespace, name),
|
|
117
127
|
flags,
|
|
118
|
-
extends_token: metadataCodedToken(extendsRaw, 2, [2, 1, 27]),
|
|
128
|
+
extends_token: metadataCodedToken(extendsRaw, 2, [2, 1, 27], layout.rowCounts),
|
|
119
129
|
field_list: {
|
|
120
130
|
first_row: fieldRange.first,
|
|
121
131
|
last_row: fieldRange.last,
|
|
@@ -128,7 +138,7 @@ export const parseTypes = (bytes, layout, ranges) => {
|
|
|
128
138
|
},
|
|
129
139
|
});
|
|
130
140
|
}
|
|
131
|
-
return items;
|
|
141
|
+
return { types: items, issues };
|
|
132
142
|
};
|
|
133
143
|
const readCompressed = (bytes, offset) => {
|
|
134
144
|
const first = bytes[offset];
|
|
@@ -171,42 +181,38 @@ const ELEMENT_TYPES = new Map([
|
|
|
171
181
|
[0x19, "native-uint"],
|
|
172
182
|
[0x1c, "object"],
|
|
173
183
|
]);
|
|
174
|
-
const ELEMENT_TYPE_SUFFIXES = new Map([
|
|
175
|
-
[0x0f, "*"],
|
|
176
|
-
[0x10, "&"],
|
|
177
|
-
]);
|
|
178
184
|
const readTypeSignature = (blob, offset) => {
|
|
179
|
-
const
|
|
185
|
+
const suffixes = [];
|
|
186
|
+
let cursor = offset;
|
|
187
|
+
let kind = blob[cursor];
|
|
188
|
+
while (kind === 0x0f || kind === 0x10 || kind === 0x1d) {
|
|
189
|
+
suffixes.push(kind === 0x0f ? "*" : kind === 0x10 ? "&" : "[]");
|
|
190
|
+
cursor += 1;
|
|
191
|
+
kind = blob[cursor];
|
|
192
|
+
}
|
|
180
193
|
if (kind === undefined)
|
|
181
|
-
throw managedFailure("invalid-blob", "signature", "truncated type signature",
|
|
194
|
+
throw managedFailure("invalid-blob", "signature", "truncated type signature", cursor);
|
|
182
195
|
const named = ELEMENT_TYPES.get(kind);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return { value: `${inner.value}${suffix}`, next: inner.next };
|
|
189
|
-
}
|
|
190
|
-
if (kind === 0x11 || kind === 0x12) {
|
|
191
|
-
const token = readCompressed(blob, offset + 1);
|
|
192
|
-
return {
|
|
193
|
-
value: `${kind === 0x11 ? "valuetype" : "class"}:${String(token.value)}`,
|
|
194
|
-
next: token.next,
|
|
195
|
-
};
|
|
196
|
+
let value;
|
|
197
|
+
let next;
|
|
198
|
+
if (named !== undefined) {
|
|
199
|
+
value = named;
|
|
200
|
+
next = cursor + 1;
|
|
196
201
|
}
|
|
197
|
-
if (kind ===
|
|
198
|
-
const
|
|
199
|
-
|
|
202
|
+
else if (kind === 0x11 || kind === 0x12) {
|
|
203
|
+
const token = readCompressed(blob, cursor + 1);
|
|
204
|
+
value = `${kind === 0x11 ? "valuetype" : "class"}:${String(token.value)}`;
|
|
205
|
+
next = token.next;
|
|
200
206
|
}
|
|
201
|
-
if (kind === 0x1e) {
|
|
202
|
-
const variable = readCompressed(blob,
|
|
203
|
-
|
|
207
|
+
else if (kind === 0x1e || kind === 0x13) {
|
|
208
|
+
const variable = readCompressed(blob, cursor + 1);
|
|
209
|
+
value = `${kind === 0x1e ? "mvar" : "var"}:${String(variable.value)}`;
|
|
210
|
+
next = variable.next;
|
|
204
211
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return { value: `var:${String(variable.value)}`, next: variable.next };
|
|
212
|
+
else {
|
|
213
|
+
throw managedFailure("unsupported-signature", "signature", `unsupported element type 0x${kind.toString(16)}`, cursor);
|
|
208
214
|
}
|
|
209
|
-
|
|
215
|
+
return { value: value + suffixes.reverse().join(""), next };
|
|
210
216
|
};
|
|
211
217
|
const callingConvention = (value) => {
|
|
212
218
|
const base = value & 0x0f;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
const opcode = (code) => OPCODES.get(code);
|
|
2
|
+
const PREFIX_OPCODES = new Set([
|
|
3
|
+
"unaligned.",
|
|
4
|
+
"volatile.",
|
|
5
|
+
"tail.",
|
|
6
|
+
"constrained.",
|
|
7
|
+
"readonly.",
|
|
8
|
+
]);
|
|
2
9
|
const OPCODES = new Map([
|
|
3
10
|
[0x00, { name: "nop", operand: "none" }],
|
|
4
11
|
[0x01, { name: "break", operand: "none" }],
|
|
@@ -344,7 +351,9 @@ const readOperand = (il, offset, kind) => {
|
|
|
344
351
|
};
|
|
345
352
|
export const decodeInstructions = (il) => {
|
|
346
353
|
const parsed = [];
|
|
354
|
+
const instructionStarts = [];
|
|
347
355
|
let offset = 0;
|
|
356
|
+
let prefixStart = null;
|
|
348
357
|
let issue = null;
|
|
349
358
|
try {
|
|
350
359
|
while (offset < il.length) {
|
|
@@ -363,6 +372,13 @@ export const decodeInstructions = (il) => {
|
|
|
363
372
|
break;
|
|
364
373
|
}
|
|
365
374
|
offset = operand.next;
|
|
375
|
+
if (PREFIX_OPCODES.has(descriptor.name)) {
|
|
376
|
+
prefixStart ??= start;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
instructionStarts.push(prefixStart ?? start);
|
|
380
|
+
prefixStart = null;
|
|
381
|
+
}
|
|
366
382
|
parsed.push({
|
|
367
383
|
offset: start,
|
|
368
384
|
opcode: descriptor.name,
|
|
@@ -376,7 +392,7 @@ export const decodeInstructions = (il) => {
|
|
|
376
392
|
cause instanceof Error ? cause.message : "Instruction decode failed";
|
|
377
393
|
}
|
|
378
394
|
const truncated = offset < il.length && issue === null ? 1 : 0;
|
|
379
|
-
return { parsed, count: parsed.length, truncated, issue };
|
|
395
|
+
return { parsed, instructionStarts, count: parsed.length, truncated, issue };
|
|
380
396
|
};
|
|
381
397
|
export const parseExceptionRegions = (bytes, offset, methodEnd) => {
|
|
382
398
|
const regions = [];
|
|
@@ -387,10 +403,10 @@ export const parseExceptionRegions = (bytes, offset, methodEnd) => {
|
|
|
387
403
|
sectionOffset < 0 ||
|
|
388
404
|
sectionOffset > methodEnd - 4 ||
|
|
389
405
|
sectionOffset > bytes.length - 4)
|
|
390
|
-
return malformedExceptionRegions("Exception section header leaves artifact");
|
|
406
|
+
return malformedExceptionRegions("Exception section header leaves artifact", regions);
|
|
391
407
|
const kind = bytes.readUInt8(sectionOffset);
|
|
392
408
|
if ((kind & 0x3f) !== 1)
|
|
393
|
-
return malformedExceptionRegions(`Unsupported method data section kind ${String(kind & 0x3f)}
|
|
409
|
+
return malformedExceptionRegions(`Unsupported method data section kind ${String(kind & 0x3f)}`, regions);
|
|
394
410
|
const fat = (kind & 0x40) !== 0;
|
|
395
411
|
const size = fat
|
|
396
412
|
? bytes.readUInt8(sectionOffset + 1) |
|
|
@@ -401,12 +417,12 @@ export const parseExceptionRegions = (bytes, offset, methodEnd) => {
|
|
|
401
417
|
if (size < 4 ||
|
|
402
418
|
sectionOffset > methodEnd - size ||
|
|
403
419
|
sectionOffset > bytes.length - size)
|
|
404
|
-
return malformedExceptionRegions("Exception section size leaves artifact");
|
|
420
|
+
return malformedExceptionRegions("Exception section size leaves artifact", regions);
|
|
405
421
|
if ((size - 4) % clauseSize !== 0)
|
|
406
|
-
return malformedExceptionRegions("Exception section size does not contain whole clauses");
|
|
422
|
+
return malformedExceptionRegions("Exception section size does not contain whole clauses", regions);
|
|
407
423
|
if (!fat &&
|
|
408
424
|
(bytes[sectionOffset + 2] !== 0 || bytes[sectionOffset + 3] !== 0))
|
|
409
|
-
return malformedExceptionRegions("Small exception section reserved bytes are nonzero");
|
|
425
|
+
return malformedExceptionRegions("Small exception section reserved bytes are nonzero", regions);
|
|
410
426
|
const count = (size - 4) / clauseSize;
|
|
411
427
|
regions.push(...readExceptionClauses(bytes, sectionOffset + 4, count, fat));
|
|
412
428
|
hasMoreSections = (kind & 0x80) !== 0;
|
|
@@ -414,7 +430,7 @@ export const parseExceptionRegions = (bytes, offset, methodEnd) => {
|
|
|
414
430
|
}
|
|
415
431
|
return { status: "complete", regions };
|
|
416
432
|
};
|
|
417
|
-
const malformedExceptionRegions = (issue) => ({ status: "malformed", regions
|
|
433
|
+
const malformedExceptionRegions = (issue, regions = []) => ({ status: "malformed", regions, issue });
|
|
418
434
|
const readExceptionClauses = (bytes, start, count, fat) => {
|
|
419
435
|
const regions = [];
|
|
420
436
|
const clauseSize = fat ? 24 : 12;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createDeclaringTypeLookup, signature, } from "./ManagedMemberInspectorCore.js";
|
|
2
|
-
import { metadataToken, metadataRowCursor, metadataCodedToken, readMetadataBlob, readMetadataString, } from "./ManagedMetadataHeaps.js";
|
|
2
|
+
import { metadataToken, metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, readMetadataBlob, readMetadataString, } from "./ManagedMetadataHeaps.js";
|
|
3
3
|
import { methodBody } from "./ManagedMethodBodyReader.js";
|
|
4
4
|
export const parseFields = (bytes, layout, ranges) => {
|
|
5
5
|
const fields = [];
|
|
@@ -29,6 +29,7 @@ export const parseFields = (bytes, layout, ranges) => {
|
|
|
29
29
|
export const parseMemberRefs = (bytes, layout) => {
|
|
30
30
|
const refs = [];
|
|
31
31
|
const core = new Map();
|
|
32
|
+
const issues = [];
|
|
32
33
|
const table = layout.table(10);
|
|
33
34
|
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
34
35
|
const cursor = metadataRowCursor(bytes, layout, 10, row);
|
|
@@ -36,16 +37,26 @@ export const parseMemberRefs = (bytes, layout) => {
|
|
|
36
37
|
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), layout.strings.size);
|
|
37
38
|
const sig = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), layout.blob.size);
|
|
38
39
|
const token = metadataToken(10, row);
|
|
40
|
+
const parentReason = metadataCodedTokenInvalidReason(parentRaw, 3, [2, 1, 26, 6, 27], layout.rowCounts);
|
|
41
|
+
if (parentReason !== null || parentRaw === 0)
|
|
42
|
+
issues.push({
|
|
43
|
+
code: "invalid-row",
|
|
44
|
+
scope: `metadata.MemberRef:${token}`,
|
|
45
|
+
offset: cursor.start,
|
|
46
|
+
detail: parentReason === null
|
|
47
|
+
? "MemberRef parent coded index 0x0 is null, but the Class column must reference a row"
|
|
48
|
+
: `MemberRef parent coded index 0x${parentRaw.toString(16)} is invalid: ${parentReason}`,
|
|
49
|
+
});
|
|
39
50
|
refs.push({
|
|
40
51
|
token,
|
|
41
52
|
row_offset: cursor.start,
|
|
42
|
-
parent_token: metadataCodedToken(parentRaw, 3, [2, 1, 26, 6, 27]),
|
|
53
|
+
parent_token: metadataCodedToken(parentRaw, 3, [2, 1, 26, 6, 27], layout.rowCounts),
|
|
43
54
|
name,
|
|
44
55
|
signature: signature(sig),
|
|
45
56
|
});
|
|
46
57
|
core.set(token, { token, name });
|
|
47
58
|
}
|
|
48
|
-
return { refs, core };
|
|
59
|
+
return { refs, core, issues };
|
|
49
60
|
};
|
|
50
61
|
export const parseMethods = ({ bytes, layout, pe, ranges, }) => {
|
|
51
62
|
const methods = [];
|
|
@@ -140,11 +140,29 @@ export const metadataRowCursor = (bytes, layout, table, row) => {
|
|
|
140
140
|
return new MetadataRowCursor(bytes, start, start + descriptor.rowSize, `metadata.${descriptor.name}`);
|
|
141
141
|
};
|
|
142
142
|
/** Decode a metadata coded index without signed 32-bit coercion. */
|
|
143
|
-
export const metadataCodedToken = (raw, bits, tables) => {
|
|
143
|
+
export const metadataCodedToken = (raw, bits, tables, rowCounts) => {
|
|
144
144
|
if (raw === 0)
|
|
145
145
|
return null;
|
|
146
146
|
const tag = raw & (2 ** bits - 1);
|
|
147
147
|
const row = Math.floor(raw / 2 ** bits);
|
|
148
148
|
const table = tables[tag];
|
|
149
|
-
return table === undefined || row === 0
|
|
149
|
+
return table === undefined || row === 0 || row > (rowCounts[table] ?? 0)
|
|
150
|
+
? null
|
|
151
|
+
: metadataToken(table, row);
|
|
152
|
+
};
|
|
153
|
+
/** Explain why a non-null coded index cannot name an admitted metadata row. */
|
|
154
|
+
export const metadataCodedTokenInvalidReason = (raw, bits, tables, rowCounts) => {
|
|
155
|
+
if (raw === 0)
|
|
156
|
+
return null;
|
|
157
|
+
const tag = raw & (2 ** bits - 1);
|
|
158
|
+
const row = Math.floor(raw / 2 ** bits);
|
|
159
|
+
const table = tables[tag];
|
|
160
|
+
if (table === undefined)
|
|
161
|
+
return `coded index tag ${tag} is not defined`;
|
|
162
|
+
if (row === 0)
|
|
163
|
+
return `coded index selects row zero in table ${table}`;
|
|
164
|
+
const count = rowCounts[table] ?? 0;
|
|
165
|
+
return row > count
|
|
166
|
+
? `coded index selects row ${row} in table ${table}, which has ${count} rows`
|
|
167
|
+
: null;
|
|
150
168
|
};
|