rea-agents 6.0.0 → 6.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 +23 -17
- package/bridge/android/ReaJadxBridge.java +14 -5
- package/bridge/ghidra/ReaGhidraBridge.java +173 -47
- package/bridge/hopper_bridge.py +310 -128
- package/bridge/mitmproxy/capture.py +0 -2
- package/bridge/native/rea_lldb_tracer.py +630 -94
- package/bridge/process/ProcessRunTokenReader.swift +39 -5
- package/bridge/pwntools/recorded_crash_impl.py +4 -0
- package/dist/android/JadxConfiguration.js +196 -33
- package/dist/android/JadxMcpTransport.js +4 -0
- package/dist/android/JadxProtocol.js +6 -0
- package/dist/android/JadxProvider.js +19 -2
- package/dist/android/JadxSession.js +23 -4
- package/dist/application/AnalysisContextQueries.js +8 -35
- package/dist/application/AnalysisDocument.js +32 -0
- package/dist/application/AppBundleExecutable.js +67 -21
- package/dist/application/CallPathTracing.js +19 -3
- package/dist/application/CapabilityInventory.js +6 -3
- package/dist/application/ClientConfigurationDocument.js +871 -6
- package/dist/application/ClientRegistrationIdentity.js +26 -5
- package/dist/application/ClientRegistrationStatus.js +29 -14
- package/dist/application/DirectAnalysis.js +27 -37
- package/dist/application/Doctor.js +4 -2
- package/dist/application/DoctorScope.js +25 -13
- package/dist/application/EnhancedLiteralTracing.js +22 -25
- package/dist/application/EnhancedTools.js +13 -11
- package/dist/application/EvidenceBundleFiles.js +23 -11
- package/dist/application/FunctionAnalysisEvidence.js +2 -3
- package/dist/application/InventoryProjectionEvidence.js +4 -3
- package/dist/application/InvestigationProviders.js +3 -2
- package/dist/application/JsonFiles.js +50 -28
- package/dist/application/ProcedureAddressResolution.js +11 -0
- package/dist/application/ReconstructionCoverageService.js +7 -4
- package/dist/application/ReconstructionObligationLedgerService.js +4 -3
- package/dist/application/Setup.js +13 -1
- package/dist/application/SetupClientConfiguration.js +10 -15
- package/dist/application/SetupHost.js +5 -2
- package/dist/application/SetupPlan.js +5 -3
- package/dist/application/SupportedClients.js +34 -1
- package/dist/application/Uninstall.js +4 -3
- package/dist/application/Update.js +18 -3
- package/dist/application/UpdateRuntime.js +46 -25
- package/dist/application/WebModuleTraceService.js +4 -2
- package/dist/application/WebNetworkCaptureService.js +4 -2
- package/dist/application/WebRuntimeService.js +5 -3
- package/dist/application/WebScriptExportService.js +2 -2
- package/dist/application/WebSourceLocationService.js +4 -2
- package/dist/application/WorkflowEvidence.js +82 -0
- package/dist/application/binary/AnalysisProviderEvaluation.js +21 -5
- package/dist/application/binary/AnalysisProviderRegistry.js +2 -0
- package/dist/application/binary/AnalysisSnapshotCache.js +3 -6
- package/dist/application/binary/BinarySession.js +95 -68
- package/dist/application/binary/BinarySessionOpen.js +3 -3
- package/dist/application/binary/BinarySessionRecords.js +25 -3
- package/dist/application/binary/BinarySessionStatus.js +17 -1
- package/dist/application/binary/CompositeProvider.js +13 -0
- package/dist/application/binary/LazyAnalysisProvider.js +3 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +4 -2
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +4 -2
- package/dist/application/evm/EvmInterfaceService.js +4 -2
- package/dist/application/investigation/EvidenceLedger.js +21 -7
- package/dist/application/investigation/InvestigationRecords.js +8 -0
- package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +24 -3
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +22 -15
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -4
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +39 -7
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +6 -3
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +11 -3
- package/dist/application/javascript/JavaScriptModuleRelationships.js +37 -8
- package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -1
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +23 -1
- package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
- package/dist/application/managed/ManagedMemberComparisonService.js +7 -4
- package/dist/application/managed/ManagedNativeVerificationService.js +4 -3
- package/dist/application/managed/ManagedReconstructionService.js +4 -3
- package/dist/application/process/ProcessCli.js +14 -6
- package/dist/application/process/ProcessEvidence.js +4 -3
- package/dist/application/workflowInputError.js +18 -0
- package/dist/artifacts/ArtifactProvider.js +12 -2
- package/dist/artifacts/MachOSliceArtifactReader.js +98 -14
- package/dist/artifacts/NativeDmgArtifactReader.js +13 -6
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +22 -3
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +36 -22
- package/dist/artifacts/apple/MachoLoadCommandReader.js +92 -31
- package/dist/artifacts/apple/NibArchive.js +81 -14
- package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
- package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +13 -8
- package/dist/artifacts/inventory/scanCanonical.js +11 -14
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
- package/dist/browser/CdpCaptureCompleteness.js +2 -0
- package/dist/browser/CdpCaptureEventHandlers.js +76 -11
- package/dist/browser/CdpCaptureEventTypes.js +5 -1
- package/dist/browser/CdpCaptureEvents.js +25 -0
- package/dist/browser/CdpConnection.js +30 -11
- package/dist/browser/CdpOptionalCommand.js +2 -3
- package/dist/browser/CdpPageCapture.js +23 -1
- package/dist/browser/PlaywrightElectronActiveActions.js +32 -23
- package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +123 -124
- package/dist/browser/WebSourceMapFetcher.js +426 -72
- package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
- package/dist/browser/history/CaptureFailures.js +37 -1
- package/dist/browser/history/CaptureRelease.js +5 -0
- package/dist/browser/history/HarCaptureAdapter.js +3 -3
- package/dist/browser/history/HarJson.js +3 -2
- package/dist/browser/history/HistoricalCaptureDecoder.js +4 -2
- package/dist/cli/analysisSelector.js +23 -0
- package/dist/cli/applicationCommands.js +2 -3
- package/dist/cli/coreBinaryCommands.js +70 -12
- package/dist/cli/electronCommands.js +7 -6
- package/dist/cli/javascriptApplicationAnalysis.js +7 -3
- package/dist/cli/jsonOutput.js +4 -99
- package/dist/cli/nativeCallCommands.js +2 -3
- package/dist/cli/webRuntimeCommands.js +8 -8
- package/dist/cli.js +2 -1
- package/dist/cliCommandNames.js +0 -1
- package/dist/cliJsonInput.js +9 -4
- package/dist/config/environment.js +4 -0
- package/dist/config/ghidraStartupTimeout.js +17 -0
- package/dist/config/mcpResponseBudget.js +22 -0
- package/dist/config/parseConfig.js +2 -1
- package/dist/contracts/enhancedInputs.js +5 -3
- package/dist/contracts/enhancedToolContracts.js +3 -3
- package/dist/contracts/hopperMemoryContracts.js +2 -5
- package/dist/contracts/javascript/electronToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +2 -4
- package/dist/contracts/native/nativeToolContracts.js +4 -2
- package/dist/contracts/officialToolContracts.js +14 -15
- package/dist/contracts/promptContracts.js +3 -3
- package/dist/contracts/sessionLifecycleInputs.js +3 -7
- package/dist/contracts/sessionStatusContract.js +2 -4
- package/dist/contracts/sessionToolContracts.js +4 -6
- package/dist/contracts/sessionToolSchemas.js +2 -5
- package/dist/contracts/toolContractExamples.js +0 -1
- package/dist/contracts/toolContractHelpers.js +4 -1
- package/dist/contracts/toolEffects.js +0 -1
- package/dist/contracts/toolOutputSchemaGroups.js +28 -27
- package/dist/contracts/toolOutputSchemaPrimitives.js +18 -0
- package/dist/contracts/toolSchemaMetadata.js +69 -10
- package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
- package/dist/domain/analysisErrorBase.js +8 -3
- package/dist/domain/analysisErrorCore.js +3 -1
- package/dist/domain/analysisErrorPresentation.js +72 -17
- package/dist/domain/analysisErrorProjection.js +106 -27
- package/dist/domain/android/androidAnalysis.js +2 -4
- package/dist/domain/android/androidApplication.js +17 -9
- package/dist/domain/apple/appleApplication.js +41 -14
- package/dist/domain/apple/dyldEnvironment.js +73 -0
- package/dist/domain/apple/dylibResolution.js +120 -9
- package/dist/domain/apple/dylibResolutionFindings.js +9 -7
- package/dist/domain/apple/interfaceBuilderGraph.js +25 -13
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
- package/dist/domain/apple/keyedArchive.js +9 -1
- package/dist/domain/apple/machoContainer.js +54 -0
- package/dist/domain/apple/plistNumbers.js +76 -0
- package/dist/domain/artifactIdentity.js +29 -0
- package/dist/domain/artifactInventoryEvidence.js +19 -24
- package/dist/domain/bridgeCandidateProjection.js +71 -0
- package/dist/domain/browserCompleteness.js +1 -0
- package/dist/domain/browserObservationError.js +24 -5
- package/dist/domain/browserScenarioValues.js +2 -6
- package/dist/domain/bundleComparison.js +3 -2
- package/dist/domain/canonicalJsonDigestSteps.js +133 -0
- package/dist/domain/canonicalOrdering.js +9 -5
- package/dist/domain/changedBehavior.js +6 -6
- package/dist/domain/comparisonSourceEvidence.js +40 -0
- package/dist/domain/configurationErrors.js +1 -1
- package/dist/domain/evidence.js +64 -9
- package/dist/domain/evidenceBundle.js +42 -1
- package/dist/domain/evidenceErrors.js +12 -1
- package/dist/domain/explicitSensitiveFailure.js +17 -1
- package/dist/domain/firmware/firmwareAnalysis.js +6 -7
- package/dist/domain/hopperErrors.js +23 -2
- package/dist/domain/hopperValues.js +51 -8
- package/dist/domain/immutableJson.js +114 -0
- package/dist/domain/inputIssueProjection.js +3 -0
- package/dist/domain/javascript/electronActiveObservation.js +30 -4
- package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
- package/dist/domain/javascript/javascriptApplicationGraph.js +13 -0
- package/dist/domain/javascript/javascriptAstValues.js +20 -0
- package/dist/domain/javascript/javascriptRecovery.js +3 -8
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +97 -2
- package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +22 -5
- package/dist/domain/javascript/javascriptSemanticGraph.js +13 -0
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +25 -17
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +83 -11
- package/dist/domain/javascript/javascriptSourceParser.js +6 -2
- package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +14 -4
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -16
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
- package/dist/domain/jsonSerialization.js +109 -0
- package/dist/domain/jsonValue.js +90 -6
- package/dist/domain/localPath.js +6 -0
- package/dist/domain/managed/managedApplicationGraph.js +10 -10
- package/dist/domain/managed/managedInspectionEvidence.js +16 -0
- package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
- package/dist/domain/managed/managedNativeVerification.js +3 -9
- package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
- package/dist/domain/native/nativeCallObservation.js +33 -11
- package/dist/domain/native/nativeCallPartialObservation.js +33 -0
- package/dist/domain/process/processCapture.js +8 -4
- package/dist/domain/process/processComparison.js +38 -4
- package/dist/domain/process/processScenario.js +11 -10
- package/dist/domain/propertyListKeys.js +1 -1
- package/dist/domain/propertyListXmlText.js +19 -0
- package/dist/domain/providerAdapterError.js +1 -1
- package/dist/domain/providerOperationHealth.js +54 -0
- package/dist/domain/reconstructionVerification.js +6 -43
- package/dist/domain/reconstructionVerificationSchemas.js +2 -2
- package/dist/domain/staticRuntimeCorrelation.js +6 -43
- package/dist/domain/webBundleAnalysis.js +20 -8
- package/dist/domain/webBundleAnalyzerInspection.js +13 -8
- package/dist/domain/webBundleAnalyzerResult.js +41 -2
- package/dist/domain/webRuntime.js +19 -5
- package/dist/domain/webSourceLocation.js +1 -0
- package/dist/firmware/FirmwareFiles.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraAnalysisProfile.js +5 -0
- package/dist/ghidra/GhidraClient.js +47 -14
- package/dist/ghidra/GhidraDiagnostics.js +7 -7
- package/dist/ghidra/GhidraFunctionValues.js +10 -7
- package/dist/ghidra/GhidraInstallation.js +18 -21
- package/dist/ghidra/GhidraInventoryValues.js +14 -4
- package/dist/ghidra/GhidraJavaLaunch.js +62 -0
- package/dist/ghidra/GhidraLauncher.js +33 -16
- package/dist/ghidra/GhidraProviderCapabilities.js +14 -2
- package/dist/ghidra/GhidraProviderClient.js +23 -12
- package/dist/ghidra/GhidraSessionError.js +11 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
- package/dist/ghidra/GhidraTransport.js +20 -0
- package/dist/hopper/BridgeLauncher.js +31 -11
- package/dist/hopper/HopperAnalysisProfile.js +62 -4
- package/dist/hopper/HopperCleanup.js +15 -3
- package/dist/hopper/HopperClient.js +222 -14
- package/dist/hopper/HopperFileOffset.js +237 -0
- package/dist/hopper/HopperMachOImage.js +196 -0
- package/dist/hopper/HopperOperationStage.js +6 -0
- package/dist/hopper/HopperProvider.js +63 -9
- package/dist/hopper/HopperProviderCapabilities.js +19 -1
- package/dist/hopper/HopperRegexSearch.js +137 -0
- package/dist/hopper/HopperRegexWorker.js +27 -0
- package/dist/hopper/HopperRequestQueue.js +68 -19
- package/dist/hopper/HopperTargetLease.js +3 -2
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
- package/dist/inspector/V8InspectorCaptureProjection.js +8 -3
- package/dist/inspector/V8InspectorProvider.js +47 -11
- package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -0
- package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
- package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
- package/dist/mcpDoctor.js +62 -2
- package/dist/native/AppleDispatchCoverage.js +47 -6
- package/dist/native/AppleDispatchDecodeFacts.js +6 -0
- package/dist/native/AppleDispatchMetadata.js +6 -3
- package/dist/native/AppleMachoFixups.js +48 -24
- package/dist/native/AppleMachoSelection.js +32 -16
- package/dist/native/AppleObjcCategories.js +6 -2
- package/dist/native/AppleObjcDispatchFacets.js +5 -2
- package/dist/native/AppleObjcProperties.js +2 -1
- package/dist/native/AppleSwiftDispatchFacets.js +27 -21
- package/dist/native/AppleSwiftVtables.js +21 -15
- package/dist/native/CommandRunner.js +81 -84
- package/dist/native/LldbCallTracer.js +365 -102
- package/dist/native/LldbRetainedObservations.js +178 -0
- package/dist/native/NativeCallObservation.js +62 -3
- package/dist/native/NativeMacOSProvider.js +98 -17
- package/dist/native/SignatureTargetBinding.js +155 -0
- package/dist/native/parsers/lipo.js +71 -1
- package/dist/native/pwndbg/PwndbgCoreContext.js +25 -5
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
- package/dist/process/DarwinProcessRunTokenReader.js +8 -9
- package/dist/process/ExecFileOutput.js +20 -0
- package/dist/process/OwnedCommand.js +7 -2
- package/dist/process/ProcessOwnership.js +203 -53
- package/dist/process/ProcessOwnershipObservation.js +49 -4
- package/dist/process/ProviderProcess.js +38 -7
- package/dist/process/capture/ProcessCaptureError.js +2 -2
- package/dist/process/capture/ProcessCaptureLifecycle.js +100 -34
- package/dist/server/EvidenceMcpServer.js +146 -0
- package/dist/server/createServer.js +15 -8
- package/dist/server/registerAndroidTools.js +2 -4
- package/dist/server/registerApplicationTools/helpers.js +2 -4
- package/dist/server/registerArtifactComparisonTool.js +11 -7
- package/dist/server/registerBinaryDiagnosticsTools.js +2 -4
- package/dist/server/registerBrowserScenarioTool.js +2 -4
- package/dist/server/registerBrowserTools.js +2 -4
- package/dist/server/registerBundleComparisonTool.js +2 -3
- package/dist/server/registerCloseLifecycleTool.js +8 -18
- package/dist/server/registerElectronTools.js +2 -4
- package/dist/server/registerEnhancedTools.js +18 -59
- package/dist/server/registerEvidenceTools.js +2 -4
- package/dist/server/registerEvmTools.js +2 -4
- package/dist/server/registerFirmwareTools.js +2 -4
- package/dist/server/registerFunctionComparisonTool.js +10 -6
- package/dist/server/registerInvestigationTools.js +7 -7
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -4
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +2 -4
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +2 -4
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +2 -4
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +2 -4
- package/dist/server/registerOfficialTools.js +2 -4
- package/dist/server/registerProcessComparisonTool.js +71 -45
- package/dist/server/registerRecordedCrashTools.js +2 -4
- package/dist/server/registerSessionRecordTools.js +5 -6
- package/dist/server/registerSessionStatusTool.js +17 -3
- package/dist/server/registerSessionTools.js +11 -3
- package/dist/server/registerWebModuleTool.js +2 -4
- package/dist/server/registerWebNetworkCaptureTool.js +2 -4
- package/dist/server/registerWebRuntimeTools.js +3 -7
- package/dist/server/registerWebScriptTool.js +2 -4
- package/dist/server/registerWebSourceLocationTool.js +2 -4
- package/dist/server/runDerivedOperation.js +15 -3
- package/dist/server/sessionAvailabilityPolicy.js +0 -1
- package/dist/server/toolRegistrationOptions.js +2 -2
- package/dist/server/toolResult.js +62 -10
- package/dist/server/toolResultEncoding.js +33 -0
- package/install.sh +1 -1
- package/native/windows/build/manifest.json +1 -1
- package/package.json +8 -3
- package/scripts/electron-active-hook-boundaries.cjs +18 -20
- package/scripts/electron-active-hook.cjs +241 -37
- package/skills/reverse-engineer-anything/SKILL.md +11 -3
- package/skills/reverse-engineer-anything/references/javascript-applications.md +8 -1
- package/dist/ghidra/GhidraDefaults.js +0 -2
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { err, ok } from "../domain/result.js";
|
|
5
4
|
import { silentLogger } from "../logger.js";
|
|
6
5
|
import { PendingOperations } from "../process/PendingOperations.js";
|
|
@@ -8,7 +7,7 @@ import { PrivateRuntimeRoot } from "../process/PrivateRuntimeRoot.js";
|
|
|
8
7
|
import { ProviderStartupDeadline } from "../process/ProviderDeadline.js";
|
|
9
8
|
import { ProviderRunLineage } from "../process/ProviderRunLineage.js";
|
|
10
9
|
import { ProviderProcessSupervisor, } from "../process/ProviderProcess.js";
|
|
11
|
-
import {
|
|
10
|
+
import { DEFAULT_GHIDRA_STARTUP_TIMEOUT_MS } from "../config/ghidraStartupTimeout.js";
|
|
12
11
|
import { createGhidraDiagnostics } from "./GhidraDiagnostics.js";
|
|
13
12
|
import { GhidraResponseBuffer } from "./GhidraResponseBuffer.js";
|
|
14
13
|
import { GhidraResponseRouter } from "./GhidraResponseRouter.js";
|
|
@@ -18,6 +17,7 @@ import { isGhidraShutdownAcknowledgement, parseGhidraSessionInfo, } from "./Ghid
|
|
|
18
17
|
import { createGhidraTargetSnapshot } from "./GhidraTargetSnapshot.js";
|
|
19
18
|
import { readFile } from "node:fs/promises";
|
|
20
19
|
import { connectGhidraSocket } from "./GhidraSocketConnection.js";
|
|
20
|
+
import { createGhidraEndpoint, } from "./GhidraTransport.js";
|
|
21
21
|
import { GhidraWire } from "./GhidraClientWire.js";
|
|
22
22
|
import { completeGhidraStartupHandshake } from "./GhidraClientStartup.js";
|
|
23
23
|
const SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
@@ -32,6 +32,8 @@ export class GhidraClient {
|
|
|
32
32
|
#launch;
|
|
33
33
|
#process;
|
|
34
34
|
#runtimeRoot;
|
|
35
|
+
#socketRoot;
|
|
36
|
+
#endpointPath;
|
|
35
37
|
#snapshotPath;
|
|
36
38
|
#targetAdmission;
|
|
37
39
|
#token;
|
|
@@ -71,7 +73,7 @@ export class GhidraClient {
|
|
|
71
73
|
constructor(options) {
|
|
72
74
|
this.#options = {
|
|
73
75
|
...options,
|
|
74
|
-
startupTimeoutMs: options.startupTimeoutMs ??
|
|
76
|
+
startupTimeoutMs: options.startupTimeoutMs ?? DEFAULT_GHIDRA_STARTUP_TIMEOUT_MS,
|
|
75
77
|
platform: options.platform ?? process.platform,
|
|
76
78
|
transport: options.transport ?? "unix-socket",
|
|
77
79
|
};
|
|
@@ -90,8 +92,11 @@ export class GhidraClient {
|
|
|
90
92
|
start(signal) {
|
|
91
93
|
if (this.#closePromise !== undefined)
|
|
92
94
|
return this.#closePromise.then(() => this.start(signal));
|
|
93
|
-
if (this.#startPromise !== undefined)
|
|
95
|
+
if (this.#startPromise !== undefined) {
|
|
96
|
+
if (this.#startupController?.signal.aborted && !signal?.aborted)
|
|
97
|
+
return this.#startPromise.then((result) => result.ok ? result : this.start(signal));
|
|
94
98
|
return this.#startPromise;
|
|
99
|
+
}
|
|
95
100
|
const controller = new AbortController();
|
|
96
101
|
const onAbort = () => controller.abort(signal?.reason);
|
|
97
102
|
if (signal?.aborted === true)
|
|
@@ -177,10 +182,16 @@ export class GhidraClient {
|
|
|
177
182
|
return err(this.#failure("cancelled", "Ghidra startup was cancelled"));
|
|
178
183
|
if (this.#socket !== undefined || this.#runtimeRoot !== undefined)
|
|
179
184
|
return err(this.#failure("protocol", "Ghidra client is already started"));
|
|
185
|
+
this.#processSnapshot = undefined;
|
|
180
186
|
const deadline = new ProviderStartupDeadline(this.#options.startupTimeoutMs, signal);
|
|
181
187
|
try {
|
|
182
188
|
return await this.#startWithin(deadline);
|
|
183
189
|
}
|
|
190
|
+
catch (cause) {
|
|
191
|
+
if (cause instanceof GhidraSessionError)
|
|
192
|
+
return err(cause);
|
|
193
|
+
throw cause;
|
|
194
|
+
}
|
|
184
195
|
finally {
|
|
185
196
|
deadline.dispose();
|
|
186
197
|
}
|
|
@@ -198,12 +209,18 @@ export class GhidraClient {
|
|
|
198
209
|
}
|
|
199
210
|
if (deadline.signal.aborted)
|
|
200
211
|
return this.#startupInterrupted(deadline);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
let endpoint;
|
|
213
|
+
try {
|
|
214
|
+
const allocated = await createGhidraEndpoint(this.#runtimeRoot.path, this.#options.transport, this.#options.platform);
|
|
215
|
+
endpoint = allocated.endpoint;
|
|
216
|
+
this.#socketRoot = allocated.socketRoot;
|
|
217
|
+
this.#endpointPath = endpoint.path;
|
|
218
|
+
}
|
|
219
|
+
catch (cause) {
|
|
220
|
+
const failure = this.#failure("start", "Ghidra private endpoint allocation failed", cause);
|
|
221
|
+
await this.#cleanup();
|
|
222
|
+
return err(failure);
|
|
223
|
+
}
|
|
207
224
|
try {
|
|
208
225
|
const snapshot = await createGhidraTargetSnapshot(this.#options.targetPath, this.#runtimeRoot.path, this.#options.targetSha256, { signal: deadline.signal, platform: this.#options.platform });
|
|
209
226
|
this.#snapshotPath = snapshot.path;
|
|
@@ -274,7 +291,7 @@ export class GhidraClient {
|
|
|
274
291
|
deadline,
|
|
275
292
|
failure: this.#failure,
|
|
276
293
|
isClosed: () => this.#closing,
|
|
277
|
-
processExited: () => this.#
|
|
294
|
+
processExited: () => this.#process?.snapshot().exitCode !== undefined,
|
|
278
295
|
startupTimeoutMs: this.#options.startupTimeoutMs,
|
|
279
296
|
handlers: {
|
|
280
297
|
data: this.#onSocketData,
|
|
@@ -364,17 +381,26 @@ export class GhidraClient {
|
|
|
364
381
|
reason: stopped.reason,
|
|
365
382
|
});
|
|
366
383
|
this.#logger.warn({ reason: stopped.reason }, "Ghidra process cleanup failed closed");
|
|
367
|
-
|
|
368
|
-
|
|
384
|
+
// Keep the supervisor and private files available for a later close.
|
|
385
|
+
// A still-live JVM can recreate files if its runtime is removed here.
|
|
386
|
+
throw this.#failure("process", `Ghidra process cleanup was incomplete: ${stopped.reason}`);
|
|
369
387
|
}
|
|
370
388
|
}
|
|
371
389
|
this.#lastDiagnostics = this.#diagnostics();
|
|
372
390
|
this.#process = undefined;
|
|
373
391
|
this.#launch = undefined;
|
|
374
392
|
const runtimeRoot = this.#runtimeRoot;
|
|
393
|
+
const socketRoot = this.#socketRoot;
|
|
375
394
|
this.#runtimeRoot = undefined;
|
|
395
|
+
this.#socketRoot = undefined;
|
|
376
396
|
try {
|
|
377
|
-
await
|
|
397
|
+
const removed = await Promise.allSettled([
|
|
398
|
+
runtimeRoot?.close(),
|
|
399
|
+
socketRoot?.close(),
|
|
400
|
+
]);
|
|
401
|
+
const failed = removed.find((result) => result.status === "rejected");
|
|
402
|
+
if (failed?.status === "rejected")
|
|
403
|
+
throw failed.reason;
|
|
378
404
|
}
|
|
379
405
|
catch (cause) {
|
|
380
406
|
if (forceStop)
|
|
@@ -383,6 +409,7 @@ export class GhidraClient {
|
|
|
383
409
|
throw cause;
|
|
384
410
|
}
|
|
385
411
|
this.#snapshotPath = undefined;
|
|
412
|
+
this.#endpointPath = undefined;
|
|
386
413
|
this.#token = undefined;
|
|
387
414
|
this.#runId = undefined;
|
|
388
415
|
this.#responseBuffer.reset();
|
|
@@ -455,6 +482,12 @@ export class GhidraClient {
|
|
|
455
482
|
...(this.#runtimeRoot === undefined
|
|
456
483
|
? {}
|
|
457
484
|
: { runtimeRoot: this.#runtimeRoot.path }),
|
|
485
|
+
...(this.#socketRoot === undefined
|
|
486
|
+
? {}
|
|
487
|
+
: { socketRoot: this.#socketRoot.path }),
|
|
488
|
+
...(this.#endpointPath === undefined
|
|
489
|
+
? {}
|
|
490
|
+
: { endpointPath: this.#endpointPath }),
|
|
458
491
|
...(this.#launch === undefined ? {} : { launch: this.#launch }),
|
|
459
492
|
...(snapshot === undefined ? {} : { snapshot }),
|
|
460
493
|
...(this.#token === undefined ? {} : { token: this.#token }),
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
/** Preserve actionable runtime coordinates after cleanup and redact bearer data. */
|
|
3
2
|
export const createGhidraDiagnostics = (options) => {
|
|
4
3
|
if (options.runtimeRoot === undefined &&
|
|
@@ -20,12 +19,13 @@ export const createGhidraDiagnostics = (options) => {
|
|
|
20
19
|
...(options.runId === undefined ? {} : { run_id: options.runId }),
|
|
21
20
|
...(options.runtimeRoot === undefined
|
|
22
21
|
? {}
|
|
23
|
-
: {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
22
|
+
: { runtime_root: options.runtimeRoot }),
|
|
23
|
+
...(options.socketRoot === undefined
|
|
24
|
+
? {}
|
|
25
|
+
: { socket_root: options.socketRoot }),
|
|
26
|
+
...(options.endpointPath === undefined
|
|
27
|
+
? {}
|
|
28
|
+
: { endpoint_path: options.endpointPath }),
|
|
29
29
|
...(options.launch === undefined
|
|
30
30
|
? {}
|
|
31
31
|
: {
|
|
@@ -2,13 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
import { nativeFunctionAnnotationsInputSchema, nativeFunctionAnnotationsSchema, } from "../domain/native/nativeFunctionAnnotations.js";
|
|
3
3
|
import { nativeDataTypeSchema } from "../domain/native/nativeDataType.js";
|
|
4
4
|
import { nativeInstructionSchema, nativeCallTargetsSchema, } from "../domain/native/nativeInstruction.js";
|
|
5
|
-
import {
|
|
5
|
+
import { AnalysisOutputError, } from "../domain/analysisErrorCore.js";
|
|
6
6
|
import { functionBodyEntryAgrees, functionInstructionWindowSchema, functionDossierSchema, } from "../domain/hopperValues.js";
|
|
7
7
|
import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
|
|
8
8
|
import { nativeApiBoundarySchema } from "../domain/native/nativeApiBoundary.js";
|
|
9
9
|
import { nativeValueFlowSchema } from "../domain/native/nativeValueFlow.js";
|
|
10
10
|
import { err, ok } from "../domain/result.js";
|
|
11
|
-
import {
|
|
11
|
+
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
|
12
|
+
import { ghidraIdentifierSchema, ghidraInputAddressSchema, ghidraCanonicalAddressSchema, ghidraFunctionClassificationSchema as classification, ghidraFunctionBodySchema as ghidraFunctionBody, ghidraProcedureIdentitySchema as procedureIdentity, } from "./GhidraInventoryValues.js";
|
|
12
13
|
/** Function analysis and annotation operations admitted by the Ghidra adapter. */
|
|
13
14
|
export const GHIDRA_FUNCTION_OPERATIONS = [
|
|
14
15
|
"annotate_native_function",
|
|
@@ -37,15 +38,15 @@ const inputSchemas = {
|
|
|
37
38
|
.object({
|
|
38
39
|
document,
|
|
39
40
|
type: z.string().min(1).nullable().default(null),
|
|
40
|
-
address:
|
|
41
|
+
address: ghidraInputAddressSchema.nullable().default(null),
|
|
41
42
|
})
|
|
42
43
|
.strict()
|
|
43
44
|
.refine((value) => (value.type === null) !== (value.address === null), "Supply exactly one of type or address"),
|
|
44
45
|
inspect_native_instruction: z
|
|
45
|
-
.object({ document, address:
|
|
46
|
+
.object({ document, address: ghidraInputAddressSchema })
|
|
46
47
|
.strict(),
|
|
47
48
|
resolve_native_call_targets: z
|
|
48
|
-
.object({ document, address:
|
|
49
|
+
.object({ document, address: ghidraInputAddressSchema })
|
|
49
50
|
.strict(),
|
|
50
51
|
analyze_function: z.object({ procedure }).strict(),
|
|
51
52
|
procedure_assembly: z.object(directProcedure).strict(),
|
|
@@ -60,14 +61,16 @@ const inputSchemas = {
|
|
|
60
61
|
direction: z.enum(["incoming", "outgoing"]).default("outgoing"),
|
|
61
62
|
})
|
|
62
63
|
.strict(),
|
|
63
|
-
xrefs: z.object({ document, address:
|
|
64
|
+
xrefs: z.object({ document, address: ghidraInputAddressSchema }).strict(),
|
|
64
65
|
};
|
|
65
66
|
/** Validate and default one function request before it crosses the socket. */
|
|
66
67
|
export const parseGhidraFunctionInput = (operation, value) => {
|
|
67
68
|
const parsed = inputSchemas[operation].safeParse(value);
|
|
68
69
|
return parsed.success
|
|
69
70
|
? ok(jsonObjectSchema.parse(Object.fromEntries(Object.entries(parsed.data).filter(([, value]) => value !== undefined))))
|
|
70
|
-
: err(
|
|
71
|
+
: err(analysisInputErrorFromIssues(operation, parsed.error.issues, value, {
|
|
72
|
+
cause: parsed.error,
|
|
73
|
+
}));
|
|
71
74
|
};
|
|
72
75
|
const localVariable = z
|
|
73
76
|
.object({
|
|
@@ -4,6 +4,11 @@ import { accessSync, readFileSync } from "node:fs";
|
|
|
4
4
|
import { posix, win32 } from "node:path";
|
|
5
5
|
import { ghidraApplicationProperties, ghidraJavaMajorAccepted, ghidraJavaRangeLabel, ghidraJavaRequirement, ghidraReleaseAccepted, ghidraReleaseCompatibility, ghidraReleaseLine, ghidraVersionDetail, SUPPORTED_GHIDRA_JAVA_MAJOR, SUPPORTED_GHIDRA_VERSION, } from "./GhidraInstallationPolicy.js";
|
|
6
6
|
export { SUPPORTED_GHIDRA_JAVA_MAJOR, SUPPORTED_GHIDRA_VERSION };
|
|
7
|
+
const NATIVE_PLATFORMS = {
|
|
8
|
+
linux: { x64: "linux_x86_64", arm64: "linux_arm_64" },
|
|
9
|
+
darwin: { x64: "mac_x86_64", arm64: "mac_arm_64" },
|
|
10
|
+
win32: { x64: "win_x86_64" },
|
|
11
|
+
};
|
|
7
12
|
/** Inspect an installation without importing a target or modifying Ghidra. */
|
|
8
13
|
export const inspectGhidraInstallation = (options, host = systemGhidraInstallationHost()) => {
|
|
9
14
|
const platform = options.platform ?? process.platform;
|
|
@@ -67,16 +72,13 @@ const installationCoordinates = (options, platform, architecture, host) => {
|
|
|
67
72
|
const analyzeHeadlessPath = installDir === null
|
|
68
73
|
? null
|
|
69
74
|
: path.join(installDir, "support", platform === "win32" ? "analyzeHeadless.bat" : "analyzeHeadless");
|
|
70
|
-
const decompilerPlatform = platform
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
: "mac_x86_64"
|
|
74
|
-
: null;
|
|
75
|
-
const nativeDecompilerPath = installDir === null || decompilerPlatform === null
|
|
75
|
+
const decompilerPlatform = NATIVE_PLATFORMS[platform]?.[architecture];
|
|
76
|
+
const decompilerExecutable = platform === "win32" ? "decompile.exe" : "decompile";
|
|
77
|
+
const nativeDecompilerPath = installDir === null || decompilerPlatform === undefined
|
|
76
78
|
? null
|
|
77
79
|
: ([
|
|
78
|
-
path.join(installDir, "Ghidra", "Features", "Decompiler", "os", decompilerPlatform,
|
|
79
|
-
path.join(installDir, "Ghidra", "Features", "Decompiler", "build", "os", decompilerPlatform,
|
|
80
|
+
path.join(installDir, "Ghidra", "Features", "Decompiler", "os", decompilerPlatform, decompilerExecutable),
|
|
81
|
+
path.join(installDir, "Ghidra", "Features", "Decompiler", "build", "os", decompilerPlatform, decompilerExecutable),
|
|
80
82
|
].find((candidate) => host.executable(candidate)) ?? null);
|
|
81
83
|
const properties = applicationPropertiesPath === null
|
|
82
84
|
? undefined
|
|
@@ -108,20 +110,17 @@ const installationChecks = ({ coordinates, platform, architecture, javaHome, hos
|
|
|
108
110
|
}),
|
|
109
111
|
installationCheck({
|
|
110
112
|
name: "platform",
|
|
111
|
-
passed: platform
|
|
113
|
+
passed: NATIVE_PLATFORMS[platform] !== undefined,
|
|
112
114
|
code: "unsupported_host",
|
|
113
115
|
detail: platform,
|
|
114
|
-
remediation: "Use Linux or
|
|
116
|
+
remediation: "Use Linux or macOS x64/arm64, or Windows x64 with matching native Ghidra tools.",
|
|
115
117
|
}),
|
|
116
118
|
installationCheck({
|
|
117
119
|
name: "architecture",
|
|
118
|
-
passed:
|
|
119
|
-
architecture === "x64") ||
|
|
120
|
-
(platform === "darwin" &&
|
|
121
|
-
(architecture === "x64" || architecture === "arm64")),
|
|
120
|
+
passed: NATIVE_PLATFORMS[platform]?.[architecture] !== undefined,
|
|
122
121
|
code: "unsupported_host",
|
|
123
122
|
detail: architecture,
|
|
124
|
-
remediation: "Use x64 on Linux or
|
|
123
|
+
remediation: "Use x64/arm64 on Linux or macOS, or x64 on Windows.",
|
|
125
124
|
}),
|
|
126
125
|
installationCheck({
|
|
127
126
|
name: "installation",
|
|
@@ -142,13 +141,11 @@ const installationChecks = ({ coordinates, platform, architecture, javaHome, hos
|
|
|
142
141
|
}),
|
|
143
142
|
installationCheck({
|
|
144
143
|
name: "native_decompiler",
|
|
145
|
-
passed:
|
|
144
|
+
passed: coordinates.nativeDecompilerPath !== null,
|
|
146
145
|
code: "executable_missing",
|
|
147
|
-
detail:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
"matching macOS native decompiler was not found"),
|
|
151
|
-
remediation: "REA does not build native tools. Build Ghidra's native components for this macOS architecture or provide an installation containing Ghidra/Features/Decompiler/os/<platform>/decompile.",
|
|
146
|
+
detail: coordinates.nativeDecompilerPath ??
|
|
147
|
+
`Matching native decompiler for ${platform}/${architecture} was not found`,
|
|
148
|
+
remediation: `Provide an executable Ghidra/Features/Decompiler/os/${NATIVE_PLATFORMS[platform]?.[architecture] ?? "<platform>"}/${platform === "win32" ? "decompile.exe" : "decompile"}, or its build/os equivalent. REA does not build or install native tools.`,
|
|
152
149
|
}),
|
|
153
150
|
javaCheck(coordinates.java, coordinates.javaCommand, javaHome, coordinates.properties),
|
|
154
151
|
];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { nativeLoadImageObservationSchema } from "../domain/native/nativeLoadImage.js";
|
|
3
|
-
import {
|
|
3
|
+
import { AnalysisOutputError, } from "../domain/analysisErrorCore.js";
|
|
4
4
|
import { functionBodySchema, functionBodyEntryAgrees, } from "../domain/hopperValues.js";
|
|
5
5
|
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
6
6
|
import { err, ok } from "../domain/result.js";
|
|
7
|
+
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
|
7
8
|
/** Read-only direct inventory operations admitted by the Ghidra adapter. */
|
|
8
9
|
export const GHIDRA_INVENTORY_OPERATIONS = [
|
|
9
10
|
"inspect_native_load_image",
|
|
@@ -26,7 +27,11 @@ export const isGhidraInventoryOperation = (operation) => operationSet.has(operat
|
|
|
26
27
|
export const ghidraIdentifierSchema = z.string().min(1);
|
|
27
28
|
const identifier = ghidraIdentifierSchema;
|
|
28
29
|
const document = identifier.nullable().default(null);
|
|
29
|
-
|
|
30
|
+
/** Caller address spelling; the bridge resolves its space and emits canonical output. */
|
|
31
|
+
export const ghidraInputAddressSchema = z
|
|
32
|
+
.string()
|
|
33
|
+
.regex(/^(?:(?:0[xX])?[0-9a-fA-F]+|(?:[A-Za-z0-9._~-]|%[0-9a-fA-F]{2})+:0[xX][0-9a-fA-F]+)$/u, "Use hexadecimal digits, optionally prefixed with 0x, or an encoded address-space name followed by :0x and hexadecimal digits");
|
|
34
|
+
const explicitAddress = ghidraInputAddressSchema;
|
|
30
35
|
const filteredAddress = explicitAddress.nullable().default(null);
|
|
31
36
|
const searchInput = {
|
|
32
37
|
pattern: z.string().min(1),
|
|
@@ -62,7 +67,9 @@ const inputSchemas = {
|
|
|
62
67
|
export const parseGhidraInventoryInput = (operation, value) => {
|
|
63
68
|
const parsed = inputSchemas[operation].safeParse(value);
|
|
64
69
|
if (!parsed.success)
|
|
65
|
-
return err(
|
|
70
|
+
return err(analysisInputErrorFromIssues(operation, parsed.error.issues, value, {
|
|
71
|
+
cause: parsed.error,
|
|
72
|
+
}));
|
|
66
73
|
return ok(parsed.data);
|
|
67
74
|
};
|
|
68
75
|
export const ghidraCanonicalAddressSchema = z
|
|
@@ -171,7 +178,10 @@ const containingProcedure = z.discriminatedUnion("found", [
|
|
|
171
178
|
.strict()
|
|
172
179
|
.superRefine((value, context) => {
|
|
173
180
|
const body = value.procedure.body;
|
|
174
|
-
|
|
181
|
+
const exactExternalEntry = value.procedure.classification.external &&
|
|
182
|
+
value.query_address === value.procedure.address;
|
|
183
|
+
if (!exactExternalEntry &&
|
|
184
|
+
body.available &&
|
|
175
185
|
!functionBodyEntryAgrees({ ...body, contains_entry: true }, value.query_address))
|
|
176
186
|
context.addIssue({
|
|
177
187
|
code: "custom",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { execFileOutput } from "../process/ExecFileOutput.js";
|
|
3
|
+
/** Launch coordinates obtained from Ghidra's own release configuration helper. */
|
|
4
|
+
export const ghidraJavaLaunch = async (options) => {
|
|
5
|
+
const supportRoot = dirname(options.analyzeHeadlessPath);
|
|
6
|
+
const installRoot = dirname(supportRoot);
|
|
7
|
+
const command = join(options.javaHome, "bin", "java");
|
|
8
|
+
const isolatedProperties = [
|
|
9
|
+
`-Duser.home=${options.homeRoot}`,
|
|
10
|
+
`-Djava.io.tmpdir=${options.tempRoot}`,
|
|
11
|
+
];
|
|
12
|
+
const supportArguments = [
|
|
13
|
+
...isolatedProperties,
|
|
14
|
+
"-cp",
|
|
15
|
+
join(supportRoot, "LaunchSupport.jar"),
|
|
16
|
+
"LaunchSupport",
|
|
17
|
+
installRoot,
|
|
18
|
+
];
|
|
19
|
+
const environment = { ...options.environment };
|
|
20
|
+
const configuredEnvironment = await execFileOutput(command, [...supportArguments, "-envvars"], {
|
|
21
|
+
env: environment,
|
|
22
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
23
|
+
});
|
|
24
|
+
for (const line of configuredEnvironment.stdout.split(/\r?\n/u)) {
|
|
25
|
+
if (line === "")
|
|
26
|
+
continue;
|
|
27
|
+
const separator = line.indexOf("=");
|
|
28
|
+
const key = line.slice(0, separator);
|
|
29
|
+
if (separator < 1 || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key))
|
|
30
|
+
throw new Error(`Invalid Ghidra LaunchSupport environment entry: ${line}`);
|
|
31
|
+
if ((environment[key] ?? "") === "")
|
|
32
|
+
environment[key] = line.slice(separator + 1);
|
|
33
|
+
}
|
|
34
|
+
const configuredArguments = await execFileOutput(command, [...supportArguments, "-vmargs"], {
|
|
35
|
+
env: environment,
|
|
36
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
37
|
+
});
|
|
38
|
+
const vmArguments = configuredArguments.stdout
|
|
39
|
+
.split(/\r?\n/u)
|
|
40
|
+
.filter((line) => line !== "");
|
|
41
|
+
if (vmArguments.some((argument) => !argument.startsWith("-") || argument.includes("\0")))
|
|
42
|
+
throw new Error("Invalid Ghidra LaunchSupport JVM argument");
|
|
43
|
+
return {
|
|
44
|
+
command,
|
|
45
|
+
environment,
|
|
46
|
+
arguments: [
|
|
47
|
+
...vmArguments,
|
|
48
|
+
...(options.platform === "darwin" ? ["-Xdock:name=Ghidra-Headless"] : []),
|
|
49
|
+
`-Xmx${environment.GHIDRA_HEADLESS_MAXMEM || environment.GHIDRA_MAXMEM || "2G"}`,
|
|
50
|
+
"-XX:ParallelGCThreads=2",
|
|
51
|
+
"-XX:CICompilerCount=2",
|
|
52
|
+
"-Djava.awt.headless=true",
|
|
53
|
+
...isolatedProperties,
|
|
54
|
+
"-showversion",
|
|
55
|
+
"-cp",
|
|
56
|
+
join(installRoot, "Ghidra", "Framework", "Utility", "lib", "Utility.jar"),
|
|
57
|
+
"ghidra.Ghidra",
|
|
58
|
+
"ghidra.app.util.headless.AnalyzeHeadless",
|
|
59
|
+
...options.arguments,
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -7,6 +7,7 @@ import { err, ok } from "../domain/result.js";
|
|
|
7
7
|
import { cleanupOwnedProcessGroup, cleanupWindowsProcessTree, } from "../process/ProcessOwnership.js";
|
|
8
8
|
import { spawnOwnedProviderProcess, } from "../process/ProviderProcess.js";
|
|
9
9
|
import { ghidraJavaEnvironment } from "./GhidraInstallation.js";
|
|
10
|
+
import { ghidraJavaLaunch } from "./GhidraJavaLaunch.js";
|
|
10
11
|
import { snapshotGhidraExtensions, } from "./extensions/GhidraExtensions.js";
|
|
11
12
|
/** Local launch failure retained as the cause of a provider-neutral error. */
|
|
12
13
|
export class GhidraLaunchError extends Error {
|
|
@@ -58,7 +59,7 @@ export class GhidraHeadlessLauncher {
|
|
|
58
59
|
? {}
|
|
59
60
|
: { dosMz: this.options.dosMz }),
|
|
60
61
|
});
|
|
61
|
-
const
|
|
62
|
+
const scriptCommand = ghidraHeadlessCommand({
|
|
62
63
|
platform,
|
|
63
64
|
analyzeHeadlessPath: this.options.analyzeHeadlessPath,
|
|
64
65
|
arguments: headlessArguments,
|
|
@@ -66,25 +67,45 @@ export class GhidraHeadlessLauncher {
|
|
|
66
67
|
? {}
|
|
67
68
|
: { comSpec: this.options.comSpec }),
|
|
68
69
|
});
|
|
70
|
+
const environment = ghidraLaunchEnvironment(paths, this.options.javaHome, platform, scriptCommand.command);
|
|
71
|
+
if (platform !== "win32" && this.options.javaHome === undefined)
|
|
72
|
+
throw new GhidraLaunchError("POSIX Ghidra requires its inspected JDK home");
|
|
73
|
+
const command = platform !== "win32" && this.options.javaHome !== undefined
|
|
74
|
+
? await ghidraJavaLaunch({
|
|
75
|
+
platform,
|
|
76
|
+
analyzeHeadlessPath: this.options.analyzeHeadlessPath,
|
|
77
|
+
javaHome: this.options.javaHome,
|
|
78
|
+
homeRoot: paths.homeRoot,
|
|
79
|
+
tempRoot: paths.tempRoot,
|
|
80
|
+
arguments: headlessArguments,
|
|
81
|
+
environment,
|
|
82
|
+
...(options.signal === undefined
|
|
83
|
+
? {}
|
|
84
|
+
: { signal: options.signal }),
|
|
85
|
+
})
|
|
86
|
+
: { ...scriptCommand, environment };
|
|
69
87
|
started = await spawnOwnedProviderProcess({
|
|
70
88
|
command: command.command,
|
|
71
89
|
arguments: command.arguments,
|
|
72
90
|
runId: session.runId,
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
expectedCommand: null,
|
|
91
|
+
// POSIX launches the inspected JVM directly; script wrappers cannot
|
|
92
|
+
// preserve JVM property paths containing spaces as single arguments.
|
|
93
|
+
expectedCommand: platform !== "win32" ? command.command : null,
|
|
76
94
|
windowsVerbatimArguments: platform === "win32",
|
|
77
95
|
platform,
|
|
78
|
-
env:
|
|
96
|
+
env: command.environment,
|
|
79
97
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
80
98
|
});
|
|
81
99
|
await writeGhidraRuntimeFile(paths.ownershipPath, `${JSON.stringify({
|
|
82
100
|
run_id: session.runId,
|
|
101
|
+
transport: session.transport,
|
|
102
|
+
endpoint_path: session.endpointPath,
|
|
83
103
|
pid: started.ownership.leaderPid,
|
|
84
104
|
process_group_id: started.ownership.processGroupId,
|
|
85
105
|
parent_pid: process.pid,
|
|
86
106
|
ownership_kind: platform === "win32" ? "windows-job-object" : "posix-process-group",
|
|
87
|
-
launcher:
|
|
107
|
+
launcher: command.command,
|
|
108
|
+
headless_script: this.options.analyzeHeadlessPath,
|
|
88
109
|
created_at: new Date().toISOString(),
|
|
89
110
|
})}\n`, platform);
|
|
90
111
|
if (isAborted(options.signal)) {
|
|
@@ -267,22 +288,18 @@ const ghidraLaunchEnvironment = (paths, javaHome, platform, executable) => {
|
|
|
267
288
|
XDG_DATA_HOME: paths.dataRoot,
|
|
268
289
|
};
|
|
269
290
|
};
|
|
270
|
-
/** Encode provider-owned JVM paths for the
|
|
291
|
+
/** Encode provider-owned JVM paths for the platform launcher that consumes them. */
|
|
271
292
|
export const ghidraHeadlessJavaOptions = (homeRoot, tempRoot, platform) => {
|
|
272
293
|
const options = [`-Duser.home=${homeRoot}`, `-Djava.io.tmpdir=${tempRoot}`];
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// JDK_JAVA_OPTIONS is parsed by Java itself, outside that batch expansion.
|
|
276
|
-
return platform === "win32"
|
|
277
|
-
? {
|
|
294
|
+
if (platform === "win32")
|
|
295
|
+
return {
|
|
278
296
|
JDK_JAVA_OPTIONS: [...options, "-XX:-UsePerfData"]
|
|
279
297
|
.map(quoteWindowsBatchToken)
|
|
280
298
|
.join(" "),
|
|
281
299
|
GHIDRA_HEADLESS_JAVA_OPTIONS: "",
|
|
282
|
-
}
|
|
283
|
-
: {
|
|
284
|
-
JDK_JAVA_OPTIONS: "",
|
|
285
|
-
GHIDRA_HEADLESS_JAVA_OPTIONS: options.join(" "),
|
|
286
300
|
};
|
|
301
|
+
// POSIX launches the JVM directly, so these properties travel as separate
|
|
302
|
+
// argv items instead of the shell-split analyzeHeadless option list.
|
|
303
|
+
return { JDK_JAVA_OPTIONS: "", GHIDRA_HEADLESS_JAVA_OPTIONS: "" };
|
|
287
304
|
};
|
|
288
305
|
const isAborted = (signal) => signal?.aborted === true;
|
|
@@ -16,6 +16,7 @@ export const GHIDRA_OPERATIONS = Object.freeze([
|
|
|
16
16
|
export const healthLimitations = Object.freeze([
|
|
17
17
|
"The session serves operations only after Ghidra reports default auto-analysis complete; incomplete analysis does not expose partial results.",
|
|
18
18
|
"The imported Program and temporary project are ephemeral and deleted on close. Annotation operations edit session database metadata; original executable bytes are never written.",
|
|
19
|
+
"Cancelling an active Ghidra request terminates its ephemeral database and discards session annotations. The selected target remains open; the next provider query imports the original artifact again.",
|
|
19
20
|
]);
|
|
20
21
|
/** Additional limitations applied to the experimental Windows x64 P0 boundary. */
|
|
21
22
|
export const windowsP0Limitations = Object.freeze([
|
|
@@ -33,7 +34,8 @@ export const limitationsFor = (operation) => {
|
|
|
33
34
|
case "annotate_native_function":
|
|
34
35
|
return [
|
|
35
36
|
...common,
|
|
36
|
-
"Names use Ghidra USER_DEFINED source. Name writes
|
|
37
|
+
"Names use Ghidra USER_DEFINED source. Name writes accept a leaf name or a fully qualified name within the existing namespace; readback uses the fully qualified name and can be reused without adding namespace prefixes. Edits retain the current namespace; other namespace-like text remains literal leaf-name text. Regular comments map to PRE and inline comments to EOL at the exact function entry. Changes commit together after readback and refreshed analysis; failure rolls them all back.",
|
|
38
|
+
"Annotation text rejects NUL and unpaired Unicode surrogates before mutation, with the field and UTF-16 index in the error. Supported Unicode and line endings are preserved.",
|
|
37
39
|
"Metadata edits invalidate immutable analysis snapshots and are discarded on close. CLI returns the updated dossier before session cleanup; this is not a saved Ghidra project.",
|
|
38
40
|
];
|
|
39
41
|
case "inspect_native_load_image":
|
|
@@ -72,6 +74,11 @@ export const limitationsFor = (operation) => {
|
|
|
72
74
|
...common,
|
|
73
75
|
"Only Ghidra-defined string Data is observed; charset is reported, while a non-missing terminator cannot distinguish a present terminator from a fixed or Pascal layout.",
|
|
74
76
|
];
|
|
77
|
+
case "resolve_containing_procedure":
|
|
78
|
+
return [
|
|
79
|
+
...common,
|
|
80
|
+
"An exact external entry resolves to its observed function identity even when its body is empty. This does not establish mapped executable bytes or containment of nearby external addresses.",
|
|
81
|
+
];
|
|
75
82
|
case "list_segments":
|
|
76
83
|
return [
|
|
77
84
|
...common,
|
|
@@ -79,7 +86,10 @@ export const limitationsFor = (operation) => {
|
|
|
79
86
|
];
|
|
80
87
|
case "search_procedures":
|
|
81
88
|
case "search_strings":
|
|
82
|
-
return
|
|
89
|
+
return [
|
|
90
|
+
...common,
|
|
91
|
+
"Regex mode uses Java Pattern semantics. Matcher or compiler stack exhaustion returns a resource constraint without closing the session; literal mode avoids regex recursion and returns complete matching values.",
|
|
92
|
+
];
|
|
83
93
|
case "procedure_pseudo_code":
|
|
84
94
|
return [
|
|
85
95
|
...common,
|
|
@@ -112,12 +122,14 @@ export const limitationsFor = (operation) => {
|
|
|
112
122
|
case "procedure_references":
|
|
113
123
|
return [
|
|
114
124
|
...common,
|
|
125
|
+
"References cover the complete Ghidra function-body AddressSet and exact entry, including instruction-interior destinations and embedded-data sources; an enclosing address span does not establish function ownership.",
|
|
115
126
|
"Reference kinds are direct Ghidra ReferenceManager observations; unresolved computed flows without a target are absent and remain unknown.",
|
|
116
127
|
"Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
|
|
117
128
|
];
|
|
118
129
|
case "analyze_function":
|
|
119
130
|
return [
|
|
120
131
|
...common,
|
|
132
|
+
"References cover the complete Ghidra function-body AddressSet and exact entry. Dossier incoming edges omit sources owned by that function; procedure_references also retains those internal edges.",
|
|
121
133
|
"The dossier combines Ghidra FunctionManager, Listing, ReferenceManager, BasicBlockModel, and decompiler observations; provider-specific pseudocode and assembly are not cross-provider text invariants.",
|
|
122
134
|
"Resolved reference metadata identifies computed, indirect, external, call, jump, and data edges; unresolved targetless flows remain unknown, and function classifications distinguish thunks and externals.",
|
|
123
135
|
"Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
|