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
package/bridge/hopper_bridge.py
CHANGED
|
@@ -8,12 +8,12 @@ API access on this thread: moving dispatch to a worker can deadlock Hopper.
|
|
|
8
8
|
import json
|
|
9
9
|
import hmac
|
|
10
10
|
import os
|
|
11
|
-
import re
|
|
12
11
|
import socket
|
|
13
12
|
from typing import Any, Optional, Protocol, Sequence
|
|
14
13
|
|
|
15
14
|
BAD_ADDRESSES = (-1, 0xFFFFFFFFFFFFFFFF, None)
|
|
16
|
-
|
|
15
|
+
# The native label setter truncates NSString names at this UTF-16 extent.
|
|
16
|
+
HOPPER_SYMBOL_NAME_UTF16_UNITS = 1024
|
|
17
17
|
_rea_session_document = None
|
|
18
18
|
_search_inventory_cache = {}
|
|
19
19
|
_pseudocode_cache = {}
|
|
@@ -89,9 +89,11 @@ def _session_document():
|
|
|
89
89
|
global _rea_session_document
|
|
90
90
|
documents = _api().documents()
|
|
91
91
|
if _rea_session_document is not None:
|
|
92
|
+
# Hopper recreates Python wrappers; equality compares native handles.
|
|
93
|
+
# Retain our bound wrapper so cache identity stays stable across calls.
|
|
92
94
|
return (
|
|
93
95
|
_rea_session_document
|
|
94
|
-
if any(document
|
|
96
|
+
if any(document == _rea_session_document for document in documents)
|
|
95
97
|
else None
|
|
96
98
|
)
|
|
97
99
|
return _bind_session_document(documents)
|
|
@@ -174,46 +176,89 @@ def _json_safe(value):
|
|
|
174
176
|
|
|
175
177
|
|
|
176
178
|
def _document(name=None):
|
|
177
|
-
"""
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
"""Keep observations and mutations bound to the active REA target."""
|
|
180
|
+
documents = _api().documents()
|
|
181
|
+
session_document = _session_document()
|
|
182
|
+
if session_document is None:
|
|
183
|
+
raise CapabilityUnavailableError("The active REA target's Hopper document is no longer open; reopen the target with open_binary")
|
|
181
184
|
if name is not None:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return current
|
|
189
|
-
raise InvalidRequestError("Hopper document name is ambiguous")
|
|
185
|
+
# A document name is display metadata; scope it to the bound native
|
|
186
|
+
# handle even when another open target happens to have the same name.
|
|
187
|
+
if session_document.getDocumentName() == name:
|
|
188
|
+
return session_document
|
|
189
|
+
if any(candidate.getDocumentName() == name for candidate in documents):
|
|
190
|
+
raise InvalidRequestError("Hopper document belongs to another target; use open_binary to select that target")
|
|
190
191
|
raise InvalidRequestError("Unknown Hopper document")
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
192
|
+
return session_document
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _api_text(value, field):
|
|
196
|
+
"""Validate text before passing it to Hopper's native UTF-8 string API."""
|
|
197
|
+
if not isinstance(value, str):
|
|
198
|
+
raise InvalidRequestError("%s must be a string" % field)
|
|
199
|
+
if "\0" in value:
|
|
200
|
+
raise InvalidRequestError("%s contains a NUL character, which Hopper's Python API cannot represent" % field)
|
|
201
|
+
try:
|
|
202
|
+
value.encode("utf-8")
|
|
203
|
+
except UnicodeEncodeError as error:
|
|
204
|
+
raise InvalidRequestError("%s contains an unpaired Unicode surrogate, which Hopper's Python API cannot represent" % field) from error
|
|
205
|
+
return value
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _validate_name_targets(document, names):
|
|
209
|
+
"""Keep Hopper's unique-label moves within the explicitly selected addresses."""
|
|
210
|
+
targets = {address for _, address, _ in names}
|
|
211
|
+
if len(targets) != len(names):
|
|
212
|
+
raise InvalidRequestError("Batch rename selects the same address more than once; use one canonical address per target")
|
|
213
|
+
labels = set()
|
|
214
|
+
for _, address, name in names:
|
|
215
|
+
_segment(document, address)
|
|
216
|
+
if not name:
|
|
217
|
+
continue
|
|
218
|
+
if name in labels:
|
|
219
|
+
raise InvalidRequestError("Batch rename assigns the same name more than once: %s" % name)
|
|
220
|
+
labels.add(name)
|
|
221
|
+
owner = document.getAddressForName(name)
|
|
222
|
+
if owner not in BAD_ADDRESSES and owner != address and owner not in targets:
|
|
223
|
+
raise InvalidRequestError("Name %s is already assigned to %s; include that address in the batch with a replacement name" % (name, _hex(owner)))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _symbol_name(value, field):
|
|
227
|
+
"""Reject native label truncation without altering the caller's name."""
|
|
228
|
+
value = _api_text(value, field)
|
|
229
|
+
if len(value.encode("utf-16-le")) // 2 > HOPPER_SYMBOL_NAME_UTF16_UNITS:
|
|
230
|
+
raise InvalidRequestError("%s exceeds Hopper's %s UTF-16 code-unit symbol-name limit" % (field, HOPPER_SYMBOL_NAME_UTF16_UNITS))
|
|
231
|
+
return value
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _name_matches(document, address, name):
|
|
235
|
+
observed = _segment(document, address).getNameAtAddress(address)
|
|
236
|
+
return observed == name or (not name and observed is None)
|
|
202
237
|
|
|
203
238
|
|
|
204
239
|
def _address(document, value=None):
|
|
205
|
-
"""
|
|
240
|
+
"""Keep explicit hexadecimal coordinates distinct from symbol names."""
|
|
206
241
|
if value is None:
|
|
207
242
|
return document.getCurrentAddress()
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
243
|
+
_api_text(value, "Address")
|
|
244
|
+
if value.lower().startswith("0x"):
|
|
245
|
+
try:
|
|
246
|
+
address = int(value, 16)
|
|
247
|
+
except ValueError as error:
|
|
248
|
+
raise InvalidRequestError("Invalid hexadecimal Hopper address: %s" % value) from error
|
|
249
|
+
else:
|
|
250
|
+
# Names such as `add` and `face` are valid hexadecimal strings too.
|
|
251
|
+
# Prefer an observed symbol, retaining bare-hex compatibility only
|
|
252
|
+
# when Hopper has no symbol with the supplied name.
|
|
253
|
+
address = document.getAddressForName(value)
|
|
254
|
+
if address in BAD_ADDRESSES:
|
|
255
|
+
try:
|
|
256
|
+
address = int(value, 16)
|
|
257
|
+
except ValueError as error:
|
|
258
|
+
raise InvalidRequestError("Unknown Hopper address or name: %s" % value) from error
|
|
259
|
+
if not 0 <= address < 0xFFFFFFFFFFFFFFFF:
|
|
260
|
+
raise InvalidRequestError("Address is outside Hopper's usable unsigned 64-bit range: %s" % value)
|
|
261
|
+
return address
|
|
217
262
|
|
|
218
263
|
|
|
219
264
|
def _segment(document, address):
|
|
@@ -249,14 +294,18 @@ def _procedure_identity(procedure):
|
|
|
249
294
|
|
|
250
295
|
|
|
251
296
|
def _procedure_locals(procedure):
|
|
252
|
-
"""
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
297
|
+
"""Preserve public local-variable names and observed stack displacements."""
|
|
298
|
+
result = []
|
|
299
|
+
for local in procedure.getLocalVariableList():
|
|
300
|
+
name = local.name()
|
|
301
|
+
displacement = local.displacement()
|
|
302
|
+
result.append({
|
|
303
|
+
"description": "%s (stack displacement %s)" % (name if name is not None else "Unnamed local", displacement),
|
|
304
|
+
"name": name,
|
|
305
|
+
"stack_displacement": str(displacement) if displacement is not None else None,
|
|
256
306
|
"provenance": "hopper-public-python-api",
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
]
|
|
307
|
+
})
|
|
308
|
+
return result
|
|
260
309
|
|
|
261
310
|
|
|
262
311
|
def _containing_procedure(document, address):
|
|
@@ -267,26 +316,75 @@ def _containing_procedure(document, address):
|
|
|
267
316
|
return (procedure, None) if procedure is not None else (None, "not_in_procedure")
|
|
268
317
|
|
|
269
318
|
|
|
319
|
+
def _basic_block_end(procedure, block):
|
|
320
|
+
"""Normalize native block endpoints to an exclusive byte address."""
|
|
321
|
+
owner_at = getattr(procedure, "getBasicBlockAtAddress", None)
|
|
322
|
+
if not callable(owner_at):
|
|
323
|
+
raise CapabilityUnavailableError(
|
|
324
|
+
"Instruction enumeration requires Hopper basic-block ownership"
|
|
325
|
+
)
|
|
326
|
+
end = block.getEndingAddress()
|
|
327
|
+
# Hopper 6.1 returns the final instruction address, despite the Python
|
|
328
|
+
# documentation describing an exclusive end. Membership distinguishes
|
|
329
|
+
# that representation from an actual exclusive endpoint in other builds.
|
|
330
|
+
if owner_at(end) == block:
|
|
331
|
+
instruction = procedure.getSegment().getInstructionAtAddress(end)
|
|
332
|
+
if instruction is not None and instruction.getInstructionLength() > 0:
|
|
333
|
+
return end + instruction.getInstructionLength()
|
|
334
|
+
return end
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _block_instruction_addresses(procedure, block):
|
|
338
|
+
"""Walk either endpoint convention using Hopper's block ownership API.
|
|
339
|
+
|
|
340
|
+
Some Hopper builds return the final instruction start, despite the public
|
|
341
|
+
API documenting an exclusive end. Equality compares fresh native wrappers;
|
|
342
|
+
probing ownership also keeps an exclusive endpoint in the next block out.
|
|
343
|
+
"""
|
|
344
|
+
segment = procedure.getSegment()
|
|
345
|
+
address = block.getStartingAddress()
|
|
346
|
+
end = _basic_block_end(procedure, block)
|
|
347
|
+
while address < end:
|
|
348
|
+
if procedure.getBasicBlockAtAddress(address) != block:
|
|
349
|
+
break
|
|
350
|
+
instruction = segment.getInstructionAtAddress(address)
|
|
351
|
+
if instruction is None:
|
|
352
|
+
break
|
|
353
|
+
length = instruction.getInstructionLength()
|
|
354
|
+
if length <= 0 or address + length > end:
|
|
355
|
+
break
|
|
356
|
+
yield address
|
|
357
|
+
address += length
|
|
358
|
+
|
|
359
|
+
|
|
270
360
|
def _instruction_addresses(procedure):
|
|
271
361
|
result = []
|
|
272
362
|
seen = set()
|
|
273
|
-
segment = procedure.getSegment()
|
|
274
363
|
for block in procedure.basicBlockIterator():
|
|
275
|
-
address
|
|
276
|
-
|
|
277
|
-
|
|
364
|
+
for address in _block_instruction_addresses(procedure, block):
|
|
365
|
+
if address in seen:
|
|
366
|
+
continue
|
|
278
367
|
seen.add(address)
|
|
279
|
-
instruction = segment.getInstructionAtAddress(address)
|
|
280
|
-
if instruction is None:
|
|
281
|
-
break
|
|
282
368
|
result.append(address)
|
|
283
|
-
length = instruction.getInstructionLength()
|
|
284
|
-
if length <= 0:
|
|
285
|
-
break
|
|
286
|
-
address += length
|
|
287
369
|
return result
|
|
288
370
|
|
|
289
371
|
|
|
372
|
+
def _native_calls(procedure, direction):
|
|
373
|
+
references = procedure.getAllCallees() if direction == "outgoing" else procedure.getAllCallers()
|
|
374
|
+
kinds = {0: "none", 1: "unknown", 2: "direct", 3: "objective_c"}
|
|
375
|
+
calls = {}
|
|
376
|
+
unresolved = []
|
|
377
|
+
for reference in references:
|
|
378
|
+
source, target, kind = reference.fromAddress(), reference.toAddress(), reference.type()
|
|
379
|
+
if source in BAD_ADDRESSES:
|
|
380
|
+
continue
|
|
381
|
+
if target in BAD_ADDRESSES:
|
|
382
|
+
unresolved.append({"address": _hex(source), "reason": "Native CallReference has no resolved target (type %s)" % kind})
|
|
383
|
+
continue
|
|
384
|
+
calls[(source, target)] = {"classification": kinds.get(kind, "unknown"), "provider_type": kind, "provenance": "hopper-public-python-api:CallReference"}
|
|
385
|
+
return calls, sorted(unresolved, key=lambda item: int(item["address"], 16))
|
|
386
|
+
|
|
387
|
+
|
|
290
388
|
def _procedure_references(document, params):
|
|
291
389
|
procedure = _procedure(document, params.get("procedure"))
|
|
292
390
|
direction = params.get("direction", "outgoing")
|
|
@@ -299,6 +397,8 @@ def _procedure_references(document, params):
|
|
|
299
397
|
references = segment.getReferencesFromAddress(address) if direction == "outgoing" else segment.getReferencesOfAddress(address)
|
|
300
398
|
for reference in references:
|
|
301
399
|
edges.add((address, reference) if direction == "outgoing" else (reference, address))
|
|
400
|
+
calls, unresolved = _native_calls(procedure, direction)
|
|
401
|
+
edges.update(calls)
|
|
302
402
|
ordered = sorted(edges)
|
|
303
403
|
items = []
|
|
304
404
|
for source, target in ordered:
|
|
@@ -309,16 +409,15 @@ def _procedure_references(document, params):
|
|
|
309
409
|
"target_address": _hex(target),
|
|
310
410
|
"source_procedure": _procedure_identity(source_procedure) if source_procedure is not None else None,
|
|
311
411
|
"target_procedure": _procedure_identity(target_procedure) if target_procedure is not None else None,
|
|
312
|
-
"kind": _unavailable("Hopper
|
|
412
|
+
"kind": _unavailable("Hopper exposes partial CallReference classification, but not detailed reference flags"),
|
|
413
|
+
**({"call": calls[(source, target)]} if (source, target) in calls else {}),
|
|
313
414
|
})
|
|
314
415
|
return {
|
|
315
416
|
"procedure": _procedure_identity(procedure), "direction": direction,
|
|
316
417
|
"reference_kinds_available": False,
|
|
317
|
-
#
|
|
318
|
-
#
|
|
319
|
-
|
|
320
|
-
# unknown coverage rather than claiming the list is exhaustive.
|
|
321
|
-
"unresolved_calls": [],
|
|
418
|
+
# These are native CallReference objects, not proof that every unresolved
|
|
419
|
+
# dispatch site has been enumerated by Hopper.
|
|
420
|
+
"unresolved_calls": unresolved,
|
|
322
421
|
"references": items,
|
|
323
422
|
}
|
|
324
423
|
|
|
@@ -333,11 +432,61 @@ def _procedure_map(document):
|
|
|
333
432
|
|
|
334
433
|
|
|
335
434
|
def _strings(document):
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
435
|
+
return {address: record["value"] for address, record in _string_inventory(document).items()}
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def _string_record(segment, address, display):
|
|
439
|
+
"""Read one native typed object, retaining its shortened display separately."""
|
|
440
|
+
length = segment.getObjectLength(address)
|
|
441
|
+
end = segment.getStartingAddress() + segment.getLength()
|
|
442
|
+
if isinstance(length, bool) or not isinstance(length, int) or length <= 0 or length > end - address:
|
|
443
|
+
raise CapabilityUnavailableError("Hopper reported an invalid string object extent at %s" % _hex(address))
|
|
444
|
+
raw = segment.readBytes(address, length)
|
|
445
|
+
if not isinstance(raw, (bytes, bytearray)) or len(raw) != length:
|
|
446
|
+
raise CapabilityUnavailableError("Hopper could not read the complete string object at %s" % _hex(address))
|
|
447
|
+
kind = segment.getTypeAtAddress(address)
|
|
448
|
+
encodings = ("utf-8", "latin-1") if kind == segment.TYPE_ASCII else ("utf-16-le", "utf-16-be") if kind == segment.TYPE_UNICODE else ()
|
|
449
|
+
# Native display escaping is not invertible (a literal backslash-n and a
|
|
450
|
+
# newline can render alike). Decode byte strings directly; for UTF-16,
|
|
451
|
+
# compare rendered candidates to establish an unambiguous byte order.
|
|
452
|
+
candidates = []
|
|
453
|
+
for encoding in encodings:
|
|
454
|
+
terminator = b"\x00\x00" if encoding.startswith("utf-16") else b"\x00"
|
|
455
|
+
terminated = raw.endswith(terminator)
|
|
456
|
+
payload = raw[:-len(terminator)] if terminated else raw
|
|
457
|
+
try:
|
|
458
|
+
value = payload.decode(encoding)
|
|
459
|
+
except UnicodeDecodeError:
|
|
460
|
+
continue
|
|
461
|
+
record = {"value": value, "provider_value": display, "string": {"encoding": encoding, "encoding_status": "inferred", "termination": "present_or_not_required" if terminated else "missing", "byte_length": length}}
|
|
462
|
+
if kind == segment.TYPE_ASCII:
|
|
463
|
+
return record
|
|
464
|
+
rendered = value.replace('"', '\\"').replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
|
|
465
|
+
if rendered == display or (display.endswith("\u2026") and display[:-1] and rendered.startswith(display[:-1])):
|
|
466
|
+
candidates.append(record)
|
|
467
|
+
if candidates and len({candidate["value"] for candidate in candidates}) == 1:
|
|
468
|
+
return candidates[0]
|
|
469
|
+
raise CapabilityUnavailableError("Hopper's string display cannot be reconciled with its typed bytes at %s; inspect the bytes and encoding explicitly" % _hex(address))
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def _string_inventory(document, addresses=None):
|
|
473
|
+
key = (id(document), "string_objects")
|
|
474
|
+
objects = _search_inventory_cache.get(key)
|
|
475
|
+
if objects is None:
|
|
476
|
+
objects = {address: (segment, display) for segment in document.getSegmentsList() for display, address in segment.getStringsList()}
|
|
477
|
+
_search_inventory_cache[key] = objects
|
|
478
|
+
key = (id(document), "string_records")
|
|
479
|
+
records = _search_inventory_cache.setdefault(key, {})
|
|
480
|
+
selected = sorted(objects if addresses is None else objects.keys() & addresses)
|
|
481
|
+
for address in selected:
|
|
482
|
+
name = _hex(address)
|
|
483
|
+
if name not in records:
|
|
484
|
+
segment, display = objects[address]
|
|
485
|
+
try:
|
|
486
|
+
records[name] = _string_record(segment, address, display)
|
|
487
|
+
except CapabilityUnavailableError as error:
|
|
488
|
+
records[name] = {"value": display, "provider_value": display, "decoding": _unavailable(str(error))}
|
|
489
|
+
return {_hex(address): records[_hex(address)] for address in selected}
|
|
341
490
|
|
|
342
491
|
|
|
343
492
|
def _invalidate_search_inventory(document):
|
|
@@ -397,17 +546,18 @@ def _search_results(document, kind, params):
|
|
|
397
546
|
needle = pattern if case_sensitive else pattern.casefold()
|
|
398
547
|
matches = lambda value: needle in (value if case_sensitive else value.casefold())
|
|
399
548
|
else:
|
|
400
|
-
|
|
401
|
-
expression = re.compile(pattern, 0 if case_sensitive else re.IGNORECASE)
|
|
402
|
-
except (re.error, OverflowError) as error:
|
|
403
|
-
raise InvalidRequestError("Invalid regex pattern") from error
|
|
404
|
-
matches = lambda value: expression.search(value) is not None
|
|
549
|
+
raise CapabilityUnavailableError("Regex matching requires REA's supervised worker; the native bridge only executes literal searches")
|
|
405
550
|
|
|
406
551
|
selected = []
|
|
407
552
|
for item in _search_inventory(document, kind):
|
|
408
553
|
if not matches(item[1]):
|
|
409
554
|
continue
|
|
410
555
|
selected.append(item)
|
|
556
|
+
if not selected:
|
|
557
|
+
return []
|
|
558
|
+
if kind == "string":
|
|
559
|
+
records = _string_inventory(document)
|
|
560
|
+
return [{"address": address, **records[address]} for address, _ in selected]
|
|
411
561
|
return [
|
|
412
562
|
{
|
|
413
563
|
"address": address,
|
|
@@ -450,25 +600,11 @@ def _render_instruction(segment, address):
|
|
|
450
600
|
|
|
451
601
|
def _assembly(procedure):
|
|
452
602
|
"""Render assembly while guarding against malformed instruction cycles."""
|
|
453
|
-
lines = []
|
|
454
603
|
segment = procedure.getSegment()
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
while address < end and address not in seen:
|
|
460
|
-
seen.add(address)
|
|
461
|
-
instruction = segment.getInstructionAtAddress(address)
|
|
462
|
-
if instruction is None:
|
|
463
|
-
break
|
|
464
|
-
line = _render_instruction(segment, address)
|
|
465
|
-
if line is not None:
|
|
466
|
-
lines.append(line)
|
|
467
|
-
length = instruction.getInstructionLength()
|
|
468
|
-
if length <= 0:
|
|
469
|
-
break
|
|
470
|
-
address += length
|
|
471
|
-
return "\n".join(lines)
|
|
604
|
+
return "\n".join(
|
|
605
|
+
line for address in _instruction_addresses(procedure)
|
|
606
|
+
if (line := _render_instruction(segment, address)) is not None
|
|
607
|
+
)
|
|
472
608
|
|
|
473
609
|
|
|
474
610
|
def _read_function_instructions(document, params):
|
|
@@ -505,7 +641,7 @@ def _analyze_function(document, params):
|
|
|
505
641
|
successors.append(_hex(successor))
|
|
506
642
|
blocks.append({
|
|
507
643
|
"start": _hex(block.getStartingAddress()),
|
|
508
|
-
"end": _hex(block
|
|
644
|
+
"end": _hex(_basic_block_end(procedure, block)),
|
|
509
645
|
"successors": sorted(set(successors), key=lambda value: int(value, 16)),
|
|
510
646
|
})
|
|
511
647
|
pseudo = _pseudocode(document, procedure) or ""
|
|
@@ -529,6 +665,10 @@ def _analyze_function(document, params):
|
|
|
529
665
|
incoming = []
|
|
530
666
|
outgoing = []
|
|
531
667
|
procedure_addresses = set(addresses)
|
|
668
|
+
outgoing_calls, unresolved_calls = _native_calls(procedure, "outgoing")
|
|
669
|
+
incoming_calls, _ = _native_calls(procedure, "incoming")
|
|
670
|
+
calls = {**incoming_calls, **outgoing_calls}
|
|
671
|
+
edges.update(calls)
|
|
532
672
|
for source, target in sorted(edges):
|
|
533
673
|
source_procedure, _ = _containing_procedure(document, source)
|
|
534
674
|
target_procedure, _ = _containing_procedure(document, target)
|
|
@@ -537,16 +677,14 @@ def _analyze_function(document, params):
|
|
|
537
677
|
"target_address": _hex(target),
|
|
538
678
|
"source_procedure": _procedure_identity(source_procedure) if source_procedure is not None else None,
|
|
539
679
|
"target_procedure": _procedure_identity(target_procedure) if target_procedure is not None else None,
|
|
540
|
-
"kind": _unavailable("Hopper
|
|
680
|
+
"kind": _unavailable("Hopper exposes partial CallReference classification, but not detailed reference flags"),
|
|
681
|
+
**({"call": calls[(source, target)]} if (source, target) in calls else {}),
|
|
541
682
|
}
|
|
542
683
|
if target in procedure_addresses and source not in procedure_addresses:
|
|
543
684
|
incoming.append(item)
|
|
544
685
|
if source in procedure_addresses:
|
|
545
686
|
outgoing.append(item)
|
|
546
|
-
string_map = {
|
|
547
|
-
int(address, 16): value
|
|
548
|
-
for address, value in _search_inventory(document, "string")
|
|
549
|
-
}
|
|
687
|
+
string_map = {int(address, 16): record for address, record in _string_inventory(document, {int(edge["target_address"], 16) for edge in outgoing}).items()}
|
|
550
688
|
name_map = {
|
|
551
689
|
int(address, 16): value
|
|
552
690
|
for address, value in _search_inventory(document, "name")
|
|
@@ -556,7 +694,7 @@ def _analyze_function(document, params):
|
|
|
556
694
|
for edge in outgoing:
|
|
557
695
|
target = int(edge["target_address"], 16)
|
|
558
696
|
if target in string_map:
|
|
559
|
-
referenced_strings.append({"address": edge["target_address"],
|
|
697
|
+
referenced_strings.append({"address": edge["target_address"], **string_map[target], "source_address": edge["source_address"]})
|
|
560
698
|
if target in name_map:
|
|
561
699
|
referenced_names.append({"address": edge["target_address"], "value": name_map[target], "source_address": edge["source_address"]})
|
|
562
700
|
comments.sort(key=lambda item: (int(item["address"], 16), item["kind"]))
|
|
@@ -574,13 +712,14 @@ def _analyze_function(document, params):
|
|
|
574
712
|
"callers": callers, "callees": callees,
|
|
575
713
|
"incoming_references": incoming,
|
|
576
714
|
"outgoing_references": outgoing,
|
|
715
|
+
"unresolved_calls": unresolved_calls,
|
|
577
716
|
"referenced_strings": referenced_strings,
|
|
578
717
|
"referenced_names": referenced_names,
|
|
579
718
|
"basic_blocks": blocks,
|
|
580
719
|
"limitations": [
|
|
581
|
-
"
|
|
720
|
+
"Native CallReference classifications are observed where available; detailed reference flags remain unknown.",
|
|
582
721
|
"Hopper's public Python API does not expose equivalent external or thunk classification in this dossier.",
|
|
583
|
-
"
|
|
722
|
+
"Native calls without resolved target addresses are not represented as edges; enumeration beyond reported CallReference objects is unknown.",
|
|
584
723
|
"Pseudocode and assembly are provider-specific representations, not original source.",
|
|
585
724
|
],
|
|
586
725
|
}
|
|
@@ -588,7 +727,6 @@ def _analyze_function(document, params):
|
|
|
588
727
|
|
|
589
728
|
def _dispatch(method, params):
|
|
590
729
|
"""Dispatch only the closed operation set implemented by REA's public tools."""
|
|
591
|
-
global _selected_document
|
|
592
730
|
if method == "health":
|
|
593
731
|
return {"name": "REA Hopper bridge", "version": "1.0.0", "run_id": REA_RUN_ID}
|
|
594
732
|
if method in ("shutdown", "shutdown_document"):
|
|
@@ -622,14 +760,9 @@ def _dispatch(method, params):
|
|
|
622
760
|
"document_closed": document_closed,
|
|
623
761
|
}
|
|
624
762
|
if method == "list_documents":
|
|
625
|
-
return [document.getDocumentName() for document in
|
|
763
|
+
return [document.getDocumentName() for document in _api().documents()]
|
|
626
764
|
if method == "current_document":
|
|
627
765
|
return _document().getDocumentName()
|
|
628
|
-
if method == "set_current_document":
|
|
629
|
-
document = _document(params.get("document"))
|
|
630
|
-
_selected_document = document.getDocumentName()
|
|
631
|
-
return _selected_document
|
|
632
|
-
|
|
633
766
|
document = _document(params.get("document"))
|
|
634
767
|
if method in EXHAUSTIVE_ANALYSIS_METHODS:
|
|
635
768
|
_api().require_analysis_complete(document, method)
|
|
@@ -650,10 +783,17 @@ def _dispatch(method, params):
|
|
|
650
783
|
"Hopper's public Python API does not expose readBytes"
|
|
651
784
|
)
|
|
652
785
|
address = _address(document, params.get("address"))
|
|
653
|
-
|
|
786
|
+
segment = _segment(document, address)
|
|
787
|
+
# Document.readBytes delegates to one Segment and returns False when
|
|
788
|
+
# the requested range crosses its end. Preserve the readable prefix.
|
|
789
|
+
available = segment.getStartingAddress() + segment.getLength() - address
|
|
790
|
+
value = reader(address, min(length, available))
|
|
791
|
+
if value is False or value is None:
|
|
792
|
+
raise InvalidRequestError("Hopper could not read the requested byte range at %s" % _hex(address))
|
|
654
793
|
if not isinstance(value, (bytes, bytearray)):
|
|
655
794
|
raise CapabilityUnavailableError(
|
|
656
|
-
"Hopper
|
|
795
|
+
"Hopper readBytes returned %s for the requested %s-byte range at %s"
|
|
796
|
+
% (type(value).__name__, length, _hex(address))
|
|
657
797
|
)
|
|
658
798
|
data = bytes(value)
|
|
659
799
|
return {
|
|
@@ -678,7 +818,26 @@ def _dispatch(method, params):
|
|
|
678
818
|
or offset < 0
|
|
679
819
|
):
|
|
680
820
|
raise InvalidRequestError("Address has no authoritative file-offset mapping")
|
|
681
|
-
|
|
821
|
+
inverse = getattr(document, "getAddressFromFileOffset", None)
|
|
822
|
+
if not callable(inverse):
|
|
823
|
+
raise CapabilityUnavailableError(
|
|
824
|
+
"Hopper's public Python API cannot verify the file-offset mapping by reverse lookup"
|
|
825
|
+
)
|
|
826
|
+
# Synthetic memory can report offset zero, which belongs to the actual
|
|
827
|
+
# file header. An integer alone does not prove source-file provenance.
|
|
828
|
+
if inverse(offset) != address:
|
|
829
|
+
raise InvalidRequestError("Address has no authoritative file-offset mapping: reverse lookup disagrees at %s" % _hex(address))
|
|
830
|
+
if offset > 9007199254740991:
|
|
831
|
+
raise CapabilityUnavailableError("Provider file offset exceeds the exact JSON integer range")
|
|
832
|
+
header_address = inverse(0)
|
|
833
|
+
reader = getattr(document, "readBytes", None)
|
|
834
|
+
header = reader(header_address, 12) if header_address not in BAD_ADDRESSES and document.getSegmentAtAddress(header_address) is not None and callable(reader) else None
|
|
835
|
+
return {
|
|
836
|
+
"address": _hex(address),
|
|
837
|
+
"provider_file_offset": offset,
|
|
838
|
+
"provider_source_path": document.getExecutableFilePath(),
|
|
839
|
+
"provider_image_header_hex": bytes(header).hex() if isinstance(header, (bytes, bytearray)) and len(header) == 12 else None,
|
|
840
|
+
}
|
|
682
841
|
if method == "resolve_containing_procedure":
|
|
683
842
|
address = _address(document, params.get("address"))
|
|
684
843
|
procedure, reason = _containing_procedure(document, address)
|
|
@@ -694,8 +853,13 @@ def _dispatch(method, params):
|
|
|
694
853
|
return _procedure_name(_procedure(document))
|
|
695
854
|
if method == "goto_address":
|
|
696
855
|
address = _address(document, params.get("address"))
|
|
856
|
+
segment = _segment(document, address)
|
|
857
|
+
expected = segment.getInstructionStart(address)
|
|
697
858
|
document.moveCursorAtAddress(address)
|
|
698
|
-
|
|
859
|
+
observed = document.getCurrentAddress()
|
|
860
|
+
if observed != (address if expected in BAD_ADDRESSES else expected):
|
|
861
|
+
raise InvalidRequestError("Hopper cursor did not reach the requested object at %s; observed %s" % (_hex(address), _hex(observed)))
|
|
862
|
+
return _hex(observed)
|
|
699
863
|
if method in ("address_name", "comment", "inline_comment", "xrefs"):
|
|
700
864
|
target = _address(document, params.get("address"))
|
|
701
865
|
segment = _segment(document, target)
|
|
@@ -708,12 +872,22 @@ def _dispatch(method, params):
|
|
|
708
872
|
return [_hex(value) for value in segment.getReferencesOfAddress(target)]
|
|
709
873
|
if method in ("next_address", "prev_address"):
|
|
710
874
|
target = _address(document, params.get("address"))
|
|
875
|
+
segment = _segment(document, target)
|
|
711
876
|
if method == "next_address":
|
|
712
|
-
|
|
877
|
+
start = segment.getInstructionStart(target)
|
|
878
|
+
if start in BAD_ADDRESSES:
|
|
879
|
+
raise InvalidRequestError("No analyzed object exists at the requested address")
|
|
880
|
+
length = segment.getObjectLength(start)
|
|
881
|
+
if length in BAD_ADDRESSES or length <= 0:
|
|
882
|
+
raise InvalidRequestError("No next analyzed object exists at the requested address")
|
|
883
|
+
result = start + length
|
|
713
884
|
else:
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
885
|
+
previous_segment = document.getSegmentAtAddress(target - 1) if target > 0 else None
|
|
886
|
+
if previous_segment is None:
|
|
887
|
+
raise InvalidRequestError("No previous address exists in mapped memory")
|
|
888
|
+
result = previous_segment.getInstructionStart(target - 1)
|
|
889
|
+
if result in BAD_ADDRESSES or document.getSegmentAtAddress(result) is None:
|
|
890
|
+
raise InvalidRequestError("No adjacent analyzed object exists in mapped memory")
|
|
717
891
|
return _hex(result)
|
|
718
892
|
if method == "list_segments":
|
|
719
893
|
result = []
|
|
@@ -747,12 +921,9 @@ def _dispatch(method, params):
|
|
|
747
921
|
if method == "list_procedures":
|
|
748
922
|
return [{"address": address, "value": value} for address, value in _search_inventory(document, "procedure")]
|
|
749
923
|
if method == "list_strings":
|
|
750
|
-
values = dict(_search_inventory(document, "string"))
|
|
751
924
|
requested = params.get("address")
|
|
752
|
-
if requested is
|
|
753
|
-
|
|
754
|
-
values = {key: values[key]} if key in values else {}
|
|
755
|
-
return [{"address": address, "value": value} for address, value in values.items()]
|
|
925
|
+
values = _string_inventory(document, None if requested is None else {_address(document, requested)})
|
|
926
|
+
return [{"address": address, **record} for address, record in values.items()]
|
|
756
927
|
if method == "list_names":
|
|
757
928
|
result = dict(_search_inventory(document, "name"))
|
|
758
929
|
requested = params.get("address")
|
|
@@ -777,7 +948,7 @@ def _dispatch(method, params):
|
|
|
777
948
|
return sorted((_hex(item.getEntryPoint()) for item in procedure.getAllCalleeProcedures()), key=lambda value: int(value, 16))
|
|
778
949
|
if method == "procedure_info":
|
|
779
950
|
blocks = list(procedure.basicBlockIterator())
|
|
780
|
-
length = sum(max(0, block
|
|
951
|
+
length = sum(max(0, _basic_block_end(procedure, block) - block.getStartingAddress()) for block in blocks)
|
|
781
952
|
return {
|
|
782
953
|
"name": _procedure_name(procedure),
|
|
783
954
|
"entrypoint": _hex(procedure.getEntryPoint()),
|
|
@@ -790,35 +961,51 @@ def _dispatch(method, params):
|
|
|
790
961
|
}
|
|
791
962
|
if method == "set_address_name":
|
|
792
963
|
address = _address(document, params.get("address"))
|
|
964
|
+
name = _symbol_name(params["name"], "Name")
|
|
965
|
+
_validate_name_targets(document, [(params.get("address"), address, name)])
|
|
793
966
|
try:
|
|
794
|
-
result = document.setNameAtAddress(address,
|
|
967
|
+
result = document.setNameAtAddress(address, name)
|
|
795
968
|
finally:
|
|
796
969
|
_invalidate_search_inventory(document)
|
|
797
970
|
_invalidate_pseudocode(document)
|
|
798
|
-
return result
|
|
971
|
+
return bool(result) and _name_matches(document, address, name)
|
|
799
972
|
if method == "set_addresses_names":
|
|
973
|
+
# Validate all destinations before applying any annotation. A malformed
|
|
974
|
+
# later address must not discard the result of an earlier mutation.
|
|
975
|
+
names = [(key, _address(document, key), _symbol_name(value, "Name for %s" % key)) for key, value in params["names"].items()]
|
|
976
|
+
_validate_name_targets(document, names)
|
|
800
977
|
try:
|
|
801
|
-
result = {key: document.setNameAtAddress(
|
|
978
|
+
result = {key: document.setNameAtAddress(address, value) for key, address, value in names}
|
|
802
979
|
finally:
|
|
803
980
|
_invalidate_search_inventory(document)
|
|
804
981
|
_invalidate_pseudocode(document)
|
|
805
|
-
return result
|
|
982
|
+
return {key: bool(result[key]) and _name_matches(document, address, value) for key, address, value in names}
|
|
806
983
|
if method in ("set_comment", "set_inline_comment"):
|
|
807
984
|
address = _address(document, params.get("address"))
|
|
985
|
+
comment = _api_text(params["comment"], "Comment")
|
|
808
986
|
segment = _segment(document, address)
|
|
809
987
|
setter = segment.setCommentAtAddress if method == "set_comment" else segment.setInlineCommentAtAddress
|
|
810
988
|
getter = segment.getCommentAtAddress if method == "set_comment" else segment.getInlineCommentAtAddress
|
|
811
|
-
setter(address,
|
|
989
|
+
setter(address, comment)
|
|
812
990
|
_invalidate_pseudocode(document)
|
|
813
|
-
|
|
991
|
+
observed = getter(address)
|
|
992
|
+
return observed == comment or (comment == "" and observed is None)
|
|
814
993
|
if method == "list_bookmarks":
|
|
815
994
|
return [{"address": _hex(item), "name": document.getBookmarkName(item)} for item in document.getBookmarks()]
|
|
816
995
|
if method == "set_bookmark":
|
|
817
996
|
address = _address(document, params.get("address"))
|
|
818
|
-
document
|
|
997
|
+
_segment(document, address)
|
|
998
|
+
name = params.get("name")
|
|
999
|
+
if name is not None:
|
|
1000
|
+
_api_text(name, "Bookmark name")
|
|
1001
|
+
document.setBookmarkAtAddress(address, name)
|
|
819
1002
|
return document.hasBookmarkAtAddress(address)
|
|
820
1003
|
if method == "unset_bookmark":
|
|
821
1004
|
address = _address(document, params.get("address"))
|
|
1005
|
+
# Permit removing a legacy orphan bookmark, but do not report success
|
|
1006
|
+
# for an unmapped address with no bookmark to remove.
|
|
1007
|
+
if not document.hasBookmarkAtAddress(address):
|
|
1008
|
+
_segment(document, address)
|
|
822
1009
|
document.removeBookmarkAtAddress(address)
|
|
823
1010
|
return not document.hasBookmarkAtAddress(address)
|
|
824
1011
|
raise InvalidRequestError("Unknown bridge method")
|
|
@@ -913,14 +1100,14 @@ def _diagnostic_type(error):
|
|
|
913
1100
|
|
|
914
1101
|
|
|
915
1102
|
def _safe_diagnostic(error):
|
|
916
|
-
"""
|
|
1103
|
+
"""Preserve bridge validation reasons while excluding transport credentials."""
|
|
917
1104
|
diagnostic_type = _diagnostic_type(error)
|
|
918
1105
|
if diagnostic_type == "capability_unavailable":
|
|
919
1106
|
message = str(error)
|
|
920
1107
|
elif diagnostic_type == "authorization":
|
|
921
1108
|
message = "Invalid bridge capability"
|
|
922
1109
|
elif diagnostic_type == "invalid_request":
|
|
923
|
-
message =
|
|
1110
|
+
message = str(error)
|
|
924
1111
|
else:
|
|
925
1112
|
message = "%s: Hopper bridge operation failed" % type(error).__name__
|
|
926
1113
|
return {"code": -32000, "message": message, "type": diagnostic_type}
|