rea-agents 2.0.0 → 2.1.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 +78 -32
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- 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 +1 -1
- 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/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/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 +147 -259
- package/dist/application/SetupClientConfiguration.js +220 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +123 -12
- package/dist/application/SetupSkill.js +26 -12
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +6 -3
- 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 +108 -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 +289 -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/managedToolContracts.js +1 -1
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/toolContracts.js +2 -2
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +232 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +327 -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/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- 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/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/runtimeCharacterization.js +85 -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/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 +3 -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 +119 -54
- 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 +31 -46
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +54 -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/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 +2 -1
- 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 +5 -0
- package/package.json +10 -11
- package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +20 -7
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
|
@@ -1,295 +1,7 @@
|
|
|
1
|
-
import { METADATA_TABLE_NAMES,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const descriptor = layout.table(table);
|
|
6
|
-
const start = metadataRowOffset(layout, table, row);
|
|
7
|
-
if (descriptor === undefined)
|
|
8
|
-
throw managedFailure("invalid-row", `metadata.${String(table)}`, "Metadata table is absent", start);
|
|
9
|
-
return new MetadataRowCursor(bytes, start, start + descriptor.rowSize, `metadata.${descriptor.name}`);
|
|
10
|
-
};
|
|
11
|
-
const publicKeyIdentity = (bytes, kind) => ({
|
|
12
|
-
kind: bytes.length === 0 ? "none" : kind,
|
|
13
|
-
byte_length: bytes.length,
|
|
14
|
-
sha256: bytes.length === 0 ? null : sha256Bytes(bytes),
|
|
15
|
-
token: bytes.length === 0
|
|
16
|
-
? null
|
|
17
|
-
: kind === "public-key"
|
|
18
|
-
? strongNameToken(bytes)
|
|
19
|
-
: bytes.length === 8
|
|
20
|
-
? bytes.toString("hex")
|
|
21
|
-
: null,
|
|
22
|
-
});
|
|
23
|
-
const readModule = (bytes, layout, maxBytes) => {
|
|
24
|
-
const table = layout.table(0);
|
|
25
|
-
if (table === undefined || table.rowCount === 0)
|
|
26
|
-
return null;
|
|
27
|
-
const cursor = rowCursor(bytes, layout, 0, 1);
|
|
28
|
-
const generation = cursor.readUInt16();
|
|
29
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
30
|
-
const mvid = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
31
|
-
const encId = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
32
|
-
const encBaseId = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
33
|
-
return {
|
|
34
|
-
name,
|
|
35
|
-
generation,
|
|
36
|
-
mvid,
|
|
37
|
-
enc_id: encId,
|
|
38
|
-
enc_base_id: encBaseId,
|
|
39
|
-
token: metadataToken(0, 1),
|
|
40
|
-
row_offset: table.offset,
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
const readAssembly = (bytes, layout, maxBytes) => {
|
|
44
|
-
const table = layout.table(32);
|
|
45
|
-
if (table === undefined || table.rowCount === 0)
|
|
46
|
-
return null;
|
|
47
|
-
const cursor = rowCursor(bytes, layout, 32, 1);
|
|
48
|
-
const hashAlgorithm = cursor.readUInt32();
|
|
49
|
-
const version = [
|
|
50
|
-
cursor.readUInt16(),
|
|
51
|
-
cursor.readUInt16(),
|
|
52
|
-
cursor.readUInt16(),
|
|
53
|
-
cursor.readUInt16(),
|
|
54
|
-
].join(".");
|
|
55
|
-
const flags = cursor.readUInt32();
|
|
56
|
-
const key = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
57
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
58
|
-
const culture = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
59
|
-
return {
|
|
60
|
-
name,
|
|
61
|
-
version,
|
|
62
|
-
culture: culture.length === 0 ? null : culture,
|
|
63
|
-
flags,
|
|
64
|
-
hash_algorithm: hashAlgorithm,
|
|
65
|
-
public_key: publicKeyIdentity(key, (flags & 1) === 0 ? "public-key-token" : "public-key"),
|
|
66
|
-
token: metadataToken(32, 1),
|
|
67
|
-
row_offset: table.offset,
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
const readAssemblyReference = (bytes, layout, row, maxBytes) => {
|
|
71
|
-
const cursor = rowCursor(bytes, layout, 35, row);
|
|
72
|
-
const version = [
|
|
73
|
-
cursor.readUInt16(),
|
|
74
|
-
cursor.readUInt16(),
|
|
75
|
-
cursor.readUInt16(),
|
|
76
|
-
cursor.readUInt16(),
|
|
77
|
-
].join(".");
|
|
78
|
-
const flags = cursor.readUInt32();
|
|
79
|
-
const keyOrToken = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
80
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
81
|
-
const culture = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
82
|
-
const hashValue = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
83
|
-
return {
|
|
84
|
-
name,
|
|
85
|
-
version,
|
|
86
|
-
culture: culture.length === 0 ? null : culture,
|
|
87
|
-
flags,
|
|
88
|
-
public_key_or_token: publicKeyIdentity(keyOrToken, (flags & 1) === 0 ? "public-key-token" : "public-key"),
|
|
89
|
-
hash_value_sha256: hashValue.length === 0 ? null : sha256Bytes(hashValue),
|
|
90
|
-
hash_value_length: hashValue.length,
|
|
91
|
-
token: metadataToken(35, row),
|
|
92
|
-
row_offset: metadataRowOffset(layout, 35, row),
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
const codedToken = (raw, bits, tables) => {
|
|
96
|
-
if (raw === 0)
|
|
97
|
-
return null;
|
|
98
|
-
const tag = raw & (2 ** bits - 1);
|
|
99
|
-
const row = Math.floor(raw / 2 ** bits);
|
|
100
|
-
const table = tables[tag];
|
|
101
|
-
return table === undefined || row === 0 ? null : metadataToken(table, row);
|
|
102
|
-
};
|
|
103
|
-
const readTypeName = (bytes, layout, table, row, maxBytes) => {
|
|
104
|
-
const descriptor = layout.table(table);
|
|
105
|
-
if (descriptor === undefined || row < 1 || row > descriptor.rowCount)
|
|
106
|
-
return null;
|
|
107
|
-
const cursor = rowCursor(bytes, layout, table, row);
|
|
108
|
-
if (table === 1)
|
|
109
|
-
cursor.readIndex(layout.codedIndexSize("ResolutionScope"));
|
|
110
|
-
else
|
|
111
|
-
cursor.readUInt32();
|
|
112
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
113
|
-
const namespace = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
114
|
-
return namespace.length === 0 ? name : `${namespace}.${name}`;
|
|
115
|
-
};
|
|
116
|
-
const declaringTypeForMethod = (bytes, layout, methodRow, maxBytes) => {
|
|
117
|
-
const types = layout.table(2);
|
|
118
|
-
const methods = layout.table(6);
|
|
119
|
-
if (types === undefined || methods === undefined)
|
|
120
|
-
return null;
|
|
121
|
-
for (let row = 1; row <= types.rowCount; row += 1) {
|
|
122
|
-
const cursor = rowCursor(bytes, layout, 2, row);
|
|
123
|
-
cursor.readUInt32();
|
|
124
|
-
const nameIndex = cursor.readIndex(layout.stringIndexSize);
|
|
125
|
-
const namespaceIndex = cursor.readIndex(layout.stringIndexSize);
|
|
126
|
-
cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
|
|
127
|
-
cursor.readIndex(layout.tableIndexSize(4));
|
|
128
|
-
const methodStart = cursor.readIndex(layout.tableIndexSize(6));
|
|
129
|
-
const methodEnd = row === types.rowCount
|
|
130
|
-
? methods.rowCount + 1
|
|
131
|
-
: methodListForType(bytes, layout, row + 1);
|
|
132
|
-
if (methodRow < methodStart || methodRow >= methodEnd)
|
|
133
|
-
continue;
|
|
134
|
-
const name = readMetadataString(bytes, layout, nameIndex, maxBytes);
|
|
135
|
-
const namespace = readMetadataString(bytes, layout, namespaceIndex, maxBytes);
|
|
136
|
-
return namespace.length === 0 ? name : `${namespace}.${name}`;
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
139
|
-
};
|
|
140
|
-
const methodListForType = (bytes, layout, row) => {
|
|
141
|
-
const cursor = rowCursor(bytes, layout, 2, row);
|
|
142
|
-
cursor.readUInt32();
|
|
143
|
-
cursor.readIndex(layout.stringIndexSize);
|
|
144
|
-
cursor.readIndex(layout.stringIndexSize);
|
|
145
|
-
cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
|
|
146
|
-
cursor.readIndex(layout.tableIndexSize(4));
|
|
147
|
-
return cursor.readIndex(layout.tableIndexSize(6));
|
|
148
|
-
};
|
|
149
|
-
const attributeTypeName = (bytes, layout, rawType, maxBytes) => {
|
|
150
|
-
const tag = rawType & 7;
|
|
151
|
-
const row = Math.floor(rawType / 8);
|
|
152
|
-
if (row === 0)
|
|
153
|
-
return null;
|
|
154
|
-
if (tag === 2)
|
|
155
|
-
return declaringTypeForMethod(bytes, layout, row, maxBytes);
|
|
156
|
-
if (tag !== 3)
|
|
157
|
-
return null;
|
|
158
|
-
const memberRefs = layout.table(10);
|
|
159
|
-
if (memberRefs === undefined || row > memberRefs.rowCount)
|
|
160
|
-
return null;
|
|
161
|
-
const cursor = rowCursor(bytes, layout, 10, row);
|
|
162
|
-
const parent = cursor.readIndex(layout.codedIndexSize("MemberRefParent"));
|
|
163
|
-
const parentTag = parent & 7;
|
|
164
|
-
const parentRow = Math.floor(parent / 8);
|
|
165
|
-
if (parentTag === 0)
|
|
166
|
-
return readTypeName(bytes, layout, 2, parentRow, maxBytes);
|
|
167
|
-
if (parentTag === 1)
|
|
168
|
-
return readTypeName(bytes, layout, 1, parentRow, maxBytes);
|
|
169
|
-
if (parentTag === 3)
|
|
170
|
-
return declaringTypeForMethod(bytes, layout, parentRow, maxBytes);
|
|
171
|
-
return null;
|
|
172
|
-
};
|
|
173
|
-
const decodeCompressedLength = (blob, offset) => {
|
|
174
|
-
const first = blob[offset];
|
|
175
|
-
if (first === undefined)
|
|
176
|
-
return undefined;
|
|
177
|
-
if ((first & 0x80) === 0)
|
|
178
|
-
return { length: first, prefix: 1 };
|
|
179
|
-
if ((first & 0xc0) === 0x80 && blob[offset + 1] !== undefined)
|
|
180
|
-
return {
|
|
181
|
-
length: ((first & 0x3f) << 8) | (blob[offset + 1] ?? 0),
|
|
182
|
-
prefix: 2,
|
|
183
|
-
};
|
|
184
|
-
if ((first & 0xe0) === 0xc0 &&
|
|
185
|
-
blob[offset + 1] !== undefined &&
|
|
186
|
-
blob[offset + 2] !== undefined &&
|
|
187
|
-
blob[offset + 3] !== undefined)
|
|
188
|
-
return {
|
|
189
|
-
length: (first & 0x1f) * 0x01_00_00_00 +
|
|
190
|
-
(blob[offset + 1] ?? 0) * 0x01_00_00 +
|
|
191
|
-
(blob[offset + 2] ?? 0) * 0x0100 +
|
|
192
|
-
(blob[offset + 3] ?? 0),
|
|
193
|
-
prefix: 4,
|
|
194
|
-
};
|
|
195
|
-
return undefined;
|
|
196
|
-
};
|
|
197
|
-
const decodeFixedString = (blob) => {
|
|
198
|
-
if (blob.length < 3 || blob.readUInt16LE(0) !== 1 || blob[2] === 0xff)
|
|
199
|
-
return null;
|
|
200
|
-
const length = decodeCompressedLength(blob, 2);
|
|
201
|
-
if (length === undefined)
|
|
202
|
-
return null;
|
|
203
|
-
const start = 2 + length.prefix;
|
|
204
|
-
if (start > blob.length - length.length)
|
|
205
|
-
return null;
|
|
206
|
-
try {
|
|
207
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(blob.subarray(start, start + length.length));
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
const readCustomAttribute = (bytes, layout, row, maxBytes) => {
|
|
214
|
-
const cursor = rowCursor(bytes, layout, 12, row);
|
|
215
|
-
const parentRaw = cursor.readIndex(layout.codedIndexSize("HasCustomAttribute"));
|
|
216
|
-
const typeRaw = cursor.readIndex(layout.codedIndexSize("CustomAttributeType"));
|
|
217
|
-
const value = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
218
|
-
const parent = codedToken(parentRaw, 5, [
|
|
219
|
-
6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
|
|
220
|
-
44, 43,
|
|
221
|
-
]);
|
|
222
|
-
if (parent === null)
|
|
223
|
-
throw managedFailure("invalid-row", "metadata.CustomAttribute", "CustomAttribute parent coded index is invalid", cursor.start);
|
|
224
|
-
const typeName = attributeTypeName(bytes, layout, typeRaw, maxBytes);
|
|
225
|
-
return {
|
|
226
|
-
parent_token: parent,
|
|
227
|
-
constructor_token: codedToken(typeRaw, 3, [undefined, undefined, 6, 10]),
|
|
228
|
-
type_name: typeName,
|
|
229
|
-
value_length: value.length,
|
|
230
|
-
value_sha256: sha256Bytes(value),
|
|
231
|
-
decoded_fixed_string: typeName === "System.Runtime.Versioning.TargetFrameworkAttribute"
|
|
232
|
-
? decodeFixedString(value)
|
|
233
|
-
: null,
|
|
234
|
-
token: metadataToken(12, row),
|
|
235
|
-
row_offset: cursor.start,
|
|
236
|
-
};
|
|
237
|
-
};
|
|
238
|
-
const readResource = (bytes, layout, row, maxBytes, directory, issues) => {
|
|
239
|
-
const cursor = rowCursor(bytes, layout, 40, row);
|
|
240
|
-
const declaredOffset = cursor.readUInt32();
|
|
241
|
-
const flags = cursor.readUInt32();
|
|
242
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
243
|
-
const implementationRaw = cursor.readIndex(layout.codedIndexSize("Implementation"));
|
|
244
|
-
const implementationToken = codedToken(implementationRaw, 2, [38, 35, 39]);
|
|
245
|
-
let dataLength = null;
|
|
246
|
-
let dataSha256 = null;
|
|
247
|
-
if (implementationRaw === 0) {
|
|
248
|
-
if (directory === null || declaredOffset > directory.size - 4) {
|
|
249
|
-
issues.push({
|
|
250
|
-
code: "invalid-resource",
|
|
251
|
-
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
252
|
-
offset: directory?.offset ?? null,
|
|
253
|
-
detail: "Embedded resource offset leaves the CLI resources directory",
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
const start = directory.offset + declaredOffset;
|
|
258
|
-
dataLength = bytes.readUInt32LE(start);
|
|
259
|
-
if (dataLength > directory.size - declaredOffset - 4) {
|
|
260
|
-
issues.push({
|
|
261
|
-
code: "invalid-resource",
|
|
262
|
-
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
263
|
-
offset: start,
|
|
264
|
-
detail: "Embedded resource length leaves the CLI resources directory",
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
else if (dataLength > maxBytes) {
|
|
268
|
-
issues.push({
|
|
269
|
-
code: "limit-exceeded",
|
|
270
|
-
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
271
|
-
offset: start + 4,
|
|
272
|
-
detail: `Embedded resource exceeds max_heap_item_bytes ${String(maxBytes)}; digest omitted`,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
dataSha256 = sha256Bytes(bytes.subarray(start + 4, start + 4 + dataLength));
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return {
|
|
281
|
-
name,
|
|
282
|
-
flags,
|
|
283
|
-
visibility: (flags & 7) === 1 ? "public" : (flags & 7) === 2 ? "private" : "unknown",
|
|
284
|
-
implementation_token: implementationToken,
|
|
285
|
-
embedded: implementationRaw === 0,
|
|
286
|
-
declared_offset: declaredOffset,
|
|
287
|
-
data_length: dataLength,
|
|
288
|
-
data_sha256: dataSha256,
|
|
289
|
-
token: metadataToken(40, row),
|
|
290
|
-
row_offset: cursor.start,
|
|
291
|
-
};
|
|
292
|
-
};
|
|
1
|
+
import { METADATA_TABLE_NAMES, } from "./ManagedMetadataLayout.js";
|
|
2
|
+
import { readAssembly, readAssemblyReference, readCustomAttribute, readModule, readResource, } from "./ManagedMetadataInventoryRows.js";
|
|
3
|
+
import { metadataToken } from "./ManagedMetadataHeaps.js";
|
|
4
|
+
import { ManagedReaderFailure } from "./ManagedReaderFailure.js";
|
|
293
5
|
const safeRead = (operation, issues) => {
|
|
294
6
|
try {
|
|
295
7
|
return operation();
|
|
@@ -323,26 +35,31 @@ const pageRows = (descriptor, offset, limit, read) => {
|
|
|
323
35
|
const uniqueIssues = (issues) => [
|
|
324
36
|
...new Map(issues.map((issue) => [JSON.stringify(issue), issue])).values(),
|
|
325
37
|
];
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
38
|
+
const readPagedReferences = (bytes, layout, input, issues) => pageRows(layout.table(35), input.referenceOffset, input.referenceLimit, (row) => safeRead(() => readAssemblyReference(bytes, layout, row, input.maxHeapItemBytes), issues));
|
|
39
|
+
const readPagedResources = ({ bytes, layout, input, resourceDirectory, issues, }) => pageRows(layout.table(40), input.resourceOffset, input.resourceLimit, (row) => safeRead(() => readResource({
|
|
40
|
+
bytes,
|
|
41
|
+
layout,
|
|
42
|
+
row,
|
|
43
|
+
maxBytes: input.maxHeapItemBytes,
|
|
44
|
+
directory: resourceDirectory,
|
|
45
|
+
issues,
|
|
46
|
+
}), issues));
|
|
47
|
+
const readPagedAttributes = (bytes, layout, input, issues) => pageRows(layout.table(12), input.attributeOffset, input.attributeLimit, (row) => safeRead(() => readCustomAttribute(bytes, layout, row, input.maxHeapItemBytes), issues));
|
|
48
|
+
const collectReferenceNames = (bytes, layout, maxBytes, issues) => {
|
|
49
|
+
const names = [];
|
|
336
50
|
const referenceTable = layout.table(35);
|
|
337
51
|
for (let row = 1; row <= (referenceTable?.rowCount ?? 0); row += 1) {
|
|
338
|
-
const reference = safeRead(() => readAssemblyReference(bytes, layout, row,
|
|
52
|
+
const reference = safeRead(() => readAssemblyReference(bytes, layout, row, maxBytes), issues);
|
|
339
53
|
if (reference !== undefined)
|
|
340
|
-
|
|
54
|
+
names.push(reference.name);
|
|
341
55
|
}
|
|
56
|
+
return names;
|
|
57
|
+
};
|
|
58
|
+
const collectTargetFrameworks = (bytes, layout, maxBytes, issues) => {
|
|
342
59
|
const targetFrameworks = [];
|
|
343
60
|
const attributeTable = layout.table(12);
|
|
344
61
|
for (let row = 1; row <= (attributeTable?.rowCount ?? 0); row += 1) {
|
|
345
|
-
const attribute = safeRead(() => readCustomAttribute(bytes, layout, row,
|
|
62
|
+
const attribute = safeRead(() => readCustomAttribute(bytes, layout, row, maxBytes), issues);
|
|
346
63
|
if (attribute?.parent_token === metadataToken(32, 1) &&
|
|
347
64
|
attribute.type_name ===
|
|
348
65
|
"System.Runtime.Versioning.TargetFrameworkAttribute" &&
|
|
@@ -350,10 +67,29 @@ export const readManagedMetadataInventory = (bytes, layout, input, resourceDirec
|
|
|
350
67
|
!targetFrameworks.includes(attribute.decoded_fixed_string))
|
|
351
68
|
targetFrameworks.push(attribute.decoded_fixed_string);
|
|
352
69
|
}
|
|
70
|
+
return targetFrameworks;
|
|
71
|
+
};
|
|
72
|
+
/** Inventory bounded identity tables without CLR reflection or execution. */
|
|
73
|
+
export const readManagedMetadataInventory = (bytes, layout, input, resourceDirectory) => {
|
|
74
|
+
const issues = [];
|
|
75
|
+
const module = safeRead(() => readModule(bytes, layout, input.maxHeapItemBytes), issues) ??
|
|
76
|
+
null;
|
|
77
|
+
const assembly = safeRead(() => readAssembly(bytes, layout, input.maxHeapItemBytes), issues) ?? null;
|
|
78
|
+
const references = readPagedReferences(bytes, layout, input, issues);
|
|
79
|
+
const resources = readPagedResources({
|
|
80
|
+
bytes,
|
|
81
|
+
layout,
|
|
82
|
+
input,
|
|
83
|
+
resourceDirectory,
|
|
84
|
+
issues,
|
|
85
|
+
});
|
|
86
|
+
const attributes = readPagedAttributes(bytes, layout, input, issues);
|
|
87
|
+
const referenceNames = collectReferenceNames(bytes, layout, input.maxHeapItemBytes, issues);
|
|
88
|
+
const targetFrameworks = collectTargetFrameworks(bytes, layout, input.maxHeapItemBytes, issues);
|
|
353
89
|
return {
|
|
354
90
|
module,
|
|
355
91
|
assembly,
|
|
356
|
-
targetFrameworks: targetFrameworks.sort(),
|
|
92
|
+
targetFrameworks: [...targetFrameworks].sort(),
|
|
357
93
|
referenceNames: [...new Set(referenceNames)].sort(),
|
|
358
94
|
references,
|
|
359
95
|
resources,
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { metadataRowOffset, } from "./ManagedMetadataLayout.js";
|
|
2
|
+
import { MetadataRowCursor, metadataToken, readMetadataBlob, readMetadataGuid, readMetadataString, sha256Bytes, strongNameToken, } from "./ManagedMetadataHeaps.js";
|
|
3
|
+
import { managedFailure } from "./ManagedReaderFailure.js";
|
|
4
|
+
const rowCursor = ({ bytes, layout, table, row, }) => {
|
|
5
|
+
const descriptor = layout.table(table);
|
|
6
|
+
const start = metadataRowOffset(layout, table, row);
|
|
7
|
+
if (descriptor === undefined)
|
|
8
|
+
throw managedFailure("invalid-row", `metadata.${String(table)}`, "Metadata table is absent", start);
|
|
9
|
+
return new MetadataRowCursor(bytes, start, start + descriptor.rowSize, `metadata.${descriptor.name}`);
|
|
10
|
+
};
|
|
11
|
+
const publicKeyIdentity = (bytes, kind) => ({
|
|
12
|
+
kind: bytes.length === 0 ? "none" : kind,
|
|
13
|
+
byte_length: bytes.length,
|
|
14
|
+
sha256: bytes.length === 0 ? null : sha256Bytes(bytes),
|
|
15
|
+
token: bytes.length === 0
|
|
16
|
+
? null
|
|
17
|
+
: kind === "public-key"
|
|
18
|
+
? strongNameToken(bytes)
|
|
19
|
+
: bytes.length === 8
|
|
20
|
+
? bytes.toString("hex")
|
|
21
|
+
: null,
|
|
22
|
+
});
|
|
23
|
+
export const readModule = (bytes, layout, maxBytes) => {
|
|
24
|
+
const table = layout.table(0);
|
|
25
|
+
if (table === undefined || table.rowCount === 0)
|
|
26
|
+
return null;
|
|
27
|
+
const cursor = rowCursor({ bytes, layout, table: 0, row: 1 });
|
|
28
|
+
const generation = cursor.readUInt16();
|
|
29
|
+
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
30
|
+
const mvid = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
31
|
+
const encId = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
32
|
+
const encBaseId = readMetadataGuid(bytes, layout, cursor.readIndex(layout.guidIndexSize));
|
|
33
|
+
return {
|
|
34
|
+
name,
|
|
35
|
+
generation,
|
|
36
|
+
mvid,
|
|
37
|
+
enc_id: encId,
|
|
38
|
+
enc_base_id: encBaseId,
|
|
39
|
+
token: metadataToken(0, 1),
|
|
40
|
+
row_offset: table.offset,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
export const readAssembly = (bytes, layout, maxBytes) => {
|
|
44
|
+
const table = layout.table(32);
|
|
45
|
+
if (table === undefined || table.rowCount === 0)
|
|
46
|
+
return null;
|
|
47
|
+
const cursor = rowCursor({ bytes, layout, table: 32, row: 1 });
|
|
48
|
+
const hashAlgorithm = cursor.readUInt32();
|
|
49
|
+
const version = [
|
|
50
|
+
cursor.readUInt16(),
|
|
51
|
+
cursor.readUInt16(),
|
|
52
|
+
cursor.readUInt16(),
|
|
53
|
+
cursor.readUInt16(),
|
|
54
|
+
].join(".");
|
|
55
|
+
const flags = cursor.readUInt32();
|
|
56
|
+
const key = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
57
|
+
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
58
|
+
const culture = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
59
|
+
return {
|
|
60
|
+
name,
|
|
61
|
+
version,
|
|
62
|
+
culture: culture.length === 0 ? null : culture,
|
|
63
|
+
flags,
|
|
64
|
+
hash_algorithm: hashAlgorithm,
|
|
65
|
+
public_key: publicKeyIdentity(key, (flags & 1) === 0 ? "public-key-token" : "public-key"),
|
|
66
|
+
token: metadataToken(32, 1),
|
|
67
|
+
row_offset: table.offset,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export const readAssemblyReference = (bytes, layout, row, maxBytes) => {
|
|
71
|
+
const cursor = rowCursor({ bytes, layout, table: 35, row });
|
|
72
|
+
const version = [
|
|
73
|
+
cursor.readUInt16(),
|
|
74
|
+
cursor.readUInt16(),
|
|
75
|
+
cursor.readUInt16(),
|
|
76
|
+
cursor.readUInt16(),
|
|
77
|
+
].join(".");
|
|
78
|
+
const flags = cursor.readUInt32();
|
|
79
|
+
const keyOrToken = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
80
|
+
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
81
|
+
const culture = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
82
|
+
const hashValue = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
version,
|
|
86
|
+
culture: culture.length === 0 ? null : culture,
|
|
87
|
+
flags,
|
|
88
|
+
public_key_or_token: publicKeyIdentity(keyOrToken, (flags & 1) === 0 ? "public-key-token" : "public-key"),
|
|
89
|
+
hash_value_sha256: hashValue.length === 0 ? null : sha256Bytes(hashValue),
|
|
90
|
+
hash_value_length: hashValue.length,
|
|
91
|
+
token: metadataToken(35, row),
|
|
92
|
+
row_offset: metadataRowOffset(layout, 35, row),
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const codedToken = (raw, bits, tables) => {
|
|
96
|
+
if (raw === 0)
|
|
97
|
+
return null;
|
|
98
|
+
const tag = raw & (2 ** bits - 1);
|
|
99
|
+
const row = Math.floor(raw / 2 ** bits);
|
|
100
|
+
const table = tables[tag];
|
|
101
|
+
return table === undefined || row === 0 ? null : metadataToken(table, row);
|
|
102
|
+
};
|
|
103
|
+
const readTypeName = ({ bytes, layout, table, row, maxBytes, }) => {
|
|
104
|
+
const descriptor = layout.table(table);
|
|
105
|
+
if (descriptor === undefined || row < 1 || row > descriptor.rowCount)
|
|
106
|
+
return null;
|
|
107
|
+
const cursor = rowCursor({ bytes, layout, table, row });
|
|
108
|
+
if (table === 1)
|
|
109
|
+
cursor.readIndex(layout.codedIndexSize("ResolutionScope"));
|
|
110
|
+
else
|
|
111
|
+
cursor.readUInt32();
|
|
112
|
+
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
113
|
+
const namespace = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
114
|
+
return namespace.length === 0 ? name : `${namespace}.${name}`;
|
|
115
|
+
};
|
|
116
|
+
const declaringTypeForMethod = (bytes, layout, methodRow, maxBytes) => {
|
|
117
|
+
const types = layout.table(2);
|
|
118
|
+
const methods = layout.table(6);
|
|
119
|
+
if (types === undefined || methods === undefined)
|
|
120
|
+
return null;
|
|
121
|
+
for (let row = 1; row <= types.rowCount; row += 1) {
|
|
122
|
+
const cursor = rowCursor({ bytes, layout, table: 2, row });
|
|
123
|
+
cursor.readUInt32();
|
|
124
|
+
const nameIndex = cursor.readIndex(layout.stringIndexSize);
|
|
125
|
+
const namespaceIndex = cursor.readIndex(layout.stringIndexSize);
|
|
126
|
+
cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
|
|
127
|
+
cursor.readIndex(layout.tableIndexSize(4));
|
|
128
|
+
const methodStart = cursor.readIndex(layout.tableIndexSize(6));
|
|
129
|
+
const methodEnd = row === types.rowCount
|
|
130
|
+
? methods.rowCount + 1
|
|
131
|
+
: methodListForType(bytes, layout, row + 1);
|
|
132
|
+
if (methodRow < methodStart || methodRow >= methodEnd)
|
|
133
|
+
continue;
|
|
134
|
+
const name = readMetadataString(bytes, layout, nameIndex, maxBytes);
|
|
135
|
+
const namespace = readMetadataString(bytes, layout, namespaceIndex, maxBytes);
|
|
136
|
+
return namespace.length === 0 ? name : `${namespace}.${name}`;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
const methodListForType = (bytes, layout, row) => {
|
|
141
|
+
const cursor = rowCursor({ bytes, layout, table: 2, row });
|
|
142
|
+
cursor.readUInt32();
|
|
143
|
+
cursor.readIndex(layout.stringIndexSize);
|
|
144
|
+
cursor.readIndex(layout.stringIndexSize);
|
|
145
|
+
cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
|
|
146
|
+
cursor.readIndex(layout.tableIndexSize(4));
|
|
147
|
+
return cursor.readIndex(layout.tableIndexSize(6));
|
|
148
|
+
};
|
|
149
|
+
const attributeTypeName = (bytes, layout, rawType, maxBytes) => {
|
|
150
|
+
const tag = rawType & 7;
|
|
151
|
+
const row = Math.floor(rawType / 8);
|
|
152
|
+
if (row === 0)
|
|
153
|
+
return null;
|
|
154
|
+
if (tag === 2)
|
|
155
|
+
return declaringTypeForMethod(bytes, layout, row, maxBytes);
|
|
156
|
+
if (tag !== 3)
|
|
157
|
+
return null;
|
|
158
|
+
const memberRefs = layout.table(10);
|
|
159
|
+
if (memberRefs === undefined || row > memberRefs.rowCount)
|
|
160
|
+
return null;
|
|
161
|
+
const cursor = rowCursor({ bytes, layout, table: 10, row });
|
|
162
|
+
const parent = cursor.readIndex(layout.codedIndexSize("MemberRefParent"));
|
|
163
|
+
const parentTag = parent & 7;
|
|
164
|
+
const parentRow = Math.floor(parent / 8);
|
|
165
|
+
if (parentTag === 0)
|
|
166
|
+
return readTypeName({ bytes, layout, table: 2, row: parentRow, maxBytes });
|
|
167
|
+
if (parentTag === 1)
|
|
168
|
+
return readTypeName({ bytes, layout, table: 1, row: parentRow, maxBytes });
|
|
169
|
+
if (parentTag === 3)
|
|
170
|
+
return declaringTypeForMethod(bytes, layout, parentRow, maxBytes);
|
|
171
|
+
return null;
|
|
172
|
+
};
|
|
173
|
+
const decodeCompressedLength = (blob, offset) => {
|
|
174
|
+
const first = blob[offset];
|
|
175
|
+
if (first === undefined)
|
|
176
|
+
return undefined;
|
|
177
|
+
if ((first & 0x80) === 0)
|
|
178
|
+
return { length: first, prefix: 1 };
|
|
179
|
+
if ((first & 0xc0) === 0x80 && blob[offset + 1] !== undefined)
|
|
180
|
+
return {
|
|
181
|
+
length: ((first & 0x3f) << 8) | (blob[offset + 1] ?? 0),
|
|
182
|
+
prefix: 2,
|
|
183
|
+
};
|
|
184
|
+
if ((first & 0xe0) === 0xc0 &&
|
|
185
|
+
blob[offset + 1] !== undefined &&
|
|
186
|
+
blob[offset + 2] !== undefined &&
|
|
187
|
+
blob[offset + 3] !== undefined)
|
|
188
|
+
return {
|
|
189
|
+
length: (first & 0x1f) * 0x01_00_00_00 +
|
|
190
|
+
(blob[offset + 1] ?? 0) * 0x01_00_00 +
|
|
191
|
+
(blob[offset + 2] ?? 0) * 0x0100 +
|
|
192
|
+
(blob[offset + 3] ?? 0),
|
|
193
|
+
prefix: 4,
|
|
194
|
+
};
|
|
195
|
+
return undefined;
|
|
196
|
+
};
|
|
197
|
+
const decodeFixedString = (blob) => {
|
|
198
|
+
if (blob.length < 3 || blob.readUInt16LE(0) !== 1 || blob[2] === 0xff)
|
|
199
|
+
return null;
|
|
200
|
+
const length = decodeCompressedLength(blob, 2);
|
|
201
|
+
if (length === undefined)
|
|
202
|
+
return null;
|
|
203
|
+
const start = 2 + length.prefix;
|
|
204
|
+
if (start > blob.length - length.length)
|
|
205
|
+
return null;
|
|
206
|
+
try {
|
|
207
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(blob.subarray(start, start + length.length));
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
export const readCustomAttribute = (bytes, layout, row, maxBytes) => {
|
|
214
|
+
const cursor = rowCursor({ bytes, layout, table: 12, row });
|
|
215
|
+
const parentRaw = cursor.readIndex(layout.codedIndexSize("HasCustomAttribute"));
|
|
216
|
+
const typeRaw = cursor.readIndex(layout.codedIndexSize("CustomAttributeType"));
|
|
217
|
+
const value = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
|
|
218
|
+
const parent = codedToken(parentRaw, 5, [
|
|
219
|
+
6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
|
|
220
|
+
44, 43,
|
|
221
|
+
]);
|
|
222
|
+
if (parent === null)
|
|
223
|
+
throw managedFailure("invalid-row", "metadata.CustomAttribute", "CustomAttribute parent coded index is invalid", cursor.start);
|
|
224
|
+
const typeName = attributeTypeName(bytes, layout, typeRaw, maxBytes);
|
|
225
|
+
return {
|
|
226
|
+
parent_token: parent,
|
|
227
|
+
constructor_token: codedToken(typeRaw, 3, [undefined, undefined, 6, 10]),
|
|
228
|
+
type_name: typeName,
|
|
229
|
+
value_length: value.length,
|
|
230
|
+
value_sha256: sha256Bytes(value),
|
|
231
|
+
decoded_fixed_string: typeName === "System.Runtime.Versioning.TargetFrameworkAttribute"
|
|
232
|
+
? decodeFixedString(value)
|
|
233
|
+
: null,
|
|
234
|
+
token: metadataToken(12, row),
|
|
235
|
+
row_offset: cursor.start,
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
export const readResource = ({ bytes, layout, row, maxBytes, directory, issues, }) => {
|
|
239
|
+
const cursor = rowCursor({ bytes, layout, table: 40, row });
|
|
240
|
+
const declaredOffset = cursor.readUInt32();
|
|
241
|
+
const flags = cursor.readUInt32();
|
|
242
|
+
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
243
|
+
const implementationRaw = cursor.readIndex(layout.codedIndexSize("Implementation"));
|
|
244
|
+
const implementationToken = codedToken(implementationRaw, 2, [38, 35, 39]);
|
|
245
|
+
let dataLength = null;
|
|
246
|
+
let dataSha256 = null;
|
|
247
|
+
if (implementationRaw === 0) {
|
|
248
|
+
if (directory === null || declaredOffset > directory.size - 4) {
|
|
249
|
+
issues.push({
|
|
250
|
+
code: "invalid-resource",
|
|
251
|
+
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
252
|
+
offset: directory?.offset ?? null,
|
|
253
|
+
detail: "Embedded resource offset leaves the CLI resources directory",
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const start = directory.offset + declaredOffset;
|
|
258
|
+
dataLength = bytes.readUInt32LE(start);
|
|
259
|
+
if (dataLength > directory.size - declaredOffset - 4) {
|
|
260
|
+
issues.push({
|
|
261
|
+
code: "invalid-resource",
|
|
262
|
+
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
263
|
+
offset: start,
|
|
264
|
+
detail: "Embedded resource length leaves the CLI resources directory",
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else if (dataLength > maxBytes) {
|
|
268
|
+
issues.push({
|
|
269
|
+
code: "limit-exceeded",
|
|
270
|
+
scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
|
|
271
|
+
offset: start + 4,
|
|
272
|
+
detail: `Embedded resource exceeds max_heap_item_bytes ${String(maxBytes)}; digest omitted`,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
dataSha256 = sha256Bytes(bytes.subarray(start + 4, start + 4 + dataLength));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
name,
|
|
282
|
+
flags,
|
|
283
|
+
visibility: (flags & 7) === 1 ? "public" : (flags & 7) === 2 ? "private" : "unknown",
|
|
284
|
+
implementation_token: implementationToken,
|
|
285
|
+
embedded: implementationRaw === 0,
|
|
286
|
+
declared_offset: declaredOffset,
|
|
287
|
+
data_length: dataLength,
|
|
288
|
+
data_sha256: dataSha256,
|
|
289
|
+
token: metadataToken(40, row),
|
|
290
|
+
row_offset: cursor.start,
|
|
291
|
+
};
|
|
292
|
+
};
|