rea-agents 6.0.0 → 6.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 +26 -18
- package/bridge/android/ReaJadxBridge.java +14 -5
- package/bridge/ghidra/ReaGhidraBridge.java +205 -51
- package/bridge/hopper_bridge.py +314 -127
- 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 +274 -31
- package/dist/android/JadxMcpTransport.js +18 -2
- package/dist/android/JadxProtocol.js +6 -0
- package/dist/android/JadxProvider.js +76 -37
- 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/BinaryTargetResolver.js +5 -3
- package/dist/application/BrowserEvidence.js +3 -8
- package/dist/application/BrowserScenarioEvidence.js +2 -18
- package/dist/application/CallPathTracing.js +19 -3
- package/dist/application/CapabilityInventory.js +48 -11
- package/dist/application/ClientConfigurationDocument.js +917 -8
- package/dist/application/ClientRegistrationIdentity.js +26 -5
- package/dist/application/ClientRegistrationStatus.js +29 -14
- package/dist/application/DirectAnalysis.js +56 -51
- package/dist/application/DirectAnalysisCleanup.js +72 -0
- package/dist/application/DirectAnalysisStatus.js +4 -5
- package/dist/application/Doctor.js +19 -21
- package/dist/application/DoctorDiagnostics.js +1 -2
- package/dist/application/DoctorScope.js +25 -13
- package/dist/application/EnhancedLiteralTracing.js +22 -25
- package/dist/application/EnhancedTools.js +64 -17
- package/dist/application/EvidenceBundleFiles.js +30 -13
- package/dist/application/FunctionAnalysisEvidence.js +2 -3
- package/dist/application/InventoryProjectionEvidence.js +4 -3
- package/dist/application/InvestigationProviders.js +11 -2
- package/dist/application/JsonFiles.js +83 -28
- package/dist/application/LinuxHopper.js +9 -6
- package/dist/application/MacHopper.js +15 -18
- package/dist/application/ProcedureAddressResolution.js +11 -0
- package/dist/application/RealHopperAssertions.js +0 -11
- package/dist/application/ReconstructionCoverageService.js +7 -4
- package/dist/application/ReconstructionObligationCandidates.js +1 -1
- package/dist/application/ReconstructionObligationLedgerService.js +4 -3
- package/dist/application/ReferenceSourceImportEntries.js +1 -1
- package/dist/application/Setup.js +21 -17
- package/dist/application/SetupClientConfiguration.js +10 -15
- package/dist/application/SetupHost.js +21 -29
- package/dist/application/SetupPlan.js +11 -9
- package/dist/application/SupportedClients.js +34 -1
- package/dist/application/Uninstall.js +82 -29
- package/dist/application/Update.js +18 -3
- package/dist/application/UpdateMaintenance.js +7 -5
- package/dist/application/UpdateRuntime.js +57 -36
- 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 +32 -6
- package/dist/application/WebSourceLocationService.js +4 -2
- package/dist/application/WorkflowEvidence.js +105 -0
- package/dist/application/XrefsAddressResolution.js +45 -0
- package/dist/application/analysisView/AnalysisViewService.js +76 -0
- package/dist/application/binary/AnalysisClientCleanup.js +30 -5
- package/dist/application/binary/AnalysisProviderEvaluation.js +22 -7
- package/dist/application/binary/AnalysisProviderRegistry.js +4 -6
- package/dist/application/binary/AnalysisSnapshotCache.js +13 -14
- package/dist/application/binary/BinarySession.js +161 -93
- package/dist/application/binary/BinarySessionComposition.js +1 -3
- package/dist/application/binary/BinarySessionExecution.js +3 -5
- package/dist/application/binary/BinarySessionOpen.js +4 -4
- package/dist/application/binary/BinarySessionRecords.js +26 -4
- package/dist/application/binary/BinarySessionStatus.js +18 -7
- package/dist/application/binary/CompositeProvider.js +16 -17
- package/dist/application/binary/LazyAnalysisProvider.js +8 -5
- package/dist/application/binary/SessionProviderRouter.js +27 -135
- 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/homebrew.js +48 -0
- package/dist/application/investigation/EvidenceLedger.js +21 -7
- package/dist/application/investigation/InvestigationRecords.js +8 -0
- package/dist/application/javascript/ElectronActiveEvidence.js +9 -13
- package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +21 -4
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +27 -15
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +10 -7
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +44 -10
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +12 -3
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +49 -19
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +56 -8
- package/dist/application/javascript/JavaScriptModuleRelationships.js +38 -9
- package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +6 -4
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -2
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +1 -5
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +75 -46
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +64 -19
- package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
- package/dist/application/managed/ManagedMemberComparisonService.js +9 -5
- package/dist/application/managed/ManagedNativeVerificationService.js +6 -4
- package/dist/application/managed/ManagedReconstructionService.js +4 -3
- package/dist/application/process/ProcessCli.js +25 -17
- package/dist/application/process/ProcessEvidence.js +4 -4
- package/dist/application/workflowInputError.js +18 -0
- package/dist/artifacts/ArtifactProvider.js +48 -13
- package/dist/artifacts/ArtifactReader.js +31 -0
- package/dist/artifacts/DirectoryArtifactReader.js +2 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +106 -15
- package/dist/artifacts/NativeDmgArtifactReader.js +73 -21
- package/dist/artifacts/SafeOutputTree.js +16 -2
- package/dist/artifacts/ZipArtifactReader.js +11 -4
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +26 -5
- package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +55 -23
- 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/extraction/ArtifactExtraction.js +78 -21
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +79 -68
- package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
- package/dist/artifacts/inventory/reader.js +3 -3
- package/dist/artifacts/inventory/scanCanonical.js +59 -38
- package/dist/artifacts/inventory/scanReader.js +5 -9
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
- package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
- package/dist/browser/CdpBrowserProvider.js +2 -3
- package/dist/browser/CdpCaptureCompleteness.js +2 -0
- package/dist/browser/CdpCaptureEventHandlers.js +78 -15
- package/dist/browser/CdpCaptureEventTypes.js +5 -1
- package/dist/browser/CdpCaptureEvents.js +25 -1
- package/dist/browser/CdpCaptureValues.js +20 -0
- package/dist/browser/CdpConnection.js +30 -11
- package/dist/browser/CdpElectronProvider.js +0 -2
- package/dist/browser/CdpElectronScriptEvents.js +2 -8
- package/dist/browser/CdpElectronScripts.js +2 -3
- package/dist/browser/CdpOptionalCommand.js +2 -3
- package/dist/browser/CdpPageCapture.js +23 -1
- package/dist/browser/CdpPageCaptureScripts.js +2 -3
- package/dist/browser/CdpSafeMetadata.js +10 -10
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +59 -44
- package/dist/browser/PlaywrightElectronActiveActions.js +34 -79
- package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +133 -130
- package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
- package/dist/browser/PlaywrightScenarioBrowser.js +139 -39
- package/dist/browser/PlaywrightScenarioEvents.js +1 -1
- package/dist/browser/PlaywrightScenarioSession.js +39 -22
- package/dist/browser/WebSourceMapFetcher.js +426 -72
- package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
- package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
- package/dist/browser/history/CaptureFailures.js +41 -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/browser/history/MitmproxyCaptureAdapter.js +4 -2
- package/dist/catalogIdentity.js +0 -1
- package/dist/cli/analysisSelector.js +23 -0
- package/dist/cli/analysisViewCommands.js +36 -0
- package/dist/cli/applicationCommands.js +2 -3
- package/dist/cli/artifactCommands.js +11 -12
- package/dist/cli/coreAnalysisCommands.js +3 -3
- package/dist/cli/coreBinaryCommands.js +100 -37
- package/dist/cli/coreNativeCommands.js +9 -10
- package/dist/cli/electronCommands.js +10 -9
- package/dist/cli/interactiveSetup.js +6 -6
- package/dist/cli/javascriptApplicationAnalysis.js +7 -3
- package/dist/cli/jsonOutput.js +4 -99
- package/dist/cli/managedCommands.js +7 -8
- package/dist/cli/nativeCallCommands.js +3 -5
- package/dist/cli/omittableDefaults.js +50 -0
- package/dist/cli/processCommands.js +3 -2
- package/dist/cli/setupCommands.js +16 -15
- package/dist/cli/utilityCommands.js +9 -9
- package/dist/cli/webRuntimeCommands.js +8 -8
- package/dist/cli.js +18 -9
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +1 -1
- package/dist/cliJsonInput.js +24 -5
- package/dist/cliOutput.js +0 -38
- package/dist/composition/auxiliaryAnalysisProviders.js +27 -23
- package/dist/composition/binary.js +9 -9
- package/dist/composition/browserScenario.js +2 -1
- package/dist/composition/directAnalysis.js +20 -13
- package/dist/composition/electronScenario.js +1 -1
- package/dist/composition/optionalObservationProviders.js +12 -7
- package/dist/config/environment.js +10 -0
- package/dist/config/ghidraStartupTimeout.js +12 -0
- package/dist/config/homeDirectory.js +12 -0
- package/dist/config/mcpResponseBudget.js +30 -0
- package/dist/config/parseConfig.js +8 -3
- package/dist/config/parsers.js +19 -22
- package/dist/contracts/analysisViewToolContracts.js +56 -0
- package/dist/contracts/applicationToolContracts.js +5 -4
- package/dist/contracts/artifactComparisonExample.js +2 -2
- package/dist/contracts/artifactToolContracts.js +1 -1
- package/dist/contracts/browserScenarioToolContracts.js +1 -1
- package/dist/contracts/browserToolContracts.js +19 -15
- package/dist/contracts/enhancedInputs.js +7 -5
- package/dist/contracts/enhancedToolContracts.js +7 -6
- package/dist/contracts/evm/evmToolContracts.js +1 -1
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/hopperMemoryContracts.js +2 -5
- package/dist/contracts/inputSchemaPresentation.js +90 -0
- package/dist/contracts/investigationExamples.js +4 -3
- package/dist/contracts/javascript/electronToolContracts.js +2 -2
- package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +0 -20
- package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +245 -0
- package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +7 -14
- package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
- package/dist/contracts/mobileApplicationGraphExamples.js +3 -3
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
- package/dist/contracts/native/nativeToolContracts.js +5 -3
- package/dist/contracts/officialToolContracts.js +16 -16
- package/dist/contracts/promptContracts.js +5 -5
- package/dist/contracts/providerSelection.js +1 -1
- package/dist/contracts/sessionLifecycleInputs.js +3 -7
- package/dist/contracts/sessionStatusContract.js +2 -4
- package/dist/contracts/sessionToolContracts.js +18 -8
- package/dist/contracts/sessionToolSchemas.js +3 -19
- package/dist/contracts/toolContractExamples.js +0 -1
- package/dist/contracts/toolContractHelpers.js +4 -1
- package/dist/contracts/toolContracts.js +2 -0
- package/dist/contracts/toolEffects.js +1 -1
- package/dist/contracts/toolOutputSchemaGroups.js +160 -115
- package/dist/contracts/toolOutputSchemaPrimitives.js +28 -20
- package/dist/contracts/toolSchemaMetadata.js +41 -33
- package/dist/contracts/webNetworkCaptureToolContracts.js +2 -2
- package/dist/contracts/webRuntimeToolContracts.js +1 -1
- package/dist/contracts/webScriptToolContracts.js +1 -1
- package/dist/doctorRuntime.js +7 -5
- package/dist/domain/analysisErrorBase.js +8 -3
- package/dist/domain/analysisErrorCore.js +6 -1
- package/dist/domain/analysisErrorPresentation.js +90 -20
- package/dist/domain/analysisErrorProjection.js +130 -32
- package/dist/domain/analysisSnapshot.js +29 -31
- package/dist/domain/analysisView/analysisView.js +243 -0
- package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
- package/dist/domain/analysisView/binaryLayoutView.js +159 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
- package/dist/domain/android/androidAnalysis.js +2 -4
- package/dist/domain/android/androidApplication.js +18 -10
- package/dist/domain/apple/appleApplication.js +42 -15
- package/dist/domain/apple/dyldEnvironment.js +73 -0
- package/dist/domain/apple/dylibResolution.js +130 -12
- package/dist/domain/apple/dylibResolutionFindings.js +9 -7
- package/dist/domain/apple/interfaceBuilderGraph.js +25 -14
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
- package/dist/domain/apple/keyedArchive.js +35 -3
- package/dist/domain/apple/machoContainer.js +54 -0
- package/dist/domain/apple/plistNumbers.js +76 -0
- package/dist/domain/artifactComparison.js +15 -6
- package/dist/domain/artifactGraph.js +16 -3
- package/dist/domain/artifactIdentity.js +29 -0
- package/dist/domain/artifactInventoryEvidence.js +28 -40
- package/dist/domain/artifactOperationError.js +3 -3
- package/dist/domain/artifactPartialObservation.js +1 -0
- package/dist/domain/artifactPathSyntax.js +49 -0
- package/dist/domain/binaryTarget.js +39 -13
- package/dist/domain/bridgeCandidateProjection.js +71 -0
- package/dist/domain/browserCaptureComparison.js +13 -49
- package/dist/domain/browserCompleteness.js +1 -0
- package/dist/domain/browserNetworkEvidence.js +10 -4
- package/dist/domain/browserObservation.js +0 -1
- package/dist/domain/browserObservationError.js +24 -5
- package/dist/domain/browserObservationSchemas.js +14 -3
- package/dist/domain/browserScenario.js +0 -1
- package/dist/domain/browserScenarioCapture.js +1 -2
- package/dist/domain/browserScenarioDiff.js +0 -2
- package/dist/domain/browserScenarioDiffEvidence.js +0 -12
- package/dist/domain/browserScenarioDiffValues.js +2 -2
- package/dist/domain/browserScenarioValues.js +5 -10
- package/dist/domain/bundleComparison.js +3 -2
- package/dist/domain/callPath.js +8 -9
- package/dist/domain/callPathSchemas.js +2 -2
- package/dist/domain/canonicalJsonDigestSteps.js +133 -0
- package/dist/domain/canonicalOrdering.js +9 -5
- package/dist/domain/changedBehavior.js +9 -9
- package/dist/domain/comparisonSourceEvidence.js +40 -0
- package/dist/domain/completionLedgerGeneration.js +2 -1
- package/dist/domain/configurationErrors.js +13 -1
- package/dist/domain/conformancePackage.js +4 -3
- package/dist/domain/evidence.js +65 -36
- package/dist/domain/evidenceBundle.js +47 -8
- package/dist/domain/evidenceCompletionLedger.js +2 -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/functionComparison.js +4 -5
- package/dist/domain/functionComparisonDimensions.js +120 -87
- package/dist/domain/functionComparisonNormalization.js +23 -34
- package/dist/domain/functionComparisonResults.js +1 -4
- package/dist/domain/functionComparisonSchemas.js +2 -8
- package/dist/domain/functionDossierEvidence.js +2 -37
- 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 +47 -64
- package/dist/domain/javascript/electronObservation.js +14 -3
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +10 -9
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +2 -1
- package/dist/domain/javascript/electronStaticAnalysisNative.js +2 -1
- package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
- package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +2 -0
- package/dist/domain/javascript/javascriptApplicationGraph.js +39 -3
- package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +5 -2
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +2 -1
- package/dist/domain/javascript/javascriptAstValues.js +20 -0
- package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
- package/dist/domain/javascript/javascriptExportShapeComparison.js +7 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +29 -1
- package/dist/domain/javascript/javascriptExportShapeSelection.js +5 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +67 -14
- package/dist/domain/javascript/javascriptFeatureSeed.js +20 -0
- package/dist/domain/javascript/javascriptFeatureTraversal.js +0 -1
- package/dist/domain/javascript/javascriptNativeHandoff.js +1 -1
- package/dist/domain/javascript/javascriptRecovery.js +3 -8
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
- package/dist/domain/javascript/javascriptRuntimeObservation.js +10 -2
- package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +1 -1
- package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +3 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +0 -1
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +106 -5
- package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
- package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
- package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -1
- package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +23 -6
- package/dist/domain/javascript/javascriptSemanticGraph.js +98 -43
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +77 -20
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +21 -27
- package/dist/domain/javascript/javascriptSemanticObjects.js +83 -42
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +18 -21
- package/dist/domain/javascript/javascriptSemanticProjection.js +2 -3
- package/dist/domain/javascript/javascriptSemanticPromises.js +2 -1
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
- package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
- package/dist/domain/javascript/javascriptSemanticReturns.js +32 -17
- package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +126 -61
- package/dist/domain/javascript/javascriptSourceMapPaths.js +104 -0
- 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 +16 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -17
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
- package/dist/domain/javascript/sourceToBundleComparison.js +12 -3
- package/dist/domain/javascript/sourceToBundleSignals.js +47 -19
- 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/managedArtifact.js +6 -4
- package/dist/domain/managed/managedInspectionEvidence.js +16 -0
- package/dist/domain/managed/managedMemberComparison.js +2 -9
- package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
- package/dist/domain/managed/managedNativeVerification.js +3 -11
- package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
- package/dist/domain/native/binaryLayout.js +2 -3
- package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
- package/dist/domain/native/nativeApiBoundary.js +1 -1
- package/dist/domain/native/nativeCallObservation.js +37 -13
- package/dist/domain/native/nativeCallPartialObservation.js +33 -0
- package/dist/domain/native/nativeInstruction.js +7 -0
- package/dist/domain/native/recordedCrash.js +2 -3
- package/dist/domain/offsetDateTime.js +17 -0
- package/dist/domain/process/processCapture.js +21 -16
- package/dist/domain/process/processCaptureCoverage.js +67 -0
- package/dist/domain/process/processCaptureExample.js +2 -1
- package/dist/domain/process/processCaptureParsing.js +1 -34
- package/dist/domain/process/processCaptureValidation.js +81 -13
- package/dist/domain/process/processComparison.js +79 -26
- package/dist/domain/process/processObservation.js +10 -2
- package/dist/domain/process/processScenario.js +35 -12
- package/dist/domain/process/processTraceComparison.js +0 -2
- package/dist/domain/process/processTraceDimensionProjection.js +1 -1
- package/dist/domain/process/processTraceEvaluation.js +15 -11
- package/dist/domain/process/processTraceSpecification.js +3 -4
- package/dist/domain/propertyListKeys.js +1 -1
- package/dist/domain/propertyListXmlText.js +19 -0
- package/dist/domain/providerAdapterError.js +3 -1
- package/dist/domain/providerOperationHealth.js +54 -0
- package/dist/domain/reconstructionCoverage.js +5 -2
- package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
- package/dist/domain/reconstructionReadinessSchemas.js +2 -1
- package/dist/domain/reconstructionVerification.js +9 -46
- package/dist/domain/reconstructionVerificationSchemas.js +4 -3
- package/dist/domain/referenceSourceGraph.js +20 -21
- package/dist/domain/staticRuntimeCorrelation.js +8 -45
- package/dist/domain/stringPatterns.js +6 -0
- package/dist/domain/swiftSymbolClassification.js +61 -0
- package/dist/domain/symbolAnalysis.js +66 -18
- package/dist/domain/webBundleAnalysis.js +20 -8
- package/dist/domain/webBundleAnalyzerInspection.js +13 -8
- package/dist/domain/webBundleAnalyzerResult.js +41 -2
- package/dist/domain/webCaptureDiff.js +0 -1
- package/dist/domain/webCaptureDiffSchemas.js +6 -3
- package/dist/domain/webEventListeners.js +3 -2
- package/dist/domain/webExecution.js +3 -2
- package/dist/domain/webRuntime.js +19 -7
- package/dist/domain/webScriptExport.js +1 -1
- package/dist/domain/webSourceLocation.js +1 -0
- package/dist/dotnet/ManagedArtifactInspector.js +2 -19
- package/dist/dotnet/ManagedMemberInspector.js +12 -18
- package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
- package/dist/dotnet/ManagedMemberRows.js +75 -62
- package/dist/dotnet/ManagedMetadataInventory.js +16 -22
- package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
- package/dist/dotnet/ManagedReaderFailure.js +16 -0
- package/dist/dotnet/ManagedStaticProvider.js +3 -5
- package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
- package/dist/evaluation/AgentEvaluationReport.js +28 -0
- package/dist/evaluation/CodexAgentEval.js +12 -8
- package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
- package/dist/evm/EvmoleInterfaceProvider.js +2 -1
- package/dist/firmware/FirmwareCommand.js +9 -5
- package/dist/firmware/FirmwareFiles.js +1 -1
- package/dist/firmware/FirmwareProvider.js +4 -4
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +7 -5
- package/dist/ghidra/GhidraClient.js +126 -34
- package/dist/ghidra/GhidraClientStartup.js +0 -2
- package/dist/ghidra/GhidraDiagnostics.js +7 -7
- package/dist/ghidra/GhidraDoctor.js +6 -5
- package/dist/ghidra/GhidraFunctionValues.js +13 -12
- package/dist/ghidra/GhidraInstallation.js +58 -33
- package/dist/ghidra/GhidraInventoryValues.js +14 -4
- package/dist/ghidra/GhidraJavaLaunch.js +66 -0
- package/dist/ghidra/GhidraLauncher.js +47 -22
- package/dist/ghidra/GhidraProvider.js +6 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +20 -2
- package/dist/ghidra/GhidraProviderClient.js +36 -15
- package/dist/ghidra/GhidraSessionError.js +13 -7
- package/dist/ghidra/GhidraSessionRoot.js +39 -0
- package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
- package/dist/ghidra/GhidraTransport.js +20 -0
- package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
- package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
- package/dist/hopper/BridgeLauncher.js +65 -56
- package/dist/hopper/HopperAnalysisProfile.js +65 -12
- package/dist/hopper/HopperCleanup.js +63 -22
- package/dist/hopper/HopperClient.js +288 -59
- package/dist/hopper/HopperFileOffset.js +237 -0
- package/dist/hopper/HopperMachOImage.js +197 -0
- package/dist/hopper/HopperOperationStage.js +6 -0
- package/dist/hopper/HopperProvider.js +71 -19
- package/dist/hopper/HopperProviderCapabilities.js +19 -1
- package/dist/hopper/HopperRegexSearch.js +134 -0
- package/dist/hopper/HopperRegexWorker.js +27 -0
- package/dist/hopper/HopperRequestQueue.js +68 -19
- package/dist/hopper/HopperTargetLease.js +133 -49
- package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
- package/dist/ida/IdaConfiguration.js +8 -3
- package/dist/ida/IdaInput.js +1 -7
- package/dist/ida/IdaMcpConnection.js +8 -4
- package/dist/ida/IdaOperationRunner.js +3 -3
- package/dist/ida/IdaProvider.js +8 -12
- package/dist/ida/IdaSessionClient.js +20 -18
- package/dist/ida/IdaWorkspace.js +12 -13
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
- package/dist/inspector/V8InspectorCaptureProjection.js +9 -4
- package/dist/inspector/V8InspectorProvider.js +82 -36
- package/dist/javascript/recovery/WakaruCommand.js +7 -2
- package/dist/javascript/recovery/WakaruExecution.js +5 -2
- 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/main/shutdown.js +11 -3
- package/dist/main/startup.js +9 -2
- package/dist/main/transport.js +22 -2
- package/dist/main.js +11 -18
- 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 +48 -22
- 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 +87 -88
- package/dist/native/LldbCallTracer.js +372 -103
- package/dist/native/LldbRetainedObservations.js +178 -0
- package/dist/native/NativeCallObservation.js +62 -3
- package/dist/native/NativeMacOSProvider.js +122 -31
- package/dist/native/NativeUiHelperRuntime.js +11 -2
- package/dist/native/NativeUiObservation.js +2 -2
- 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/PwntoolsDecoder.js +2 -1
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
- package/dist/process/DarwinProcessRunTokenReader.js +23 -10
- package/dist/process/ExecFileOutput.js +108 -6
- package/dist/process/OwnedCommand.js +7 -2
- package/dist/process/PrivateRuntimeRoot.js +10 -5
- package/dist/process/ProcessOwnership.js +204 -57
- package/dist/process/ProcessOwnershipObservation.js +60 -9
- package/dist/process/ProviderProcess.js +39 -10
- package/dist/process/capture/FilesystemSnapshot.js +50 -13
- package/dist/process/capture/ProcessCaptureError.js +15 -2
- package/dist/process/capture/ProcessCaptureLifecycle.js +235 -81
- package/dist/process/capture/ProcessFilesystemEffects.js +33 -3
- package/dist/process/capture/ProcessHarness.js +21 -25
- package/dist/process/capture/ProcessNormalization.js +20 -2
- package/dist/process/capture/ProcessSampling.js +25 -2
- package/dist/process/capture/TerminalRenderer.js +14 -0
- package/dist/process/snapshotEnvironment.js +14 -0
- package/dist/server/EvidenceMcpServer.js +157 -0
- package/dist/server/createServer.js +61 -41
- package/dist/server/mcpClientMetadata.js +12 -5
- package/dist/server/promptCompletion.js +3 -8
- package/dist/server/registerAnalysisViewTool.js +15 -0
- package/dist/server/registerAndroidTools.js +2 -5
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -5
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +4 -5
- package/dist/server/registerApplicationTools/coverage.js +1 -2
- package/dist/server/registerApplicationTools/helpers.js +1 -4
- package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
- package/dist/server/registerApplicationTools/traceFeature.js +4 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +13 -10
- package/dist/server/registerBinaryDiagnosticsTools.js +2 -5
- package/dist/server/registerBrowserScenarioTool.js +3 -6
- package/dist/server/registerBrowserTools.js +13 -18
- package/dist/server/registerBundleComparisonTool.js +5 -7
- package/dist/server/registerCloseLifecycleTool.js +9 -20
- package/dist/server/registerElectronTools.js +10 -15
- package/dist/server/registerEnhancedTools.js +36 -77
- package/dist/server/registerEvidenceTools.js +3 -6
- package/dist/server/registerEvmTools.js +2 -5
- package/dist/server/registerFirmwareTools.js +2 -5
- package/dist/server/registerFunctionComparisonTool.js +15 -12
- package/dist/server/registerInvestigationTools.js +16 -17
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -5
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -8
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -8
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -7
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -9
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -9
- package/dist/server/registerOfficialTools.js +4 -21
- package/dist/server/registerProcessComparisonTool.js +74 -48
- package/dist/server/registerRecordedCrashTools.js +2 -5
- package/dist/server/registerSessionRecordTools.js +19 -24
- package/dist/server/registerSessionStatusTool.js +19 -6
- package/dist/server/registerSessionTools.js +20 -18
- package/dist/server/registerWebModuleTool.js +2 -5
- package/dist/server/registerWebNetworkCaptureTool.js +2 -5
- package/dist/server/registerWebRuntimeTools.js +4 -9
- package/dist/server/registerWebScriptTool.js +2 -5
- package/dist/server/registerWebSourceLocationTool.js +2 -5
- 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 +75 -51
- package/dist/server/toolResultEncoding.js +34 -0
- package/dist/windows/WindowsNativeLoader.js +1 -0
- package/dist/windows/WindowsOwnedProcess.js +60 -15
- package/dist/windows/WindowsPrivateRuntime.js +7 -8
- package/install.sh +1 -1
- package/native/windows/README.md +3 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +44 -30
- package/scripts/electron-active-hook-boundaries.cjs +18 -20
- package/scripts/electron-active-hook.cjs +241 -37
- package/scripts/rea.mjs +3 -6
- package/skills/reverse-engineer-anything/SKILL.md +12 -3
- package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +20 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
- package/dist/config.js +0 -1
- package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
- package/dist/contracts/process/processCaptureExample.js +0 -2
- package/dist/contracts/toolOutputSchemas.js +0 -2
- package/dist/ghidra/GhidraDefaults.js +0 -2
- package/dist/main/reload.js +0 -12
- package/dist/main/state.js +0 -3
- package/dist/server/sessionToolPolicies.js +0 -2
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { open } from "node:fs/promises";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { AnalysisAccessDeniedError, AnalysisArtifactChangedError, AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/analysisErrorCore.js";
|
|
6
|
+
import { BinaryTargetError } from "../domain/configurationErrors.js";
|
|
7
|
+
import { readFatSliceDeclarations, validateFatSlice, } from "../domain/apple/machoContainer.js";
|
|
8
|
+
import { err, ok } from "../domain/result.js";
|
|
9
|
+
const OPERATION = "address_to_file_offset";
|
|
10
|
+
const MAX_FAT_ARCHITECTURES = 128;
|
|
11
|
+
const PREFIX_BYTES = 8 + MAX_FAT_ARCHITECTURES * 32;
|
|
12
|
+
const observationSchema = z.strictObject({
|
|
13
|
+
address: z.string().regex(/^0x[0-9a-f]+$/u),
|
|
14
|
+
provider_file_offset: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.nonnegative()
|
|
18
|
+
.max(Number.MAX_SAFE_INTEGER),
|
|
19
|
+
provider_source_path: z.string().nullable(),
|
|
20
|
+
provider_image_header_hex: z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^[a-f0-9]{24}$/u)
|
|
23
|
+
.nullable(),
|
|
24
|
+
});
|
|
25
|
+
/** Bind native image-relative offsets to coordinates in the admitted source bytes. */
|
|
26
|
+
export async function mapHopperFileOffset(target, value, signal) {
|
|
27
|
+
const parsed = observationSchema.safeParse(value);
|
|
28
|
+
if (!parsed.success)
|
|
29
|
+
return err(new AnalysisOutputError(OPERATION, "Hopper's native file mapping observation is malformed"));
|
|
30
|
+
const observation = parsed.data;
|
|
31
|
+
const partial = (reason) => ({
|
|
32
|
+
operation: OPERATION,
|
|
33
|
+
...observation,
|
|
34
|
+
original_file_offset: { available: false, reason },
|
|
35
|
+
});
|
|
36
|
+
const unavailable = (reason) => err(new AnalysisCapabilityUnavailableError("hopper", OPERATION, reason, {
|
|
37
|
+
partialObservation: partial(reason),
|
|
38
|
+
}));
|
|
39
|
+
if (target.kind !== "executable")
|
|
40
|
+
return unavailable("The selected database digest does not identify its original executable bytes. Open that executable to verify original-file coordinates; read_bytes still exposes the database's native bytes.");
|
|
41
|
+
if (signal?.aborted)
|
|
42
|
+
return err(new AnalysisCancelledError(OPERATION, {
|
|
43
|
+
partialObservation: partial("Source verification was cancelled"),
|
|
44
|
+
}));
|
|
45
|
+
try {
|
|
46
|
+
const captured = await snapshotFromPath(target.path, signal);
|
|
47
|
+
if (!captured.ok)
|
|
48
|
+
return err(new AnalysisArtifactChangedError(OPERATION, target.path, captured.error, {
|
|
49
|
+
partialObservation: partial(captured.error),
|
|
50
|
+
}));
|
|
51
|
+
const snapshot = captured.value;
|
|
52
|
+
if (signal?.aborted)
|
|
53
|
+
return err(new AnalysisCancelledError(OPERATION, {
|
|
54
|
+
partialObservation: partial("Source verification was cancelled"),
|
|
55
|
+
}));
|
|
56
|
+
if (snapshot.sha256 !== target.sha256) {
|
|
57
|
+
const reason = `Source ${target.path} differs from the admitted artifact: expected SHA-256 ${target.sha256}, observed ${snapshot.sha256}. Reopen the changed source for a new analysis identity.`;
|
|
58
|
+
return err(new AnalysisArtifactChangedError(OPERATION, target.path, reason, {
|
|
59
|
+
partialObservation: partial(reason),
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
const mapped = originalOffset(snapshot, observation);
|
|
63
|
+
if (!mapped.ok)
|
|
64
|
+
return unavailable(mapped.error);
|
|
65
|
+
return ok({
|
|
66
|
+
address: observation.address,
|
|
67
|
+
file_offset: mapped.value + observation.provider_file_offset,
|
|
68
|
+
provider_file_offset: observation.provider_file_offset,
|
|
69
|
+
image_base_file_offset: mapped.value,
|
|
70
|
+
source_path: target.path,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
if (signal?.aborted)
|
|
75
|
+
return err(new AnalysisCancelledError(OPERATION, {
|
|
76
|
+
cause,
|
|
77
|
+
partialObservation: partial("Source verification was cancelled"),
|
|
78
|
+
}));
|
|
79
|
+
const reason = `Cannot verify original source bytes: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
80
|
+
const code = typeof cause === "object" && cause !== null && "code" in cause
|
|
81
|
+
? cause.code
|
|
82
|
+
: undefined;
|
|
83
|
+
if (code === "EACCES" || code === "EPERM")
|
|
84
|
+
return err(new AnalysisAccessDeniedError(OPERATION, target.path, code, {
|
|
85
|
+
cause,
|
|
86
|
+
partialObservation: partial(reason),
|
|
87
|
+
}));
|
|
88
|
+
return err(new BinaryTargetError(target.path, reason, {
|
|
89
|
+
cause,
|
|
90
|
+
partialObservation: partial(reason),
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function snapshotFromPath(path, signal) {
|
|
95
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
96
|
+
try {
|
|
97
|
+
if (!(await file.stat()).isFile())
|
|
98
|
+
return err(`Source ${path} is no longer a regular file. Restore the admitted executable or reopen a regular source.`);
|
|
99
|
+
return ok(await readSourceSnapshot(file, signal));
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
await file.close();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function fatLayout(prefix) {
|
|
106
|
+
const magic = prefix.length < 4 ? 0 : prefix.readUInt32BE(0);
|
|
107
|
+
if (![0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca].includes(magic))
|
|
108
|
+
return ok(null);
|
|
109
|
+
if (prefix.length < 8)
|
|
110
|
+
return err("The original FAT header is truncated");
|
|
111
|
+
const littleEndian = magic === 0xbebafeca || magic === 0xbfbafeca;
|
|
112
|
+
const wide = magic === 0xcafebabf || magic === 0xbfbafeca;
|
|
113
|
+
const count = littleEndian ? prefix.readUInt32LE(4) : prefix.readUInt32BE(4);
|
|
114
|
+
if (count === 0 || count > MAX_FAT_ARCHITECTURES)
|
|
115
|
+
return err("FAT architecture count is outside the supported 1..128 range");
|
|
116
|
+
const tableEnd = 8 + count * (wide ? 32 : 20);
|
|
117
|
+
const table = prefix.subarray(8, tableEnd);
|
|
118
|
+
const parsed = readFatSliceDeclarations(table, { count, wide, littleEndian });
|
|
119
|
+
if (parsed.status !== "parsed")
|
|
120
|
+
return err(parsed.reason);
|
|
121
|
+
if (wide) {
|
|
122
|
+
for (const slice of parsed.slices)
|
|
123
|
+
if ((littleEndian
|
|
124
|
+
? table.readUInt32LE(slice.index * 32 + 28)
|
|
125
|
+
: table.readUInt32BE(slice.index * 32 + 28)) !== 0)
|
|
126
|
+
return err(`FAT64 architecture ${slice.index} has a nonzero reserved field`);
|
|
127
|
+
}
|
|
128
|
+
return ok({ slices: parsed.slices, tableEnd });
|
|
129
|
+
}
|
|
130
|
+
async function readSourceSnapshot(file, signal) {
|
|
131
|
+
const prefix = Buffer.alloc(PREFIX_BYTES);
|
|
132
|
+
const hash = createHash("sha256");
|
|
133
|
+
let size = 0;
|
|
134
|
+
let layout;
|
|
135
|
+
const headers = new Map();
|
|
136
|
+
const capture = (bytes, position) => {
|
|
137
|
+
if (layout?.ok !== true || layout.value === null)
|
|
138
|
+
return;
|
|
139
|
+
for (const slice of layout.value.slices) {
|
|
140
|
+
const start = Math.max(position, slice.offset);
|
|
141
|
+
const end = Math.min(position + bytes.length, slice.offset + 12);
|
|
142
|
+
if (end <= start)
|
|
143
|
+
continue;
|
|
144
|
+
let header = headers.get(slice.index);
|
|
145
|
+
if (header === undefined) {
|
|
146
|
+
header = Buffer.alloc(12);
|
|
147
|
+
headers.set(slice.index, header);
|
|
148
|
+
}
|
|
149
|
+
bytes.copy(header, start - slice.offset, start - position, end - position);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
for await (const chunk of file.createReadStream({
|
|
153
|
+
start: 0,
|
|
154
|
+
autoClose: false,
|
|
155
|
+
...(signal === undefined ? {} : { signal }),
|
|
156
|
+
})) {
|
|
157
|
+
const bytes = Buffer.from(chunk);
|
|
158
|
+
hash.update(bytes);
|
|
159
|
+
if (size < prefix.length)
|
|
160
|
+
bytes.copy(prefix, size, 0, Math.min(bytes.length, prefix.length - size));
|
|
161
|
+
if (layout === undefined && size + bytes.length >= prefix.length) {
|
|
162
|
+
layout = fatLayout(prefix);
|
|
163
|
+
capture(prefix, 0);
|
|
164
|
+
}
|
|
165
|
+
capture(bytes, size);
|
|
166
|
+
size += bytes.length;
|
|
167
|
+
}
|
|
168
|
+
if (layout === undefined) {
|
|
169
|
+
layout = fatLayout(prefix.subarray(0, size));
|
|
170
|
+
capture(prefix.subarray(0, size), 0);
|
|
171
|
+
}
|
|
172
|
+
return { layout, headers, size, sha256: hash.digest("hex") };
|
|
173
|
+
}
|
|
174
|
+
function originalOffset(snapshot, observation) {
|
|
175
|
+
const { layout, size, headers } = snapshot;
|
|
176
|
+
if (!layout.ok)
|
|
177
|
+
return layout;
|
|
178
|
+
if (layout.value === null)
|
|
179
|
+
return observation.provider_file_offset < size
|
|
180
|
+
? ok(0)
|
|
181
|
+
: err("Provider mapping lies outside the admitted executable bytes");
|
|
182
|
+
const header = observation.provider_image_header_hex === null
|
|
183
|
+
? null
|
|
184
|
+
: Buffer.from(observation.provider_image_header_hex, "hex");
|
|
185
|
+
const loadedMagic = header?.readUInt32BE(0);
|
|
186
|
+
if (header === null ||
|
|
187
|
+
loadedMagic === undefined ||
|
|
188
|
+
![0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe].includes(loadedMagic))
|
|
189
|
+
return err("Hopper did not expose the loaded Mach-O header needed to identify its FAT slice");
|
|
190
|
+
const little = loadedMagic === 0xcefaedfe || loadedMagic === 0xcffaedfe;
|
|
191
|
+
const cpu = little ? header.readUInt32LE(4) : header.readUInt32BE(4);
|
|
192
|
+
const subtype = little ? header.readUInt32LE(8) : header.readUInt32BE(8);
|
|
193
|
+
const matches = [];
|
|
194
|
+
const ranges = [...layout.value.slices].sort((a, b) => a.offset - b.offset);
|
|
195
|
+
for (let index = 1; index < ranges.length; index++) {
|
|
196
|
+
const previous = ranges[index - 1];
|
|
197
|
+
const current = ranges[index];
|
|
198
|
+
if (previous !== undefined &&
|
|
199
|
+
current !== undefined &&
|
|
200
|
+
current.offset < previous.offset + previous.size)
|
|
201
|
+
return err("Original FAT slices overlap");
|
|
202
|
+
}
|
|
203
|
+
for (const slice of layout.value.slices) {
|
|
204
|
+
const reason = validateFatSlice(slice, size, layout.value.tableEnd);
|
|
205
|
+
if (reason !== null)
|
|
206
|
+
return err(reason);
|
|
207
|
+
const embedded = headers.get(slice.index);
|
|
208
|
+
if (slice.size < 12 || embedded === undefined)
|
|
209
|
+
return err(`FAT architecture ${slice.index} has a truncated Mach-O header`);
|
|
210
|
+
const embeddedMagic = embedded.readUInt32BE(0);
|
|
211
|
+
if (![0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe].includes(embeddedMagic))
|
|
212
|
+
return err(`FAT architecture ${slice.index} does not contain a Mach-O image`);
|
|
213
|
+
const embeddedLittle = embeddedMagic === 0xcefaedfe || embeddedMagic === 0xcffaedfe;
|
|
214
|
+
const identityError = validateFatSlice(slice, size, layout.value.tableEnd, {
|
|
215
|
+
cpuType: embeddedLittle
|
|
216
|
+
? embedded.readUInt32LE(4)
|
|
217
|
+
: embedded.readUInt32BE(4),
|
|
218
|
+
cpuSubtype: embeddedLittle
|
|
219
|
+
? embedded.readUInt32LE(8)
|
|
220
|
+
: embedded.readUInt32BE(8),
|
|
221
|
+
});
|
|
222
|
+
if (identityError !== null)
|
|
223
|
+
return err(identityError);
|
|
224
|
+
if (slice.cpuType === cpu && slice.cpuSubtype === subtype)
|
|
225
|
+
matches.push(slice);
|
|
226
|
+
}
|
|
227
|
+
const selected = matches.length === 1 ? matches[0] : undefined;
|
|
228
|
+
if (selected === undefined)
|
|
229
|
+
return err(`Original FAT slice matching Hopper's loaded header is ${matches.length === 0 ? "missing" : "ambiguous"}`);
|
|
230
|
+
if (headers.get(selected.index)?.equals(header) !== true)
|
|
231
|
+
return err("Original FAT slice header disagrees with Hopper's loaded header");
|
|
232
|
+
if (observation.provider_file_offset >= selected.size)
|
|
233
|
+
return err("Provider mapping lies outside the loaded FAT slice");
|
|
234
|
+
if (!Number.isSafeInteger(selected.offset + observation.provider_file_offset))
|
|
235
|
+
return err("Original file offset exceeds the exact JSON integer range");
|
|
236
|
+
return ok(selected.offset);
|
|
237
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { open } from "node:fs/promises";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { BinaryTargetError } from "../domain/configurationErrors.js";
|
|
5
|
+
import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
|
|
6
|
+
import { readFatSliceDeclarations, validateFatSlice, } from "../domain/apple/machoContainer.js";
|
|
7
|
+
import { HopperCancelledError, HopperStartError, } from "../domain/hopperErrors.js";
|
|
8
|
+
import { err, ok } from "../domain/result.js";
|
|
9
|
+
/** Stable source coordinates committed before preparing an owned thin image. */
|
|
10
|
+
export const hopperMachOImageSchema = z.strictObject({
|
|
11
|
+
method: z.literal("fat64_thin_slice"),
|
|
12
|
+
architecture_count: z.number().int().min(1).max(128),
|
|
13
|
+
container_table_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
14
|
+
source_offset: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
15
|
+
byte_length: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
16
|
+
cpu_type: z.number().int().nonnegative(),
|
|
17
|
+
cpu_subtype: z.number().int().nonnegative(),
|
|
18
|
+
});
|
|
19
|
+
/** Validate the selected FAT64 slice without depending on Apple's lipo tool. */
|
|
20
|
+
export const resolveHopperMachOImage = async (target, signal) => {
|
|
21
|
+
const invalid = (reason, cause) => err(new BinaryTargetError(target.path, reason, cause === undefined ? undefined : { cause }));
|
|
22
|
+
if (signal?.aborted)
|
|
23
|
+
return err(new AnalysisCancelledError("open_binary"));
|
|
24
|
+
let file;
|
|
25
|
+
try {
|
|
26
|
+
file = await open(target.path, "r");
|
|
27
|
+
}
|
|
28
|
+
catch (cause) {
|
|
29
|
+
// Keep the OS error so a read-permission denial reports access_denied.
|
|
30
|
+
return invalid(`Cannot read FAT64 source for Hopper image preparation: ${cause instanceof Error ? cause.message : String(cause)}`, cause);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const read = async (offset, length) => {
|
|
34
|
+
const bytes = Buffer.alloc(length);
|
|
35
|
+
const { bytesRead } = await file.read(bytes, 0, length, offset);
|
|
36
|
+
return bytes.subarray(0, bytesRead);
|
|
37
|
+
};
|
|
38
|
+
const header = await read(0, 8);
|
|
39
|
+
const magic = header.length === 8 ? header.readUInt32BE(0) : 0;
|
|
40
|
+
if (magic !== 0xcafebabf && magic !== 0xbfbafeca)
|
|
41
|
+
return invalid("FAT64 source header changed before Hopper image preparation");
|
|
42
|
+
const littleEndian = magic === 0xbfbafeca;
|
|
43
|
+
const count = littleEndian
|
|
44
|
+
? header.readUInt32LE(4)
|
|
45
|
+
: header.readUInt32BE(4);
|
|
46
|
+
const size = (await file.stat()).size;
|
|
47
|
+
const tableEnd = 8 + count * 32;
|
|
48
|
+
if (count === 0 || count > 128 || tableEnd > size)
|
|
49
|
+
return invalid("FAT64 architecture table is truncated or exceeds the supported 128 entries");
|
|
50
|
+
const table = await read(8, count * 32);
|
|
51
|
+
const parsed = readFatSliceDeclarations(table, {
|
|
52
|
+
count,
|
|
53
|
+
wide: true,
|
|
54
|
+
littleEndian,
|
|
55
|
+
});
|
|
56
|
+
if (parsed.status === "malformed")
|
|
57
|
+
return invalid(parsed.reason);
|
|
58
|
+
const cpuTypes = { x86: 7, x86_64: 0x1000007, arm: 12, arm64: 0x100000c };
|
|
59
|
+
const matches = [];
|
|
60
|
+
const ranges = [];
|
|
61
|
+
for (const slice of parsed.slices) {
|
|
62
|
+
if (signal?.aborted)
|
|
63
|
+
return err(new AnalysisCancelledError("open_binary"));
|
|
64
|
+
const rangeError = validateFatSlice(slice, size, tableEnd);
|
|
65
|
+
if (rangeError !== null)
|
|
66
|
+
return invalid(rangeError);
|
|
67
|
+
const reserved = littleEndian
|
|
68
|
+
? table.readUInt32LE(slice.index * 32 + 28)
|
|
69
|
+
: table.readUInt32BE(slice.index * 32 + 28);
|
|
70
|
+
if (reserved !== 0)
|
|
71
|
+
return invalid(`FAT64 architecture ${slice.index} has a nonzero reserved field`);
|
|
72
|
+
if (slice.size < 12)
|
|
73
|
+
return invalid(`FAT64 architecture ${slice.index} has a truncated Mach-O header`);
|
|
74
|
+
const embedded = await read(slice.offset, 12);
|
|
75
|
+
if (embedded.length !== 12)
|
|
76
|
+
return invalid(`FAT64 architecture ${slice.index} became truncated`);
|
|
77
|
+
const thinMagic = embedded.readUInt32BE(0);
|
|
78
|
+
if (![0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe].includes(thinMagic))
|
|
79
|
+
return invalid(`FAT64 architecture ${slice.index} does not contain a Mach-O image`);
|
|
80
|
+
const little = thinMagic === 0xcefaedfe || thinMagic === 0xcffaedfe;
|
|
81
|
+
const identity = {
|
|
82
|
+
cpuType: little ? embedded.readUInt32LE(4) : embedded.readUInt32BE(4),
|
|
83
|
+
cpuSubtype: little
|
|
84
|
+
? embedded.readUInt32LE(8)
|
|
85
|
+
: embedded.readUInt32BE(8),
|
|
86
|
+
};
|
|
87
|
+
const identityError = validateFatSlice(slice, size, tableEnd, identity);
|
|
88
|
+
if (identityError !== null)
|
|
89
|
+
return invalid(identityError);
|
|
90
|
+
ranges.push(slice);
|
|
91
|
+
if (slice.cpuType === cpuTypes[target.architecture])
|
|
92
|
+
matches.push(slice);
|
|
93
|
+
}
|
|
94
|
+
ranges.sort((a, b) => a.offset - b.offset);
|
|
95
|
+
for (let index = 1; index < ranges.length; index++) {
|
|
96
|
+
const previous = ranges[index - 1];
|
|
97
|
+
const current = ranges[index];
|
|
98
|
+
if (previous !== undefined &&
|
|
99
|
+
current !== undefined &&
|
|
100
|
+
current.offset < previous.offset + previous.size)
|
|
101
|
+
return invalid("FAT64 slices overlap");
|
|
102
|
+
}
|
|
103
|
+
const selected = matches.length === 1 ? matches[0] : undefined;
|
|
104
|
+
if (selected === undefined)
|
|
105
|
+
return invalid(`FAT64 selection for ${target.architecture} is ${matches.length === 0 ? "missing" : "ambiguous"}; extract the exact architecture into a thin image before opening it`);
|
|
106
|
+
return ok({
|
|
107
|
+
method: "fat64_thin_slice",
|
|
108
|
+
architecture_count: count,
|
|
109
|
+
container_table_sha256: createHash("sha256")
|
|
110
|
+
.update(header)
|
|
111
|
+
.update(table)
|
|
112
|
+
.digest("hex"),
|
|
113
|
+
source_offset: selected.offset,
|
|
114
|
+
byte_length: selected.size,
|
|
115
|
+
cpu_type: selected.cpuType,
|
|
116
|
+
cpu_subtype: selected.cpuSubtype,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch (cause) {
|
|
120
|
+
return invalid(`Cannot validate FAT64 image: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
await file.close();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
/** Copy a selected slice and verify the entire original source in the same pass. */
|
|
127
|
+
export const prepareHopperMachOImage = async (sourcePath, sourceSha256, image, destination, signal) => {
|
|
128
|
+
if (signal?.aborted)
|
|
129
|
+
return err(new HopperCancelledError());
|
|
130
|
+
try {
|
|
131
|
+
const source = await open(sourcePath, "r");
|
|
132
|
+
try {
|
|
133
|
+
const output = await open(destination, "wx", 0o600);
|
|
134
|
+
try {
|
|
135
|
+
const hash = createHash("sha256");
|
|
136
|
+
const tableHash = createHash("sha256");
|
|
137
|
+
const tableEnd = 8 + image.architecture_count * 32;
|
|
138
|
+
const thinHeader = [];
|
|
139
|
+
let position = 0;
|
|
140
|
+
let copied = 0;
|
|
141
|
+
for await (const chunk of source.createReadStream({
|
|
142
|
+
autoClose: false,
|
|
143
|
+
})) {
|
|
144
|
+
if (signal?.aborted)
|
|
145
|
+
return err(new HopperCancelledError());
|
|
146
|
+
const bytes = Buffer.from(chunk);
|
|
147
|
+
hash.update(bytes);
|
|
148
|
+
if (position < tableEnd)
|
|
149
|
+
tableHash.update(bytes.subarray(0, Math.min(bytes.length, tableEnd - position)));
|
|
150
|
+
const start = Math.max(0, image.source_offset - position);
|
|
151
|
+
const end = Math.min(bytes.length, image.source_offset + image.byte_length - position);
|
|
152
|
+
if (end > start) {
|
|
153
|
+
if (copied < 12)
|
|
154
|
+
thinHeader.push(bytes.subarray(start, Math.min(end, start + 12 - copied)));
|
|
155
|
+
await output.writeFile(bytes.subarray(start, end));
|
|
156
|
+
copied += end - start;
|
|
157
|
+
}
|
|
158
|
+
position += bytes.length;
|
|
159
|
+
}
|
|
160
|
+
const observed = hash.digest("hex");
|
|
161
|
+
const header = Buffer.concat(thinHeader);
|
|
162
|
+
const magic = header.length === 12 ? header.readUInt32BE(0) : 0;
|
|
163
|
+
const little = magic === 0xcefaedfe || magic === 0xcffaedfe;
|
|
164
|
+
const headerMatches = header.length === 12 &&
|
|
165
|
+
[0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe].includes(magic) &&
|
|
166
|
+
(little ? header.readUInt32LE(4) : header.readUInt32BE(4)) ===
|
|
167
|
+
image.cpu_type &&
|
|
168
|
+
(little ? header.readUInt32LE(8) : header.readUInt32BE(8)) ===
|
|
169
|
+
image.cpu_subtype;
|
|
170
|
+
if (tableHash.digest("hex") !== image.container_table_sha256 ||
|
|
171
|
+
!headerMatches)
|
|
172
|
+
return err(new HopperStartError({
|
|
173
|
+
userMessage: `FAT64 source ${sourcePath} no longer agrees with its committed architecture table or selected Mach-O header. Open the stable source again.`,
|
|
174
|
+
}));
|
|
175
|
+
if (observed !== sourceSha256 || copied !== image.byte_length)
|
|
176
|
+
return err(new HopperStartError({
|
|
177
|
+
userMessage: `FAT64 source ${sourcePath} changed before launch: expected SHA-256 ${sourceSha256}, observed ${observed}; copied ${copied} of ${image.byte_length} selected bytes. Open the stable source again.`,
|
|
178
|
+
}));
|
|
179
|
+
return ok(destination);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
await output.close();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
await source.close();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (cause) {
|
|
190
|
+
return signal?.aborted
|
|
191
|
+
? err(new HopperCancelledError())
|
|
192
|
+
: err(new HopperStartError({
|
|
193
|
+
cause,
|
|
194
|
+
userMessage: `Cannot prepare the selected FAT64 image from ${sourcePath}: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
};
|
|
@@ -1,32 +1,36 @@
|
|
|
1
|
+
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
|
|
1
2
|
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { accessSync, constants } from "node:fs";
|
|
3
4
|
import { createAnalysisExecution } from "../application/AnalysisProvider.js";
|
|
4
5
|
import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
|
|
5
|
-
import { err } from "../domain/result.js";
|
|
6
|
+
import { err, ok } from "../domain/result.js";
|
|
6
7
|
import { HopperApplicationLauncher } from "./BridgeLauncher.js";
|
|
7
8
|
import { hopperLoaderArgsForTarget, resolveHopperAnalysisProfile, } from "./HopperAnalysisProfile.js";
|
|
9
|
+
import { mapHopperFileOffset } from "./HopperFileOffset.js";
|
|
10
|
+
import { HopperRegexSearch } from "./HopperRegexSearch.js";
|
|
8
11
|
import { HopperClient } from "./HopperClient.js";
|
|
12
|
+
import { hopperMachOImageSchema } from "./HopperMachOImage.js";
|
|
9
13
|
import { CAPABILITIES, HOPPER_PROVIDER_IDENTITY, } from "./HopperProviderCapabilities.js";
|
|
10
|
-
export { HOPPER_PROVIDER_IDENTITY, HOPPER_OPERATIONS, } from "./HopperProviderCapabilities.js";
|
|
11
|
-
const IDENTITY = HOPPER_PROVIDER_IDENTITY;
|
|
12
14
|
/** Concrete analysis provider backed by REA's private Hopper bridge. */
|
|
13
15
|
export class HopperProvider {
|
|
14
16
|
config;
|
|
15
17
|
logger;
|
|
16
18
|
platform;
|
|
19
|
+
environment;
|
|
17
20
|
/**
|
|
18
21
|
* Host platform, injected so availability and launch-mode decisions can be
|
|
19
22
|
* exercised for any host rather than only the machine running the suite.
|
|
20
23
|
* Mirrors `GhidraProvider`, which already threads its installation host's
|
|
21
24
|
* platform the same way.
|
|
22
25
|
*/
|
|
23
|
-
constructor(config, logger, platform = process.platform) {
|
|
26
|
+
constructor(config, logger, environment, platform = process.platform) {
|
|
24
27
|
this.config = config;
|
|
25
28
|
this.logger = logger;
|
|
26
29
|
this.platform = platform;
|
|
30
|
+
this.environment = snapshotEnvironment(environment, platform);
|
|
27
31
|
}
|
|
28
32
|
identity() {
|
|
29
|
-
return
|
|
33
|
+
return HOPPER_PROVIDER_IDENTITY;
|
|
30
34
|
}
|
|
31
35
|
capabilities() {
|
|
32
36
|
return CAPABILITIES;
|
|
@@ -101,28 +105,52 @@ export class HopperProvider {
|
|
|
101
105
|
return resolveHopperAnalysisProfile(target, {
|
|
102
106
|
launcherPath: this.config.hopperLauncherPath,
|
|
103
107
|
loaderArgsOverride: this.config.hopperLoaderArgs,
|
|
104
|
-
provider:
|
|
108
|
+
provider: HOPPER_PROVIDER_IDENTITY,
|
|
105
109
|
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
106
110
|
});
|
|
107
111
|
}
|
|
108
112
|
createClient(target, profile, context) {
|
|
109
113
|
if (target.kind !== "executable" && target.kind !== "database")
|
|
110
114
|
return {
|
|
111
|
-
execute: (operation) => Promise.resolve(err(new AnalysisCapabilityUnavailableError(
|
|
112
|
-
close: () => Promise.resolve(),
|
|
115
|
+
execute: (operation) => Promise.resolve(err(new AnalysisCapabilityUnavailableError(HOPPER_PROVIDER_IDENTITY.id, operation, `Hopper cannot open ${target.kind} targets directly. Inventory or extract the artifact first.`))),
|
|
116
|
+
close: () => Promise.resolve(ok(null)),
|
|
113
117
|
};
|
|
114
|
-
const
|
|
118
|
+
const preparation = profile?.parameters.prepared_image;
|
|
119
|
+
const parsedImage = preparation === undefined
|
|
120
|
+
? undefined
|
|
121
|
+
: hopperMachOImageSchema.safeParse(preparation);
|
|
122
|
+
if (parsedImage?.success === false)
|
|
123
|
+
return {
|
|
124
|
+
execute: (operation) => Promise.resolve(err(new AnalysisCapabilityUnavailableError(HOPPER_PROVIDER_IDENTITY.id, operation, "Hopper prepared-image profile is malformed; resolve the analysis profile again."))),
|
|
125
|
+
close: () => Promise.resolve(ok(null)),
|
|
126
|
+
};
|
|
127
|
+
const preparedImage = parsedImage?.data;
|
|
128
|
+
const container = preparedImage === undefined
|
|
129
|
+
? profile?.parameters.macho_container
|
|
130
|
+
: "thin";
|
|
131
|
+
const derivedLoaderArgs = hopperLoaderArgsForTarget(target, container === "thin" || container === "fat32" || container === "fat64"
|
|
132
|
+
? container
|
|
133
|
+
: undefined);
|
|
115
134
|
if (!derivedLoaderArgs.ok)
|
|
116
135
|
return {
|
|
117
136
|
execute: () => Promise.resolve(err(derivedLoaderArgs.error)),
|
|
118
|
-
close: () => Promise.resolve(),
|
|
137
|
+
close: () => Promise.resolve(ok(null)),
|
|
119
138
|
};
|
|
120
|
-
const executionProvider = profile?.provider ??
|
|
139
|
+
const executionProvider = profile?.provider ?? HOPPER_PROVIDER_IDENTITY;
|
|
121
140
|
const client = new HopperClient({
|
|
122
141
|
launcher: new HopperApplicationLauncher({
|
|
142
|
+
environment: this.environment,
|
|
123
143
|
launcherPath: this.config.hopperLauncherPath,
|
|
124
144
|
targetPath: target.path,
|
|
125
145
|
targetKind: target.kind,
|
|
146
|
+
...(preparedImage === undefined
|
|
147
|
+
? {}
|
|
148
|
+
: {
|
|
149
|
+
preparedImage: {
|
|
150
|
+
image: preparedImage,
|
|
151
|
+
sourceSha256: target.sha256,
|
|
152
|
+
},
|
|
153
|
+
}),
|
|
126
154
|
loaderArgs: this.config.hopperLoaderArgs.length > 0
|
|
127
155
|
? this.config.hopperLoaderArgs
|
|
128
156
|
: derivedLoaderArgs.value,
|
|
@@ -138,25 +166,46 @@ export class HopperProvider {
|
|
|
138
166
|
logger: this.logger.child({ layer: "bridge" }),
|
|
139
167
|
onDiagnostic: (diagnostic) => this.logger.info(diagnostic, "Hopper bridge reported a diagnostic"),
|
|
140
168
|
});
|
|
169
|
+
const regexSearch = new HopperRegexSearch(client);
|
|
141
170
|
return {
|
|
142
171
|
execute: async (operation, parameters, options) => {
|
|
143
|
-
const result =
|
|
144
|
-
|
|
172
|
+
const result = (operation === "search_strings" ||
|
|
173
|
+
operation === "search_procedures") &&
|
|
174
|
+
parameters.mode === "regex"
|
|
175
|
+
? await regexSearch.execute(operation, parameters, options)
|
|
176
|
+
: await client.callTool(operation, parameters, options);
|
|
177
|
+
if (!result.ok)
|
|
178
|
+
return result;
|
|
179
|
+
const mapped = operation === "address_to_file_offset"
|
|
180
|
+
? await mapHopperFileOffset(target, result.value, options?.signal)
|
|
181
|
+
: result;
|
|
182
|
+
return mapped.ok
|
|
145
183
|
? {
|
|
146
184
|
ok: true,
|
|
147
|
-
value: createAnalysisExecution(
|
|
185
|
+
value: createAnalysisExecution(mapped.value, executionProvider, {
|
|
186
|
+
rawResult: result.value,
|
|
148
187
|
...(profile === undefined ? {} : { analysisProfile: profile }),
|
|
149
188
|
limitations: [
|
|
150
|
-
|
|
189
|
+
...(preparedImage === undefined
|
|
190
|
+
? []
|
|
191
|
+
: [
|
|
192
|
+
"REA loaded a verified thin Mach-O slice from the original FAT64 source. Identity and file offsets refer to the original file. The owned temporary image and its Hopper document close together, including on MCP shutdown.",
|
|
193
|
+
]),
|
|
194
|
+
...(CAPABILITIES.find((descriptor) => descriptor.operation === operation)?.limitations ?? []),
|
|
195
|
+
...(operation === "read_bytes"
|
|
196
|
+
? [
|
|
197
|
+
"Hopper byte reads stop at the containing segment's exclusive end; a readable prefix is returned with complete=false when the requested range crosses it.",
|
|
198
|
+
]
|
|
199
|
+
: []),
|
|
151
200
|
...(operation === "procedure_references"
|
|
152
201
|
? [
|
|
153
|
-
"
|
|
202
|
+
"Native CallReference classifications and unresolved targets are preserved. Detailed reference flags and coverage beyond reported CallReference objects remain unknown.",
|
|
154
203
|
]
|
|
155
204
|
: []),
|
|
156
205
|
],
|
|
157
206
|
}),
|
|
158
207
|
}
|
|
159
|
-
:
|
|
208
|
+
: mapped;
|
|
160
209
|
},
|
|
161
210
|
runtimeLineageSnapshots: () => {
|
|
162
211
|
const observation = client.runtimeLineage();
|
|
@@ -181,8 +230,11 @@ export class HopperProvider {
|
|
|
181
230
|
},
|
|
182
231
|
];
|
|
183
232
|
},
|
|
184
|
-
|
|
185
|
-
close: () =>
|
|
233
|
+
operationHealthSnapshot: () => client.operationHealth(),
|
|
234
|
+
close: async (options) => {
|
|
235
|
+
await regexSearch.close();
|
|
236
|
+
return client.close(options);
|
|
237
|
+
},
|
|
186
238
|
};
|
|
187
239
|
}
|
|
188
240
|
}
|
|
@@ -38,7 +38,6 @@ export const HOPPER_OPERATIONS = Object.freeze([
|
|
|
38
38
|
"set_addresses_names",
|
|
39
39
|
"set_bookmark",
|
|
40
40
|
"set_comment",
|
|
41
|
-
"set_current_document",
|
|
42
41
|
"set_inline_comment",
|
|
43
42
|
"unset_bookmark",
|
|
44
43
|
"xrefs",
|
|
@@ -69,5 +68,24 @@ export const CAPABILITIES = Object.freeze(HOPPER_OPERATIONS.map((operation) => O
|
|
|
69
68
|
}),
|
|
70
69
|
limitations: Object.freeze([
|
|
71
70
|
"Results depend on Hopper's completed static analysis.",
|
|
71
|
+
...(operation === "address_to_file_offset"
|
|
72
|
+
? [
|
|
73
|
+
"Original-file coordinates require source bytes matching the selected executable digest. A changed, unavailable, or database-only source retains native mapping facts in partial error evidence.",
|
|
74
|
+
]
|
|
75
|
+
: []),
|
|
76
|
+
...(operation === "search_strings" || operation === "search_procedures"
|
|
77
|
+
? [
|
|
78
|
+
"Regex mode uses ECMAScript Unicode semantics in a supervised worker with a five-second matching deadline. Cancellation or deadline failure stops matching without blocking Hopper; literal mode retains native casefold semantics.",
|
|
79
|
+
]
|
|
80
|
+
: []),
|
|
81
|
+
...(operation === "list_strings" ||
|
|
82
|
+
operation === "search_strings" ||
|
|
83
|
+
operation === "analyze_function"
|
|
84
|
+
? [
|
|
85
|
+
"String values cover native typed objects. Hopper may split long literals into adjacent unterminated fragments; string searches match each object independently.",
|
|
86
|
+
"Undecodable typed objects retain native display text with an explicit decoding unknown; these values do not establish decoded source literals.",
|
|
87
|
+
"Reported string encodings are inferred from typed bytes and native display; the original source's intended encoding is unknown.",
|
|
88
|
+
]
|
|
89
|
+
: []),
|
|
72
90
|
]),
|
|
73
91
|
})));
|