rea-agents 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -1,274 +1,19 @@
|
|
|
1
1
|
import { managedNativeBoundaryInspectionSchema, } from "../domain/managedArtifact.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { readManagedMetadataInventory, managedTableRowCounts, } from "./ManagedMetadataInventory.js";
|
|
2
|
+
import { readManagedMetadataInventory, } from "./ManagedMetadataInventory.js";
|
|
3
|
+
import { readManagedMetadataLayout, } from "./ManagedMetadataLayout.js";
|
|
5
4
|
import { readManagedPeLayout, } from "./ManagedPeReader.js";
|
|
6
|
-
import { ManagedReaderFailure
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (table === undefined || row === 0)
|
|
19
|
-
return null;
|
|
20
|
-
return metadataToken(table, row);
|
|
21
|
-
};
|
|
22
|
-
const flagsHex = (value) => `0x${value.toString(16).padStart(4, "0")}`;
|
|
23
|
-
const page = (items, offset, limit) => {
|
|
24
|
-
const safeOffset = Math.min(offset, items.length);
|
|
25
|
-
const selected = items.slice(safeOffset, safeOffset + limit);
|
|
26
|
-
return {
|
|
27
|
-
items: selected,
|
|
28
|
-
offset,
|
|
29
|
-
limit,
|
|
30
|
-
total: items.length,
|
|
31
|
-
returned: selected.length,
|
|
32
|
-
dropped: Math.max(0, items.length - safeOffset - selected.length),
|
|
33
|
-
complete: safeOffset === 0 && selected.length === items.length,
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
const parseModuleRefs = (bytes, layout, maxBytes) => {
|
|
37
|
-
const refs = [];
|
|
38
|
-
const table = layout.table(26);
|
|
39
|
-
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
40
|
-
const cursor = rowCursor(bytes, layout, 26, row);
|
|
41
|
-
refs.push({
|
|
42
|
-
token: metadataToken(26, row),
|
|
43
|
-
row_offset: cursor.start,
|
|
44
|
-
name: readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
return refs;
|
|
48
|
-
};
|
|
49
|
-
const parseFields = (bytes, layout, maxBytes) => {
|
|
50
|
-
const fields = new Map();
|
|
51
|
-
const table = layout.table(4);
|
|
52
|
-
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
53
|
-
const cursor = rowCursor(bytes, layout, 4, row);
|
|
54
|
-
const flags = cursor.readUInt16();
|
|
55
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
56
|
-
cursor.readIndex(layout.blobIndexSize);
|
|
57
|
-
const token = metadataToken(4, row);
|
|
58
|
-
fields.set(token, {
|
|
59
|
-
token,
|
|
60
|
-
rowOffset: cursor.start,
|
|
61
|
-
kind: "field",
|
|
62
|
-
name,
|
|
63
|
-
flags,
|
|
64
|
-
implFlags: null,
|
|
65
|
-
rva: null,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return fields;
|
|
69
|
-
};
|
|
70
|
-
const parseMethods = (bytes, layout, maxBytes) => {
|
|
71
|
-
const methods = new Map();
|
|
72
|
-
const table = layout.table(6);
|
|
73
|
-
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
74
|
-
const cursor = rowCursor(bytes, layout, 6, row);
|
|
75
|
-
const rva = cursor.readUInt32();
|
|
76
|
-
const implFlags = cursor.readUInt16();
|
|
77
|
-
const flags = cursor.readUInt16();
|
|
78
|
-
const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
79
|
-
cursor.readIndex(layout.blobIndexSize);
|
|
80
|
-
cursor.readIndex(layout.tableIndexSize(8));
|
|
81
|
-
const token = metadataToken(6, row);
|
|
82
|
-
methods.set(token, {
|
|
83
|
-
token,
|
|
84
|
-
rowOffset: cursor.start,
|
|
85
|
-
kind: "method",
|
|
86
|
-
name,
|
|
87
|
-
flags,
|
|
88
|
-
implFlags,
|
|
89
|
-
rva,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return methods;
|
|
93
|
-
};
|
|
94
|
-
const parseImplMaps = (bytes, layout, maxBytes, modules, members) => {
|
|
95
|
-
const moduleNames = new Map(modules.map((module) => [module.token, module]));
|
|
96
|
-
const imports = [];
|
|
97
|
-
const table = layout.table(28);
|
|
98
|
-
for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
|
|
99
|
-
const cursor = rowCursor(bytes, layout, 28, row);
|
|
100
|
-
const mappingFlags = cursor.readUInt16();
|
|
101
|
-
const memberToken = codedToken(cursor.readIndex(layout.codedIndexSize("MemberForwarded")), 1, [4, 6]);
|
|
102
|
-
const importName = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
|
|
103
|
-
const importScopeRow = cursor.readIndex(layout.tableIndexSize(26));
|
|
104
|
-
const importScopeToken = importScopeRow === 0 ? null : metadataToken(26, importScopeRow);
|
|
105
|
-
const member = memberToken === null ? undefined : members.get(memberToken);
|
|
106
|
-
imports.push({
|
|
107
|
-
token: metadataToken(28, row),
|
|
108
|
-
row_offset: cursor.start,
|
|
109
|
-
mapping_flags: mappingFlags,
|
|
110
|
-
mapping_flags_hex: flagsHex(mappingFlags),
|
|
111
|
-
member_token: memberToken,
|
|
112
|
-
member_kind: member?.kind ?? "unknown",
|
|
113
|
-
member_name: member?.name ?? null,
|
|
114
|
-
import_name: importName,
|
|
115
|
-
import_scope_token: importScopeToken,
|
|
116
|
-
import_scope_name: importScopeToken === null
|
|
117
|
-
? null
|
|
118
|
-
: (moduleNames.get(importScopeToken)?.name ?? null),
|
|
119
|
-
no_mangle: (mappingFlags & 0x0001) !== 0,
|
|
120
|
-
char_set: charSet(mappingFlags),
|
|
121
|
-
call_convention: callConvention(mappingFlags),
|
|
122
|
-
supports_last_error: (mappingFlags & 0x0040) !== 0,
|
|
123
|
-
best_fit: bestFit(mappingFlags),
|
|
124
|
-
throw_on_unmappable_char: throwOnUnmappable(mappingFlags),
|
|
125
|
-
verification: "managed-declaration-only",
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
return imports;
|
|
129
|
-
};
|
|
130
|
-
const charSet = (flags) => {
|
|
131
|
-
switch (flags & 0x0006) {
|
|
132
|
-
case 0x0000:
|
|
133
|
-
return "not-specified";
|
|
134
|
-
case 0x0002:
|
|
135
|
-
return "ansi";
|
|
136
|
-
case 0x0004:
|
|
137
|
-
return "unicode";
|
|
138
|
-
case 0x0006:
|
|
139
|
-
return "auto";
|
|
140
|
-
default:
|
|
141
|
-
return "unknown";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
const callConvention = (flags) => {
|
|
145
|
-
switch (flags & 0x0700) {
|
|
146
|
-
case 0x0000:
|
|
147
|
-
return "not-specified";
|
|
148
|
-
case 0x0100:
|
|
149
|
-
return "winapi";
|
|
150
|
-
case 0x0200:
|
|
151
|
-
return "cdecl";
|
|
152
|
-
case 0x0300:
|
|
153
|
-
return "stdcall";
|
|
154
|
-
case 0x0400:
|
|
155
|
-
return "thiscall";
|
|
156
|
-
case 0x0500:
|
|
157
|
-
return "fastcall";
|
|
158
|
-
default:
|
|
159
|
-
return "unknown";
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
const bestFit = (flags) => {
|
|
163
|
-
switch (flags & 0x0030) {
|
|
164
|
-
case 0x0000:
|
|
165
|
-
return "assembly-default";
|
|
166
|
-
case 0x0010:
|
|
167
|
-
return "enabled";
|
|
168
|
-
case 0x0020:
|
|
169
|
-
return "disabled";
|
|
170
|
-
default:
|
|
171
|
-
return "unknown";
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
const throwOnUnmappable = (flags) => {
|
|
175
|
-
switch (flags & 0x3000) {
|
|
176
|
-
case 0x0000:
|
|
177
|
-
return "assembly-default";
|
|
178
|
-
case 0x1000:
|
|
179
|
-
return "enabled";
|
|
180
|
-
case 0x2000:
|
|
181
|
-
return "disabled";
|
|
182
|
-
default:
|
|
183
|
-
return "unknown";
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const nativeImplementations = (methods, pinvokeTokens) => {
|
|
187
|
-
const implementations = [];
|
|
188
|
-
for (const method of methods) {
|
|
189
|
-
const implFlags = method.implFlags ?? 0;
|
|
190
|
-
const codeType = codeTypeFor(implFlags);
|
|
191
|
-
const managedKind = managedKindFor(implFlags);
|
|
192
|
-
const pinvokeDeclared = pinvokeTokens.has(method.token) || (method.flags & 0x2000) !== 0;
|
|
193
|
-
if (!pinvokeDeclared && codeType === "il" && managedKind === "managed")
|
|
194
|
-
continue;
|
|
195
|
-
implementations.push({
|
|
196
|
-
token: method.token,
|
|
197
|
-
row_offset: method.rowOffset,
|
|
198
|
-
name: method.name,
|
|
199
|
-
rva: method.rva ?? 0,
|
|
200
|
-
flags: method.flags,
|
|
201
|
-
impl_flags: implFlags,
|
|
202
|
-
code_type: codeType,
|
|
203
|
-
managed_kind: managedKind,
|
|
204
|
-
pinvoke_declared: pinvokeDeclared,
|
|
205
|
-
boundary_kind: boundaryKind(pinvokeDeclared, codeType, managedKind),
|
|
206
|
-
body_interpretation: codeType === "il" && managedKind === "managed" && !pinvokeDeclared
|
|
207
|
-
? "managed-cil"
|
|
208
|
-
: method.rva === 0
|
|
209
|
-
? "not-file-backed"
|
|
210
|
-
: "native-or-runtime",
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
return implementations;
|
|
214
|
-
};
|
|
215
|
-
const codeTypeFor = (implFlags) => {
|
|
216
|
-
switch (implFlags & 0x0003) {
|
|
217
|
-
case 0x0000:
|
|
218
|
-
return "il";
|
|
219
|
-
case 0x0001:
|
|
220
|
-
return "native";
|
|
221
|
-
case 0x0002:
|
|
222
|
-
return "optil";
|
|
223
|
-
case 0x0003:
|
|
224
|
-
return "runtime";
|
|
225
|
-
default:
|
|
226
|
-
return "unknown";
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
const managedKindFor = (implFlags) => {
|
|
230
|
-
switch (implFlags & 0x0004) {
|
|
231
|
-
case 0x0000:
|
|
232
|
-
return "managed";
|
|
233
|
-
case 0x0004:
|
|
234
|
-
return "unmanaged";
|
|
235
|
-
default:
|
|
236
|
-
return "unknown";
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
const boundaryKind = (pinvokeDeclared, codeType, managedKind) => {
|
|
240
|
-
if (pinvokeDeclared)
|
|
241
|
-
return "pinvoke";
|
|
242
|
-
if (codeType === "native")
|
|
243
|
-
return "native-body";
|
|
244
|
-
if (codeType === "runtime")
|
|
245
|
-
return "runtime-provided";
|
|
246
|
-
if (managedKind === "unmanaged")
|
|
247
|
-
return "unmanaged-method";
|
|
248
|
-
return "mixed-or-unknown";
|
|
249
|
-
};
|
|
250
|
-
const cliNative = (pe) => {
|
|
251
|
-
if (pe.cli === null)
|
|
252
|
-
return {
|
|
253
|
-
il_only: false,
|
|
254
|
-
requires_32bit: false,
|
|
255
|
-
strong_name_signed: false,
|
|
256
|
-
native_entry_point: false,
|
|
257
|
-
ready_to_run_signature: false,
|
|
258
|
-
managed_native_header_rva: 0,
|
|
259
|
-
managed_native_header_size: 0,
|
|
260
|
-
};
|
|
261
|
-
return {
|
|
262
|
-
il_only: (pe.cli.flags & 0x0000_0001) !== 0,
|
|
263
|
-
requires_32bit: (pe.cli.flags & 0x0000_0002) !== 0,
|
|
264
|
-
strong_name_signed: (pe.cli.flags & 0x0000_0008) !== 0,
|
|
265
|
-
native_entry_point: (pe.cli.flags & 0x0000_0010) !== 0,
|
|
266
|
-
ready_to_run_signature: pe.cli.readyToRunSignature,
|
|
267
|
-
managed_native_header_rva: pe.cli.managedNativeHeader.rva,
|
|
268
|
-
managed_native_header_size: pe.cli.managedNativeHeader.size,
|
|
269
|
-
};
|
|
270
|
-
};
|
|
271
|
-
const unavailable = (target, bytes, limits, issue) => managedNativeBoundaryInspectionSchema.parse({
|
|
5
|
+
import { ManagedReaderFailure } from "./ManagedReaderFailure.js";
|
|
6
|
+
import { buildNativeBoundaryInspection, cliNative, nativeImplementations, parseFields, parseImplMaps, parseMethods, parseModuleRefs, } from "./ManagedNativeBoundaryHelpers.js";
|
|
7
|
+
const emptyPage = () => ({
|
|
8
|
+
items: [],
|
|
9
|
+
offset: 0,
|
|
10
|
+
limit: 0,
|
|
11
|
+
total: 0,
|
|
12
|
+
returned: 0,
|
|
13
|
+
dropped: 0,
|
|
14
|
+
complete: true,
|
|
15
|
+
});
|
|
16
|
+
const emptyInspection = (target, bytes, classification, issues = []) => managedNativeBoundaryInspectionSchema.parse({
|
|
272
17
|
schema_version: 1,
|
|
273
18
|
artifact: {
|
|
274
19
|
path: target.path,
|
|
@@ -277,7 +22,13 @@ const unavailable = (target, bytes, limits, issue) => managedNativeBoundaryInspe
|
|
|
277
22
|
format: "pe",
|
|
278
23
|
},
|
|
279
24
|
module: null,
|
|
280
|
-
metadata: {
|
|
25
|
+
metadata: {
|
|
26
|
+
status: classification === "malformed" || classification === "not-available"
|
|
27
|
+
? "malformed"
|
|
28
|
+
: "absent",
|
|
29
|
+
version: null,
|
|
30
|
+
table_row_counts: {},
|
|
31
|
+
},
|
|
281
32
|
identity_scope: {
|
|
282
33
|
token_identity: "build-local",
|
|
283
34
|
requires_artifact_sha256: target.sha256,
|
|
@@ -292,9 +43,9 @@ const unavailable = (target, bytes, limits, issue) => managedNativeBoundaryInspe
|
|
|
292
43
|
managed_native_header_rva: 0,
|
|
293
44
|
managed_native_header_size: 0,
|
|
294
45
|
},
|
|
295
|
-
module_refs:
|
|
296
|
-
pinvoke_imports:
|
|
297
|
-
native_implementations:
|
|
46
|
+
module_refs: emptyPage(),
|
|
47
|
+
pinvoke_imports: emptyPage(),
|
|
48
|
+
native_implementations: emptyPage(),
|
|
298
49
|
summary: {
|
|
299
50
|
module_ref_count: 0,
|
|
300
51
|
pinvoke_import_count: 0,
|
|
@@ -302,90 +53,91 @@ const unavailable = (target, bytes, limits, issue) => managedNativeBoundaryInspe
|
|
|
302
53
|
ready_to_run: false,
|
|
303
54
|
mixed_mode_or_native_header: false,
|
|
304
55
|
},
|
|
305
|
-
coverage: {
|
|
306
|
-
state: "unavailable",
|
|
307
|
-
issues: issue === null ? [] : [issue],
|
|
308
|
-
},
|
|
56
|
+
coverage: { state: classification, issues },
|
|
309
57
|
limitations: [
|
|
310
|
-
"
|
|
58
|
+
"No CLI data was admitted; native boundary declarations are unavailable.",
|
|
59
|
+
"Static inspection does not load or execute target code, so native export resolution is not performed.",
|
|
311
60
|
],
|
|
312
61
|
});
|
|
313
|
-
|
|
62
|
+
const readBoundaryInventory = (bytes, pe, limits) => {
|
|
63
|
+
const cli = pe.cli;
|
|
64
|
+
const metadataOffset = pe.rvaToOffset(cli.metadata.rva, cli.metadata.size, "cli.metadata");
|
|
65
|
+
const layout = readManagedMetadataLayout(bytes, metadataOffset, cli.metadata.size, limits.maxTableRows);
|
|
66
|
+
const resourceDirectory = {
|
|
67
|
+
offset: pe.rvaToOffset(cli.resources.rva, cli.resources.size, "cli.resources"),
|
|
68
|
+
size: cli.resources.size,
|
|
69
|
+
};
|
|
70
|
+
const inventory = readManagedMetadataInventory(bytes, layout, {
|
|
71
|
+
referenceOffset: 0,
|
|
72
|
+
referenceLimit: 0,
|
|
73
|
+
resourceOffset: 0,
|
|
74
|
+
resourceLimit: 0,
|
|
75
|
+
attributeOffset: 0,
|
|
76
|
+
attributeLimit: 0,
|
|
77
|
+
maxHeapItemBytes: limits.maxHeapItemBytes,
|
|
78
|
+
}, resourceDirectory);
|
|
79
|
+
return { layout, inventory };
|
|
80
|
+
};
|
|
81
|
+
const metadataLimitIssue = (cli, maxBytes) => ({
|
|
82
|
+
code: "limit-exceeded",
|
|
83
|
+
scope: "cli.metadata",
|
|
84
|
+
offset: cli.headerOffset + 8,
|
|
85
|
+
detail: `CLI metadata size exceeds max_metadata_bytes ${String(maxBytes)}`,
|
|
86
|
+
});
|
|
87
|
+
/** Inspect managed/native boundary declarations from PE metadata without execution. */
|
|
314
88
|
export const inspectManagedNativeBoundariesBytes = (bytes, target, limits) => {
|
|
315
|
-
|
|
89
|
+
let pe;
|
|
90
|
+
try {
|
|
91
|
+
pe = readManagedPeLayout(bytes);
|
|
92
|
+
}
|
|
93
|
+
catch (cause) {
|
|
94
|
+
if (!(cause instanceof ManagedReaderFailure))
|
|
95
|
+
throw cause;
|
|
96
|
+
return emptyInspection(target, bytes, "malformed", [cause.issue]);
|
|
97
|
+
}
|
|
316
98
|
if (pe.cli === null)
|
|
317
|
-
return
|
|
318
|
-
|
|
99
|
+
return emptyInspection(target, bytes, pe.cliDirectoryPresent ? "malformed" : "not-managed", pe.cliIssue === null ? [] : [pe.cliIssue]);
|
|
100
|
+
if (pe.cli.metadata.size > limits.maxMetadataBytes)
|
|
101
|
+
return emptyInspection(target, bytes, "malformed", [
|
|
102
|
+
metadataLimitIssue(pe.cli, limits.maxMetadataBytes),
|
|
103
|
+
]);
|
|
104
|
+
let layout;
|
|
105
|
+
let inventory;
|
|
319
106
|
try {
|
|
320
|
-
|
|
321
|
-
if (pe.cli.metadata.size > limits.maxMetadataBytes)
|
|
322
|
-
throw managedFailure("limit-exceeded", "metadata.root", `CLI metadata size exceeds max_metadata_bytes ${String(limits.maxMetadataBytes)}`, rootOffset);
|
|
323
|
-
const layout = readManagedMetadataLayout(bytes, rootOffset, pe.cli.metadata.size, limits.maxTableRows);
|
|
324
|
-
const inventory = readManagedMetadataInventory(bytes, layout, {
|
|
325
|
-
referenceOffset: 0,
|
|
326
|
-
referenceLimit: 1,
|
|
327
|
-
resourceOffset: 0,
|
|
328
|
-
resourceLimit: 1,
|
|
329
|
-
attributeOffset: 0,
|
|
330
|
-
attributeLimit: 1,
|
|
331
|
-
maxHeapItemBytes: limits.maxHeapItemBytes,
|
|
332
|
-
}, null);
|
|
333
|
-
issues.push(...inventory.issues);
|
|
334
|
-
const moduleRefs = parseModuleRefs(bytes, layout, limits.maxHeapItemBytes);
|
|
335
|
-
const fields = parseFields(bytes, layout, limits.maxHeapItemBytes);
|
|
336
|
-
const methods = parseMethods(bytes, layout, limits.maxHeapItemBytes);
|
|
337
|
-
const members = new Map([...fields, ...methods]);
|
|
338
|
-
const imports = parseImplMaps(bytes, layout, limits.maxHeapItemBytes, moduleRefs, members);
|
|
339
|
-
const implementations = nativeImplementations(methods.values(), new Set(imports
|
|
340
|
-
.map(({ member_token: token }) => token)
|
|
341
|
-
.filter((token) => token !== null)));
|
|
342
|
-
const native = cliNative(pe);
|
|
343
|
-
return managedNativeBoundaryInspectionSchema.parse({
|
|
344
|
-
schema_version: 1,
|
|
345
|
-
artifact: {
|
|
346
|
-
path: target.path,
|
|
347
|
-
sha256: target.sha256,
|
|
348
|
-
byte_length: bytes.length,
|
|
349
|
-
format: "pe",
|
|
350
|
-
},
|
|
351
|
-
module: inventory.module,
|
|
352
|
-
metadata: {
|
|
353
|
-
status: issues.length === 0 ? "complete" : "partial",
|
|
354
|
-
version: layout.version,
|
|
355
|
-
table_row_counts: managedTableRowCounts(layout),
|
|
356
|
-
},
|
|
357
|
-
identity_scope: {
|
|
358
|
-
token_identity: "build-local",
|
|
359
|
-
requires_artifact_sha256: target.sha256,
|
|
360
|
-
requires_mvid: inventory.module?.mvid ?? null,
|
|
361
|
-
},
|
|
362
|
-
cli_native: native,
|
|
363
|
-
module_refs: page(moduleRefs, limits.moduleRefOffset, limits.moduleRefLimit),
|
|
364
|
-
pinvoke_imports: page(imports, limits.importOffset, limits.importLimit),
|
|
365
|
-
native_implementations: page(implementations, limits.implementationOffset, limits.implementationLimit),
|
|
366
|
-
summary: {
|
|
367
|
-
module_ref_count: moduleRefs.length,
|
|
368
|
-
pinvoke_import_count: imports.length,
|
|
369
|
-
native_implementation_count: implementations.length,
|
|
370
|
-
ready_to_run: native.ready_to_run_signature,
|
|
371
|
-
mixed_mode_or_native_header: native.managed_native_header_rva !== 0 ||
|
|
372
|
-
native.managed_native_header_size !== 0 ||
|
|
373
|
-
native.native_entry_point,
|
|
374
|
-
},
|
|
375
|
-
coverage: {
|
|
376
|
-
state: issues.length === 0 ? "complete" : "partial",
|
|
377
|
-
issues,
|
|
378
|
-
},
|
|
379
|
-
limitations: [
|
|
380
|
-
"P/Invoke rows prove managed import declarations only; this inspection does not verify that a native library, export, thunk, or provider-qualified function exists.",
|
|
381
|
-
"Managed metadata tokens are build-local coordinates and are only meaningful with the reported artifact SHA-256 and MVID.",
|
|
382
|
-
"ReadyToRun, NativeAOT, C++/CLI, and IL2CPP native semantics require separately selected native-provider evidence; this tool does not translate managed tokens into native addresses.",
|
|
383
|
-
],
|
|
384
|
-
});
|
|
107
|
+
({ layout, inventory } = readBoundaryInventory(bytes, pe, limits));
|
|
385
108
|
}
|
|
386
109
|
catch (cause) {
|
|
387
|
-
if (cause instanceof ManagedReaderFailure)
|
|
388
|
-
|
|
389
|
-
|
|
110
|
+
if (!(cause instanceof ManagedReaderFailure))
|
|
111
|
+
throw cause;
|
|
112
|
+
return emptyInspection(target, bytes, "malformed", [cause.issue]);
|
|
390
113
|
}
|
|
114
|
+
const moduleRefs = parseModuleRefs(bytes, layout, limits.maxHeapItemBytes);
|
|
115
|
+
const members = new Map([
|
|
116
|
+
...parseFields(bytes, layout, limits.maxHeapItemBytes),
|
|
117
|
+
...parseMethods(bytes, layout, limits.maxHeapItemBytes),
|
|
118
|
+
]);
|
|
119
|
+
const imports = parseImplMaps({
|
|
120
|
+
bytes,
|
|
121
|
+
layout,
|
|
122
|
+
maxBytes: limits.maxHeapItemBytes,
|
|
123
|
+
modules: moduleRefs,
|
|
124
|
+
members,
|
|
125
|
+
});
|
|
126
|
+
const pinvokeTokens = new Set(imports
|
|
127
|
+
.map(({ member_token }) => member_token)
|
|
128
|
+
.filter((token) => token !== null));
|
|
129
|
+
const implementations = nativeImplementations(members.values(), pinvokeTokens);
|
|
130
|
+
return buildNativeBoundaryInspection({
|
|
131
|
+
target,
|
|
132
|
+
bytes,
|
|
133
|
+
limits,
|
|
134
|
+
pe,
|
|
135
|
+
layout,
|
|
136
|
+
inventory,
|
|
137
|
+
moduleRefs,
|
|
138
|
+
imports,
|
|
139
|
+
implementations,
|
|
140
|
+
native: cliNative(pe),
|
|
141
|
+
issues: [],
|
|
142
|
+
});
|
|
391
143
|
};
|
|
@@ -27,7 +27,8 @@ const architectureFor = (machine) => {
|
|
|
27
27
|
throw managedFailure("invalid-directory", "pe.machine", `Unsupported PE machine 0x${machine.toString(16).padStart(4, "0")}`);
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
-
const mapRva = (
|
|
30
|
+
const mapRva = (mapping) => {
|
|
31
|
+
const { bytes, sections, rva, size, scope } = mapping;
|
|
31
32
|
if (rva === 0 && size === 0)
|
|
32
33
|
return 0;
|
|
33
34
|
for (const section of sections) {
|
|
@@ -55,7 +56,13 @@ const readDirectory = (bytes, offset) => {
|
|
|
55
56
|
const readCliHeader = (bytes, sections, directory) => {
|
|
56
57
|
if (directory.size < 72)
|
|
57
58
|
throw managedFailure("invalid-cli-header", "cli.header", "CLI header is shorter than the required 72 bytes");
|
|
58
|
-
const offset = mapRva(
|
|
59
|
+
const offset = mapRva({
|
|
60
|
+
bytes,
|
|
61
|
+
sections,
|
|
62
|
+
rva: directory.rva,
|
|
63
|
+
size: 72,
|
|
64
|
+
scope: "cli.header",
|
|
65
|
+
});
|
|
59
66
|
const headerSize = bytes.readUInt32LE(offset);
|
|
60
67
|
if (headerSize < 72 || headerSize > directory.size)
|
|
61
68
|
throw managedFailure("invalid-cli-header", "cli.header", "CLI header size is outside its PE data directory", offset);
|
|
@@ -66,7 +73,13 @@ const readCliHeader = (bytes, sections, directory) => {
|
|
|
66
73
|
const managedNativeHeader = readDirectory(bytes, offset + 64);
|
|
67
74
|
let readyToRunSignature = false;
|
|
68
75
|
if (managedNativeHeader.rva !== 0 && managedNativeHeader.size >= 4) {
|
|
69
|
-
const nativeOffset = mapRva(
|
|
76
|
+
const nativeOffset = mapRva({
|
|
77
|
+
bytes,
|
|
78
|
+
sections,
|
|
79
|
+
rva: managedNativeHeader.rva,
|
|
80
|
+
size: 4,
|
|
81
|
+
scope: "cli.managed-native-header",
|
|
82
|
+
});
|
|
70
83
|
readyToRunSignature = bytes.readUInt32LE(nativeOffset) === 0x0052_5452;
|
|
71
84
|
}
|
|
72
85
|
return {
|
|
@@ -83,11 +96,7 @@ const readCliHeader = (bytes, sections, directory) => {
|
|
|
83
96
|
readyToRunSignature,
|
|
84
97
|
};
|
|
85
98
|
};
|
|
86
|
-
|
|
87
|
-
export const readManagedPeLayout = (bytes) => {
|
|
88
|
-
requireRange(bytes, 0, 64, "pe.dos-header");
|
|
89
|
-
if (bytes[0] !== 0x4d || bytes[1] !== 0x5a)
|
|
90
|
-
throw managedFailure("invalid-directory", "pe.dos-header", "Artifact does not start with an MZ header", 0);
|
|
99
|
+
const readCoffHeader = (bytes) => {
|
|
91
100
|
const peOffset = bytes.readUInt32LE(0x3c);
|
|
92
101
|
requireRange(bytes, peOffset, 24, "pe.coff-header");
|
|
93
102
|
if (bytes.readUInt32LE(peOffset) !== 0x0000_4550)
|
|
@@ -99,22 +108,29 @@ export const readManagedPeLayout = (bytes) => {
|
|
|
99
108
|
throw managedFailure("invalid-directory", "pe.sections", "PE section count is outside the admitted range", coff + 2);
|
|
100
109
|
const optionalSize = bytes.readUInt16LE(coff + 16);
|
|
101
110
|
const characteristics = bytes.readUInt16LE(coff + 18);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
return { coff, machine, sectionCount, optionalSize, characteristics };
|
|
112
|
+
};
|
|
113
|
+
const readOptionalHeader = (bytes, coff) => {
|
|
114
|
+
const optionalOffset = coff.coff + 20;
|
|
115
|
+
requireRange(bytes, optionalOffset, coff.optionalSize, "pe.optional-header");
|
|
116
|
+
if (coff.optionalSize < 96)
|
|
105
117
|
throw managedFailure("invalid-directory", "pe.optional-header", "PE optional header is too short", optionalOffset);
|
|
106
118
|
const magic = bytes.readUInt16LE(optionalOffset);
|
|
107
119
|
const optionalHeader = magic === 0x010b ? "pe32" : magic === 0x020b ? "pe32-plus" : undefined;
|
|
108
120
|
if (optionalHeader === undefined)
|
|
109
121
|
throw managedFailure("invalid-directory", "pe.optional-header", "PE optional header magic is unsupported", optionalOffset);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
return {
|
|
123
|
+
optionalOffset,
|
|
124
|
+
optionalHeader,
|
|
125
|
+
directoryCountOffset: optionalOffset + (optionalHeader === "pe32" ? 92 : 108),
|
|
126
|
+
directoryOffset: optionalOffset + (optionalHeader === "pe32" ? 96 : 112),
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
const readSections = (bytes, coff, optional) => {
|
|
130
|
+
const sectionOffset = add(optional.optionalOffset, coff.optionalSize, "pe.sections");
|
|
131
|
+
requireRange(bytes, sectionOffset, coff.sectionCount * 40, "pe.sections");
|
|
116
132
|
const sections = [];
|
|
117
|
-
for (let index = 0; index < sectionCount; index += 1) {
|
|
133
|
+
for (let index = 0; index < coff.sectionCount; index += 1) {
|
|
118
134
|
const offset = sectionOffset + index * 40;
|
|
119
135
|
const section = {
|
|
120
136
|
virtualSize: bytes.readUInt32LE(offset + 8),
|
|
@@ -126,10 +142,25 @@ export const readManagedPeLayout = (bytes) => {
|
|
|
126
142
|
requireRange(bytes, section.rawOffset, section.rawSize, "pe.section-data");
|
|
127
143
|
sections.push(section);
|
|
128
144
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
return sections;
|
|
146
|
+
};
|
|
147
|
+
const readCliDirectory = (bytes, coff, optional) => {
|
|
148
|
+
requireRange(bytes, optional.directoryCountOffset, 4, "pe.data-directories");
|
|
149
|
+
const directoryCount = bytes.readUInt32LE(optional.directoryCountOffset);
|
|
150
|
+
if (directoryCount <= 14 ||
|
|
151
|
+
coff.optionalSize < optional.directoryOffset - optional.optionalOffset + 120)
|
|
152
|
+
return { rva: 0, size: 0 };
|
|
153
|
+
return readDirectory(bytes, optional.directoryOffset + 14 * 8);
|
|
154
|
+
};
|
|
155
|
+
/** Parse the file-backed PE and CLI layout without loading target code. */
|
|
156
|
+
export const readManagedPeLayout = (bytes) => {
|
|
157
|
+
requireRange(bytes, 0, 64, "pe.dos-header");
|
|
158
|
+
if (bytes[0] !== 0x4d || bytes[1] !== 0x5a)
|
|
159
|
+
throw managedFailure("invalid-directory", "pe.dos-header", "Artifact does not start with an MZ header", 0);
|
|
160
|
+
const coff = readCoffHeader(bytes);
|
|
161
|
+
const optional = readOptionalHeader(bytes, coff);
|
|
162
|
+
const sections = readSections(bytes, coff, optional);
|
|
163
|
+
const cliDirectory = readCliDirectory(bytes, coff, optional);
|
|
133
164
|
const cliDirectoryPresent = cliDirectory.rva !== 0 || cliDirectory.size !== 0;
|
|
134
165
|
let cli = null;
|
|
135
166
|
let cliIssue = null;
|
|
@@ -143,15 +174,15 @@ export const readManagedPeLayout = (bytes) => {
|
|
|
143
174
|
cliIssue = cause.issue;
|
|
144
175
|
}
|
|
145
176
|
return {
|
|
146
|
-
machine,
|
|
147
|
-
architecture: architectureFor(machine),
|
|
148
|
-
optionalHeader,
|
|
149
|
-
sectionCount,
|
|
150
|
-
characteristics,
|
|
177
|
+
machine: coff.machine,
|
|
178
|
+
architecture: architectureFor(coff.machine),
|
|
179
|
+
optionalHeader: optional.optionalHeader,
|
|
180
|
+
sectionCount: coff.sectionCount,
|
|
181
|
+
characteristics: coff.characteristics,
|
|
151
182
|
sections,
|
|
152
183
|
cli,
|
|
153
184
|
cliDirectoryPresent,
|
|
154
185
|
cliIssue,
|
|
155
|
-
rvaToOffset: (rva, size, scope) => mapRva(bytes, sections, rva, size, scope),
|
|
186
|
+
rvaToOffset: (rva, size, scope) => mapRva({ bytes, sections, rva, size, scope }),
|
|
156
187
|
};
|
|
157
188
|
};
|