rea-agents 3.0.0 → 3.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 +83 -108
- package/bridge/ghidra/ReaGhidraBridge.java +609 -841
- package/bridge/hopper_bridge.py +99 -344
- package/dist/application/AbortablePromise.js +6 -3
- package/dist/application/AnalysisContextQueries.js +21 -9
- package/dist/application/AnalysisSnapshotCache.js +0 -1
- package/dist/application/AnalysisSnapshotFiles.js +7 -7
- package/dist/application/AndroidApplicationService.js +1 -1
- package/dist/application/AppleApplicationService.js +1 -1
- package/dist/application/ArtifactExtraction.js +35 -54
- package/dist/application/ArtifactExtractionDestination.js +17 -0
- package/dist/application/ArtifactGraphConstruction.js +2 -17
- package/dist/application/ArtifactInventory/classify.js +2 -6
- package/dist/application/ArtifactInventory/hash.js +2 -20
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +8 -15
- package/dist/application/ArtifactInventory/scanReader.js +76 -58
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/ArtifactInventory.js +6 -14
- package/dist/application/AuthorizedArtifactInventory.js +3 -13
- package/dist/application/BinarySession.js +54 -28
- package/dist/application/BinarySessionComposition.js +0 -11
- package/dist/application/BinarySessionOpen.js +2 -1
- package/dist/application/BinarySessionRecords.js +24 -86
- package/dist/application/BinarySessionStatus.js +16 -21
- package/dist/application/BinaryTargetResolver.js +216 -0
- package/dist/application/BrowserEvidence.js +39 -57
- package/dist/application/BrowserObservationService.js +3 -6
- package/dist/application/BrowserScenarioCaptureService.js +3 -6
- package/dist/application/BrowserScenarioEvidence.js +3 -3
- package/dist/application/CallPathTracing.js +2 -36
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +143 -77
- package/dist/application/ClientConfigurationDocument.js +27 -0
- package/dist/application/ClientRegistrationStatus.js +16 -13
- package/dist/application/CommandShimReplay.js +14 -1
- package/dist/application/DirectAnalysis.js +22 -46
- package/dist/application/DirectAnalysisStatus.js +5 -61
- package/dist/application/Doctor.js +11 -32
- package/dist/application/DoctorDiagnostics.js +1 -2
- package/dist/application/DoctorScope.js +1 -1
- package/dist/application/ElectronActiveEvidence.js +50 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +78 -0
- package/dist/application/ElectronBoundaryAnalysis.js +7 -8
- package/dist/application/ElectronBoundaryGraphContext.js +1 -1
- package/dist/application/ElectronBoundaryGraphIpc.js +3 -3
- package/dist/application/ElectronBoundaryGraphNative.js +1 -2
- package/dist/application/ElectronBoundaryGraphWindows.js +6 -8
- package/dist/application/ElectronEvidence.js +4 -7
- package/dist/application/ElectronObservationService.js +5 -9
- package/dist/application/EnhancedLiteralTracing.js +42 -65
- package/dist/application/EnhancedTools.js +98 -64
- package/dist/application/EvidenceBundleCommands.js +16 -12
- package/dist/application/EvidenceBundleFiles.js +9 -15
- package/dist/application/EvidenceLedger.js +14 -42
- package/dist/application/FilesystemSnapshot.js +2 -3
- package/dist/application/InterfaceBuilderAnalysis.js +266 -0
- package/dist/application/InventoryProjectionEvidence.js +4 -2
- package/dist/application/InvestigationProviders.js +1 -1
- package/dist/application/JavaScriptApplicationEvidence.js +2 -5
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +6 -10
- package/dist/application/JavaScriptApplicationService.js +6 -29
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +5 -5
- package/dist/application/JavaScriptApplicationWorkflowService.js +0 -8
- package/dist/application/JavaScriptArtifactAnalysis.js +38 -127
- package/dist/application/JavaScriptArtifactFiles.js +67 -107
- package/dist/application/JavaScriptArtifactGraphAccumulator.js +0 -7
- package/dist/application/JavaScriptArtifactGraphBuilder.js +7 -58
- package/dist/application/JavaScriptArtifactGraphBundlers.js +1 -6
- package/dist/application/JavaScriptArtifactGraphContext.js +12 -39
- package/dist/application/JavaScriptArtifactGraphDocuments.js +4 -11
- package/dist/application/JavaScriptArtifactGraphEvidence.js +0 -14
- package/dist/application/JavaScriptArtifactGraphFindings.js +3 -3
- package/dist/application/JavaScriptArtifactGraphStructure.js +16 -17
- package/dist/application/JavaScriptArtifactPathResolution.js +61 -49
- package/dist/application/JavaScriptArtifactReconstruction.js +5 -10
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -14
- package/dist/application/JavaScriptJsonModules.js +2 -2
- package/dist/application/JavaScriptModuleRelationships.js +22 -27
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayPlanning.js +9 -3
- package/dist/application/JavaScriptReplayService.js +29 -47
- package/dist/application/JavaScriptReturnShapeProjection.js +12 -42
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +7 -8
- package/dist/application/JavaScriptRuntimeObservationService.js +4 -8
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +2 -3
- package/dist/application/JavaScriptSemanticGraphBuilder.js +11 -41
- package/dist/application/JavaScriptSemanticGraphConstruction.js +5 -29
- package/dist/application/JavaScriptSemanticGraphEvidence.js +1 -1
- package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +1 -1
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +0 -13
- package/dist/application/JavaScriptSemanticGraphProjection.js +1 -3
- package/dist/application/JavaScriptSemanticTraceService.js +1 -10
- package/dist/application/JsonFiles.js +79 -0
- package/dist/application/LinuxHopper.js +11 -9
- package/dist/application/LoopbackReplay.js +26 -23
- package/dist/application/LoopbackReplayRecorder.js +29 -1
- package/dist/application/ManagedApplicationGraphService.js +1 -2
- package/dist/application/ManagedMemberComparisonService.js +11 -41
- package/dist/application/ManagedNativeVerificationService.js +1 -2
- package/dist/application/ManagedReconstructionService.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +14 -13
- package/dist/application/NativeApiInspection.js +2 -7
- package/dist/application/NativeUiActionTrace.js +394 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +11 -16
- package/dist/application/PermissionAuthority.js +15 -7
- package/dist/application/PermissionFailure.js +5 -0
- package/dist/application/ProcessCaptureAuthority.js +5 -7
- package/dist/application/ProcessCaptureJournal.js +3 -2
- package/dist/application/ProcessCaptureLifecycle.js +10 -12
- package/dist/application/ProcessCheckpoints.js +29 -11
- package/dist/application/ProcessCli.js +8 -17
- package/dist/application/ProcessEvidence.js +5 -7
- package/dist/application/ProcessHarness.js +60 -20
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProcessReactiveCoordinator.js +2 -4
- package/dist/application/ProcessReactiveEffects.js +9 -3
- package/dist/application/ProcessReactiveHarness.js +13 -7
- package/dist/application/ProcessSampling.js +2 -4
- package/dist/application/ProcessTimer.js +39 -0
- package/dist/application/ProjectPermissionStore.js +39 -95
- package/dist/application/RealHopperAssertions.js +20 -66
- package/dist/application/ReconstructionCoverageService.js +12 -58
- package/dist/application/ReconstructionObligationAuthority.js +2 -2
- package/dist/application/ReconstructionObligationCandidates.js +4 -4
- package/dist/application/ReconstructionObligationLedgerEvaluation.js +8 -15
- package/dist/application/ReconstructionObligationLedgerProjection.js +3 -7
- package/dist/application/ReconstructionObligationLedgerService.js +19 -38
- package/dist/application/ReferenceSourceImport.js +21 -47
- package/dist/application/ReferenceSourceImportEntries.js +2 -4
- package/dist/application/ReferenceSourceImportPolicy.js +5 -32
- package/dist/application/ReferenceSourceImportTypes.js +0 -16
- package/dist/application/RuntimeExecutableDiagnostics.js +55 -29
- package/dist/application/SessionProviderRouter.js +2 -2
- package/dist/application/Setup.js +1 -3
- package/dist/application/SetupClientConfiguration.js +22 -88
- package/dist/application/SetupRegistrationEnvironment.js +0 -7
- package/dist/application/StoreFileLock.js +119 -0
- package/dist/application/TerminalRenderer.js +2 -3
- package/dist/application/Uninstall.js +9 -14
- package/dist/application/UnknownEvidence.js +1 -1
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/artifacts/ArtifactPaths.js +2 -5
- package/dist/artifacts/ArtifactProvider.js +43 -67
- package/dist/artifacts/DirectoryArtifactReader.js +13 -8
- package/dist/artifacts/MachOSliceArtifactReader.js +1 -5
- package/dist/artifacts/NativeDmgArtifactReader.js +11 -11
- package/dist/artifacts/NibArchive.js +269 -0
- package/dist/artifacts/SafeOutputTree.js +21 -31
- package/dist/browser/BrowserProcessStartup.js +1 -2
- package/dist/browser/CdpAuthorizedMainFrame.js +16 -0
- package/dist/browser/CdpBrowserProvider.js +3 -13
- package/dist/browser/CdpCanonicalJsonDigest.js +9 -0
- package/dist/browser/CdpCaptureDocuments.js +28 -76
- package/dist/browser/CdpCaptureEventBodyShapes.js +13 -33
- package/dist/browser/CdpCaptureEventHandlers.js +22 -87
- package/dist/browser/CdpCaptureEvents.js +2 -8
- package/dist/browser/CdpCaptureStorage.js +9 -20
- package/dist/browser/CdpCaptureStorageFingerprints.js +85 -95
- package/dist/browser/CdpCaptureValues.js +21 -21
- package/dist/browser/CdpConnection.js +10 -25
- package/dist/browser/CdpElectronInspection.js +29 -51
- package/dist/browser/CdpElectronProvider.js +10 -35
- package/dist/browser/CdpElectronScriptEvents.js +8 -16
- package/dist/browser/CdpElectronScripts.js +6 -35
- package/dist/browser/CdpElectronWorkers.js +6 -10
- package/dist/browser/CdpEndpoint.js +25 -41
- package/dist/browser/CdpObservationSession.js +14 -26
- package/dist/browser/CdpPageCapture.js +34 -48
- package/dist/browser/CdpPageCaptureScripts.js +1 -19
- package/dist/browser/CdpPageCaptureWorkers.js +6 -10
- package/dist/browser/CdpSafeMetadata.js +19 -22
- package/dist/browser/CdpScreenshot.js +3 -5
- package/dist/browser/CdpTargetSession.js +1 -2
- package/dist/browser/CdpWebMcpDiscovery.js +13 -22
- package/dist/browser/ElectronFileScope.js +8 -19
- package/dist/browser/JavaScriptRuntimeScope.js +10 -10
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +31 -64
- package/dist/browser/PlaywrightElectronActiveActions.js +309 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +274 -0
- package/dist/browser/PlaywrightExecutionBoundary.js +16 -5
- package/dist/browser/PlaywrightScenarioActions.js +3 -7
- package/dist/browser/PlaywrightScenarioArtifacts.js +23 -92
- package/dist/browser/PlaywrightScenarioBrowser.js +7 -9
- package/dist/browser/PlaywrightScenarioEvents.js +45 -94
- package/dist/browser/PlaywrightScenarioSession.js +18 -34
- package/dist/browser/PngVisualDiff.js +22 -14
- package/dist/browser/SensitiveTextCapture.js +1 -18
- package/dist/browser/V8InspectorCaptureProjection.js +7 -7
- package/dist/browser/V8InspectorEndpoint.js +12 -14
- package/dist/browser/V8InspectorProvider.js +20 -61
- package/dist/browser/WebSourceMapFetcher.js +56 -176
- package/dist/catalogIdentity.js +12 -60
- package/dist/cli/artifactCommands.js +49 -77
- package/dist/cli/coreAnalysisCommands.js +83 -133
- package/dist/cli/javascriptApplicationAnalysis.js +1 -9
- package/dist/cli/managedCommands.js +6 -271
- package/dist/cli/setupCommands.js +3 -12
- package/dist/cli/utilityCommands.js +7 -41
- package/dist/cli.js +0 -2
- package/dist/cliApplicationCommands.js +44 -114
- package/dist/cliBrowserAdvancedCommands.js +12 -102
- package/dist/cliBrowserCommands.js +19 -124
- package/dist/cliBrowserContext.js +30 -0
- package/dist/cliCommandNames.js +5 -5
- package/dist/cliElectronCommands.js +49 -71
- package/dist/cliEvidenceCommands.js +8 -77
- package/dist/cliJavaScriptRuntimeCommands.js +18 -92
- package/dist/cliJsonInput.js +4 -14
- package/dist/cliObservationOptions.js +11 -92
- package/dist/cliPolicyCommands.js +2 -16
- package/dist/cliProcessCommands.js +3 -3
- package/dist/cliSetup.js +0 -13
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -9
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -232
- package/dist/config/parsers.js +16 -28
- package/dist/config/passiveObservation.js +87 -0
- package/dist/config/permissions.js +0 -7
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/analysisSearchContract.js +2 -5
- package/dist/contracts/applicationToolContracts.js +58 -114
- package/dist/contracts/applicationWorkflowInputContracts.js +29 -114
- package/dist/contracts/artifactComparisonExample.js +58 -60
- package/dist/contracts/artifactToolContracts.js +37 -91
- package/dist/contracts/browserScenarioToolContracts.js +6 -51
- package/dist/contracts/browserToolContracts.js +10 -75
- package/dist/contracts/electronToolContracts.js +27 -98
- package/dist/contracts/enhancedInputs.js +31 -78
- package/dist/contracts/errorSchemas.js +0 -1
- package/dist/contracts/functionComparisonExample.js +10 -24
- package/dist/contracts/functionInstructionContract.js +1 -3
- package/dist/contracts/functionWorkflowToolContracts.js +4 -5
- package/dist/contracts/hopperMemoryContracts.js +3 -3
- package/dist/contracts/investigationExamples.js +14 -11
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +12 -19
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +2 -20
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +45 -12
- package/dist/contracts/managedToolContracts.js +10 -104
- package/dist/contracts/managedWorkflowExamples.js +77 -125
- package/dist/contracts/managedWorkflowToolContracts.js +51 -74
- package/dist/contracts/nativeToolContracts.js +9 -14
- package/dist/contracts/processCaptureExample.js +2 -69
- package/dist/contracts/promptContracts.js +49 -67
- package/dist/contracts/providerSelection.js +0 -1
- package/dist/contracts/reconstructionReadinessExample.js +1 -6
- package/dist/contracts/sessionStatusContract.js +1 -17
- package/dist/contracts/sessionToolSchemas.js +52 -0
- package/dist/contracts/toolContractExamples.js +11 -10
- package/dist/contracts/toolContractHelpers.js +19 -0
- package/dist/contracts/toolContracts.js +60 -143
- package/dist/contracts/toolEffects.js +16 -9
- package/dist/contracts/toolOutputSchemaGroups.js +47 -86
- package/dist/contracts/toolOutputSchemaPrimitives.js +72 -62
- package/dist/contracts/toolSchemaMetadata.js +117 -0
- package/dist/contracts/unknownContractExamples.js +0 -2
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +46 -54
- package/dist/domain/analysisErrorProjection.js +28 -37
- package/dist/domain/analysisProfile.js +3 -31
- package/dist/domain/analysisSnapshot.js +3 -12
- package/dist/domain/androidApplication.js +15 -52
- package/dist/domain/appleApplication.js +24 -65
- package/dist/domain/artifactComparison.js +11 -29
- package/dist/domain/artifactGraph.js +14 -44
- package/dist/domain/artifactInspection.js +38 -69
- package/dist/domain/artifactInventoryEvidence.js +27 -21
- package/dist/domain/binaryTarget.js +2 -219
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +35 -60
- package/dist/domain/browserObservation.js +45 -197
- package/dist/domain/browserObservationSchemas.js +5 -23
- package/dist/domain/browserScenario.js +11 -14
- package/dist/domain/browserScenarioCapture.js +11 -12
- package/dist/domain/browserScenarioCaptureValues.js +146 -84
- package/dist/domain/browserScenarioDiff.js +2 -59
- package/dist/domain/browserScenarioDiffEvidence.js +51 -0
- package/dist/domain/browserScenarioDiffValues.js +21 -38
- package/dist/domain/browserScenarioValues.js +80 -109
- package/dist/domain/browserSession.js +4 -7
- package/dist/domain/bundleComparison.js +6 -32
- package/dist/domain/bytecodeProvider.js +53 -54
- package/dist/domain/callPath.js +50 -169
- package/dist/domain/callPathSchemas.js +79 -0
- package/dist/domain/changedBehavior.js +34 -60
- package/dist/domain/completionLedgerGeneration.js +8 -14
- package/dist/domain/conformancePackage.js +126 -97
- package/dist/domain/conformanceReplay.js +39 -11
- package/dist/domain/conformanceTrustGate.js +174 -30
- package/dist/domain/customProtocolCapture.js +4 -4
- package/dist/domain/electronActiveObservation.js +244 -0
- package/dist/domain/electronObservation.js +21 -83
- package/dist/domain/electronStaticAnalysisBrowser.js +36 -46
- package/dist/domain/electronStaticAnalysisIpc.js +38 -14
- package/dist/domain/electronStaticAnalysisNative.js +1 -8
- package/dist/domain/electronStaticAnalysisValues.js +14 -18
- package/dist/domain/errors.js +33 -54
- package/dist/domain/eventProcessTree.js +101 -90
- package/dist/domain/evidence.js +2 -10
- package/dist/domain/evidenceBundle.js +3 -5
- package/dist/domain/evidenceCompletionLedger.js +6 -8
- package/dist/domain/functionComparison.js +4 -14
- package/dist/domain/functionComparisonNormalization.js +8 -8
- package/dist/domain/functionComparisonResults.js +25 -15
- package/dist/domain/functionComparisonSchemas.js +49 -33
- package/dist/domain/functionDossierEvidence.js +31 -151
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +17 -141
- package/dist/domain/inputIssueProjection.js +4 -1
- package/dist/domain/interfaceBuilderGraph.js +654 -0
- package/dist/domain/javascriptApplicationAnalysis.js +8 -112
- package/dist/domain/javascriptApplicationChangeGraph.js +22 -82
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +59 -47
- package/dist/domain/javascriptApplicationGraph.js +3 -13
- package/dist/domain/javascriptApplicationGraphSchemas.js +12 -34
- package/dist/domain/javascriptApplicationVersionComparison.js +26 -30
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +123 -68
- package/dist/domain/javascriptApplicationVersionItems.js +120 -53
- package/dist/domain/javascriptApplicationVersionKeys.js +24 -11
- package/dist/domain/javascriptAstFingerprint.js +25 -58
- package/dist/domain/javascriptAstValues.js +9 -0
- package/dist/domain/javascriptExportInstrumentation.js +2 -4
- package/dist/domain/javascriptExportShapeComparison.js +6 -7
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +70 -77
- package/dist/domain/javascriptExportShapeSelection.js +17 -19
- package/dist/domain/javascriptFeatureSeed.js +20 -12
- package/dist/domain/javascriptFeatureTrace.js +13 -67
- package/dist/domain/javascriptFeatureTraceSchemas.js +24 -52
- package/dist/domain/javascriptFeatureTraversal.js +1 -44
- package/dist/domain/javascriptNativeHandoff.js +1 -1
- package/dist/domain/javascriptReplay.js +100 -101
- package/dist/domain/javascriptRuntimeLoadState.js +3 -8
- package/dist/domain/javascriptRuntimeObservation.js +43 -103
- package/dist/domain/javascriptRuntimeReconciliation.js +1 -3
- package/dist/domain/javascriptRuntimeReconciliationActive.js +80 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +21 -33
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +75 -61
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +21 -46
- package/dist/domain/javascriptRuntimeReconciliationResult.js +25 -19
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +8 -12
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +34 -49
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -3
- package/dist/domain/javascriptSemanticAnalysis.js +12 -45
- package/dist/domain/javascriptSemanticAsyncEffects.js +1 -9
- package/dist/domain/javascriptSemanticCallResolution.js +6 -16
- package/dist/domain/javascriptSemanticCalls.js +5 -32
- package/dist/domain/javascriptSemanticChildProcesses.js +1 -11
- package/dist/domain/javascriptSemanticCoverage.js +11 -0
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +1 -8
- package/dist/domain/javascriptSemanticDataEffects.js +1 -11
- package/dist/domain/javascriptSemanticFingerprints.js +3 -5
- package/dist/domain/javascriptSemanticGraphSchemas.js +25 -51
- package/dist/domain/javascriptSemanticGraphSerialization.js +2 -13
- package/dist/domain/javascriptSemanticIr.js +1 -29
- package/dist/domain/javascriptSemanticObjects.js +1 -5
- package/dist/domain/javascriptSemanticPrimitives.js +2 -9
- package/dist/domain/javascriptSemanticProjection.js +0 -18
- package/dist/domain/javascriptSemanticPromises.js +9 -16
- package/dist/domain/javascriptSemanticProvenance.js +16 -19
- package/dist/domain/javascriptSemanticQuery.js +17 -139
- package/dist/domain/javascriptSemanticQueryAssessment.js +9 -37
- package/dist/domain/javascriptSemanticQueryIdentity.js +2 -23
- package/dist/domain/javascriptSemanticQuerySchemas.js +14 -107
- package/dist/domain/javascriptSemanticResources.js +1 -6
- package/dist/domain/javascriptSemanticReturns.js +10 -27
- package/dist/domain/javascriptSemanticValueTypes.js +1 -0
- package/dist/domain/javascriptSemanticValues.js +44 -62
- package/dist/domain/javascriptStaticAnalysis.js +21 -43
- package/dist/domain/javascriptStaticAnalysisBundler.js +34 -93
- package/dist/domain/javascriptStaticAnalysisCalls.js +17 -16
- package/dist/domain/javascriptStaticAnalysisFindings.js +3 -19
- package/dist/domain/javascriptStaticAnalysisHelpers.js +47 -88
- package/dist/domain/javascriptStaticAnalysisState.js +1 -5
- package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
- package/dist/domain/jsonShape.js +7 -33
- package/dist/domain/localPath.js +7 -0
- package/dist/domain/managedApplicationGraph.js +9 -41
- package/dist/domain/managedApplicationGraphCoverage.js +24 -156
- package/dist/domain/managedApplicationGraphNodes.js +10 -13
- package/dist/domain/managedArtifact.js +14 -27
- package/dist/domain/managedMemberComparison.js +90 -92
- package/dist/domain/managedMemberComparisonCoverage.js +11 -33
- package/dist/domain/managedMemberComparisonItems.js +221 -0
- package/dist/domain/managedMemberComparisonMatch.js +8 -208
- package/dist/domain/managedNativeVerification.js +3 -6
- package/dist/domain/managedNativeVerificationMatch.js +55 -59
- package/dist/domain/managedNativeVerificationSchemas.js +83 -47
- package/dist/domain/managedReconstruction.js +19 -23
- package/dist/domain/managedRuntimeCorrelation.js +6 -9
- package/dist/domain/nativeApiBoundary.js +17 -14
- package/dist/domain/nativeInspection.js +0 -2
- package/dist/domain/nativeInvestigationGraph.js +351 -0
- package/dist/domain/nativeValueFlow.js +61 -0
- package/dist/domain/nodeRuntimeCharacterization.js +15 -18
- package/dist/domain/objcSwiftMetadata.js +254 -0
- package/dist/domain/peInspection.js +1 -1
- package/dist/domain/permissionPolicy.js +13 -0
- package/dist/domain/processCapture.js +76 -113
- package/dist/domain/processCaptureExample.js +68 -0
- package/dist/domain/processCaptureParsing.js +21 -0
- package/dist/domain/processCaptureReactiveSchema.js +68 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +8 -10
- package/dist/domain/processComparison.js +12 -16
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +32 -46
- package/dist/domain/processReactiveRuntime.js +4 -8
- package/dist/domain/processReactiveScenario.js +28 -94
- package/dist/domain/processReactiveScenarioPreflight.js +5 -30
- package/dist/domain/processReactiveTransition.js +42 -21
- package/dist/domain/processScenario.js +62 -93
- package/dist/domain/processTraceComparison.js +0 -7
- package/dist/domain/processTraceEvaluation.js +14 -4
- package/dist/domain/processTraceSpecification.js +11 -17
- package/dist/domain/protocolCapture.js +11 -9
- package/dist/domain/reconstructionCoverage.js +62 -129
- package/dist/domain/reconstructionCoverageEvaluation.js +17 -17
- package/dist/domain/reconstructionObligationLedgerSchemas.js +45 -72
- package/dist/domain/reconstructionReadiness.js +1 -2
- package/dist/domain/reconstructionReadinessSchemas.js +66 -40
- package/dist/domain/reconstructionUnknowns.js +3 -3
- package/dist/domain/reconstructionVerification.js +13 -47
- package/dist/domain/reconstructionVerificationSchemas.js +50 -38
- package/dist/domain/referenceSourceGraph.js +53 -61
- package/dist/domain/referenceSourceImportParsing.js +3 -7
- package/dist/domain/replayMachine.js +19 -31
- package/dist/domain/replayMachineRun.js +15 -63
- package/dist/domain/replayMachineRuntime.js +46 -44
- package/dist/domain/replayMachineValues.js +84 -0
- package/dist/domain/residualUnknown.js +25 -30
- package/dist/domain/runtimeCharacterization.js +15 -16
- package/dist/domain/runtimeIdentification.js +48 -47
- package/dist/domain/sourceToBundleComparison.js +11 -87
- package/dist/domain/sourceToBundleComparisonSchemas.js +25 -50
- package/dist/domain/sourceToBundleSignals.js +11 -16
- package/dist/domain/staticRuntimeCorrelation.js +44 -54
- package/dist/domain/symbolAnalysis.js +10 -19
- package/dist/domain/unicodeCodePointOrder.js +12 -0
- package/dist/domain/webBundleAnalysis.js +70 -99
- package/dist/domain/webBundleAnalyzer.js +2 -4
- package/dist/domain/webBundleAnalyzerAst.js +0 -13
- package/dist/domain/webBundleAnalyzerInspection.js +26 -52
- package/dist/domain/webBundleAnalyzerResult.js +7 -24
- package/dist/domain/webCaptureDiff.js +48 -85
- package/dist/domain/webCaptureDiffSchemas.js +86 -0
- package/dist/domain/webContentArtifact.js +1 -10
- package/dist/domain/webMcpDiscovery.js +3 -14
- package/dist/domain/webScreenshot.js +58 -34
- package/dist/domain/zipPackageFormat.js +7 -0
- package/dist/dotnet/ManagedArtifactInspector.js +17 -50
- package/dist/dotnet/ManagedMemberInspector.js +27 -58
- package/dist/dotnet/ManagedMemberInspectorCore.js +14 -51
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +2 -2
- package/dist/dotnet/ManagedMemberRows.js +16 -16
- package/dist/dotnet/ManagedMetadataHeaps.js +26 -8
- package/dist/dotnet/ManagedMetadataInventory.js +21 -30
- package/dist/dotnet/ManagedMetadataInventoryRows.js +57 -63
- package/dist/dotnet/ManagedMetadataLayout.js +3 -5
- package/dist/dotnet/ManagedMethodBodyReader.js +5 -30
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +19 -49
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +13 -42
- package/dist/dotnet/ManagedPeReader.js +2 -2
- package/dist/dotnet/ManagedStaticProvider.js +13 -71
- package/dist/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraAnalysisProfile.js +3 -8
- package/dist/ghidra/GhidraClient.js +5 -13
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraClientWire.js +9 -5
- package/dist/ghidra/GhidraDefaults.js +0 -18
- package/dist/ghidra/GhidraDiagnostics.js +0 -2
- package/dist/ghidra/GhidraDoctor.js +16 -12
- package/dist/ghidra/GhidraFunctionValues.js +67 -108
- package/dist/ghidra/GhidraInstallation.js +98 -42
- package/dist/ghidra/GhidraInventoryValues.js +18 -77
- package/dist/ghidra/GhidraLauncher.js +0 -8
- package/dist/ghidra/GhidraProvider.js +32 -31
- package/dist/ghidra/GhidraProviderCapabilities.js +11 -48
- package/dist/ghidra/GhidraRequestQueue.js +6 -30
- package/dist/ghidra/GhidraResponseBuffer.js +1 -7
- package/dist/ghidra/GhidraSessionValues.js +0 -2
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/GhidraTransport.js +4 -7
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +115 -37
- package/dist/hopper/HopperAnalysisProfile.js +3 -5
- package/dist/hopper/HopperCleanup.js +11 -9
- package/dist/hopper/HopperClient.js +5 -8
- package/dist/hopper/HopperProcessDiagnostic.js +2 -2
- package/dist/hopper/HopperProvider.js +0 -30
- package/dist/hopper/HopperRequestQueue.js +21 -40
- package/dist/hopper/HopperResponseStream.js +1 -9
- package/dist/hopper/HopperSessionValues.js +3 -2
- package/dist/hopper/HopperTargetLease.js +119 -0
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +24 -31
- package/dist/hopper/LinuxPrivateDisplayProbe.js +21 -26
- package/dist/hopper/protocol.js +6 -4
- package/dist/main/reload.js +1 -9
- package/dist/main/shutdown.js +1 -1
- package/dist/main/state.js +0 -23
- package/dist/main/transport.js +27 -39
- package/dist/main.js +17 -15
- package/dist/mcpDoctor.js +27 -69
- package/dist/native/CommandRunner.js +18 -25
- package/dist/native/NativeMacOSProvider.js +13 -38
- package/dist/native/NativeMachoInspection.js +1 -1
- package/dist/process/BoundedFileBytes.js +17 -0
- package/dist/process/ExecFileOutput.js +11 -0
- package/dist/process/PendingOperations.js +8 -6
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +67 -130
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +87 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/ProviderProcess.js +7 -28
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +8 -24
- package/dist/reference/ReferenceSourceReaderEntries.js +11 -39
- package/dist/reference/ReferenceSourceReaderFile.js +13 -31
- package/dist/reference/ReferenceSourceReaderPaths.js +3 -18
- package/dist/reference/ReferenceSourceReaderValidate.js +3 -6
- package/dist/replay/JavaScriptReplayWorker.js +95 -13
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +42 -43
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +0 -19
- package/dist/replay/LinuxRuntimeClosure.js +1 -3
- package/dist/replay/ReplayOutcome.js +27 -18
- package/dist/replay/ReplayProcessLifecycle.js +32 -7
- package/dist/replay/ReplaySeccompFile.js +29 -0
- package/dist/replay/ReplayWorkerProtocol.js +33 -30
- package/dist/replay/SystemJavaScriptReplayHost.js +45 -74
- package/dist/server/ProcessCaptureElicitation.js +4 -8
- package/dist/server/createServer.js +145 -119
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/promptCompletion.js +37 -61
- package/dist/server/recordDerivedEvidence.js +1 -1
- package/dist/server/registerApplicationTools/characterization.js +10 -21
- package/dist/server/registerApplicationTools/compareExportShapes.js +6 -16
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +6 -15
- package/dist/server/registerApplicationTools/compareVersions.js +6 -16
- package/dist/server/registerApplicationTools/controlledReplay.js +8 -15
- package/dist/server/registerApplicationTools/coverage.js +7 -78
- package/dist/server/registerApplicationTools/helpers.js +1 -13
- package/dist/server/registerApplicationTools/obligationLedger.js +4 -8
- package/dist/server/registerApplicationTools/traceFeature.js +6 -15
- package/dist/server/registerApplicationTools/traceSemantics.js +5 -13
- package/dist/server/registerApplicationTools.js +0 -2
- package/dist/server/registerArtifactComparisonTool.js +27 -35
- package/dist/server/registerBrowserScenarioTool.js +3 -8
- package/dist/server/registerBrowserTools.js +36 -81
- package/dist/server/registerBundleComparisonTool.js +10 -16
- package/dist/server/registerCloseLifecycleTool.js +5 -27
- package/dist/server/registerElectronTools.js +29 -65
- package/dist/server/registerEnhancedTools.js +118 -127
- package/dist/server/registerEvidenceTools.js +19 -30
- package/dist/server/registerFunctionComparisonTool.js +35 -34
- package/dist/server/registerInvestigationTools/helpers.js +3 -32
- package/dist/server/registerInvestigationTools.js +36 -148
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +15 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +16 -23
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/evidence.js +19 -35
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -14
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +4 -14
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +11 -20
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +10 -21
- package/dist/server/registerOfficialTools.js +8 -51
- package/dist/server/registerProcessComparisonTool.js +43 -38
- package/dist/server/registerPrompts.js +19 -17
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +36 -153
- package/dist/server/registerSessionStatusTool.js +18 -96
- package/dist/server/registerSessionTools.js +34 -91
- package/dist/server/sessionAvailabilityPolicy.js +2 -3
- package/dist/server/sessionEvidence.js +9 -15
- package/dist/server/sessionToolPolicies.js +1 -13
- package/dist/server/toolRegistrationOptions.js +4 -192
- package/dist/server/toolResult.js +15 -67
- package/dist/serverIdentity.js +0 -20
- package/install.sh +1 -1
- package/package.json +27 -15
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +469 -0
- package/scripts/hopper-demo-x11.py +13 -32
- package/scripts/rea.mjs +1 -11
- package/skills/reverse-engineer-anything/SKILL.md +46 -11
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +6 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +13 -13
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +12 -8
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +0 -180
- package/dist/application/BoundedJsonFiles.js +0 -86
- package/dist/application/CrossVersionInventory.js +0 -128
- package/dist/application/CrossVersionInvestigation.js +0 -301
- package/dist/application/CrossVersionInvestigationCollections.js +0 -23
- package/dist/application/CrossVersionInvestigationEvidence.js +0 -64
- package/dist/application/CrossVersionInvestigationReplay.js +0 -170
- package/dist/application/DeferredFileAuthorization.js +0 -61
- package/dist/application/DoctorProjection.js +0 -43
- package/dist/application/EnhancedToolPagination.js +0 -22
- package/dist/application/EvidenceReferenceResolver.js +0 -26
- package/dist/application/InvestigationWorkspaceStore.js +0 -204
- package/dist/application/ProcessPairedExperiment.js +0 -72
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +0 -31
- package/dist/application/ReconstructionReadinessService.js +0 -48
- package/dist/cliInvestigationCommands.js +0 -173
- package/dist/domain/boundedCartesianProjection.js +0 -15
- package/dist/domain/investigationWorkspace.js +0 -346
- package/dist/domain/jsonLimits.js +0 -26
- package/dist/domain/knownPageCoverage.js +0 -21
- package/dist/domain/processPairedExperiment.js +0 -128
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/LazyToolCatalog.js +0 -134
- package/dist/server/hydrateServerTools.js +0 -191
- package/dist/server/javascriptApplicationResult.js +0 -106
- package/dist/server/permissionFailure.js +0 -12
- package/dist/server/registerApplicationTools/readiness.js +0 -55
- package/dist/server/registerEvidenceResources.js +0 -315
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -65
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -32
- package/dist/server/registerReconstructionReadinessResource.js +0 -32
- package/dist/server/toolInputValidation.js +0 -77
- package/scripts/package-runner-bootstrap.mjs +0 -72
package/bridge/hopper_bridge.py
CHANGED
|
@@ -9,19 +9,15 @@ import json
|
|
|
9
9
|
import hmac
|
|
10
10
|
import os
|
|
11
11
|
import re
|
|
12
|
-
import sre_parse
|
|
13
12
|
import socket
|
|
14
13
|
from typing import Any, Optional, Protocol, Sequence
|
|
15
14
|
|
|
16
|
-
MAX_LINE_BYTES = 10 * 1024 * 1024
|
|
17
|
-
MAX_READ_BYTES = 4096
|
|
18
15
|
BAD_ADDRESSES = (-1, 0xFFFFFFFFFFFFFFFF, None)
|
|
19
16
|
_selected_document = None
|
|
17
|
+
_rea_session_document = None
|
|
20
18
|
_search_inventory_cache = {}
|
|
21
19
|
_pseudocode_cache = {}
|
|
22
20
|
_hopper_api = None
|
|
23
|
-
MAX_SEARCH_PATTERN_LENGTH = 256
|
|
24
|
-
MAX_SEARCH_VALUE_LENGTH = 4096
|
|
25
21
|
|
|
26
22
|
|
|
27
23
|
class HopperDocument(Protocol):
|
|
@@ -69,8 +65,9 @@ class HopperApiFacade:
|
|
|
69
65
|
|
|
70
66
|
def _configure_hopper_api(document_provider):
|
|
71
67
|
"""Inject Hopper's document provider or a standalone test facade."""
|
|
72
|
-
global _hopper_api
|
|
68
|
+
global _hopper_api, _rea_session_document
|
|
73
69
|
_hopper_api = HopperApiFacade(document_provider)
|
|
70
|
+
_rea_session_document = None
|
|
74
71
|
|
|
75
72
|
|
|
76
73
|
def _api():
|
|
@@ -88,19 +85,43 @@ def _api():
|
|
|
88
85
|
|
|
89
86
|
|
|
90
87
|
def _session_document():
|
|
91
|
-
"""
|
|
88
|
+
"""Return the exact document bound to this authenticated REA session."""
|
|
89
|
+
global _rea_session_document
|
|
90
|
+
documents = _api().documents()
|
|
91
|
+
if _rea_session_document is not None:
|
|
92
|
+
return (
|
|
93
|
+
_rea_session_document
|
|
94
|
+
if any(document is _rea_session_document for document in documents)
|
|
95
|
+
else None
|
|
96
|
+
)
|
|
97
|
+
return _bind_session_document(documents)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _bind_session_document(documents=None):
|
|
101
|
+
"""Bind this bridge to Hopper's current document for its target."""
|
|
102
|
+
global _rea_session_document
|
|
103
|
+
api = _api()
|
|
104
|
+
if documents is None:
|
|
105
|
+
documents = api.documents()
|
|
92
106
|
target = os.path.realpath(REA_TARGET_PATH)
|
|
93
|
-
for document in _api().documents():
|
|
94
|
-
paths = (document.getExecutableFilePath(), document.getDatabaseFilePath())
|
|
95
|
-
for path in paths:
|
|
96
|
-
if path and os.path.realpath(path) == target:
|
|
97
|
-
return document
|
|
98
|
-
return None
|
|
99
107
|
|
|
108
|
+
def matches_target(document):
|
|
109
|
+
paths = (document.getExecutableFilePath(), document.getDatabaseFilePath())
|
|
110
|
+
return any(path and os.path.realpath(path) == target for path in paths)
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
current = api.current_document()
|
|
113
|
+
if current is not None and matches_target(current):
|
|
114
|
+
_rea_session_document = current
|
|
115
|
+
return current
|
|
116
|
+
matching = [document for document in documents if matches_target(document)]
|
|
117
|
+
if len(matching) == 1:
|
|
118
|
+
_rea_session_document = matching[0]
|
|
119
|
+
return matching[0]
|
|
120
|
+
if len(matching) > 1:
|
|
121
|
+
raise CapabilityUnavailableError(
|
|
122
|
+
"The REA session document is ambiguous; Hopper did not identify the launched document"
|
|
123
|
+
)
|
|
124
|
+
return None
|
|
104
125
|
|
|
105
126
|
|
|
106
127
|
class CapabilityUnavailableError(Exception):
|
|
@@ -149,14 +170,22 @@ def _document(name=None):
|
|
|
149
170
|
api = _api()
|
|
150
171
|
documents = api.documents()
|
|
151
172
|
if name is not None:
|
|
152
|
-
for candidate in documents
|
|
153
|
-
|
|
154
|
-
|
|
173
|
+
matches = [candidate for candidate in documents if candidate.getDocumentName() == name]
|
|
174
|
+
if len(matches) == 1:
|
|
175
|
+
return matches[0]
|
|
176
|
+
if len(matches) > 1:
|
|
177
|
+
current = api.current_document()
|
|
178
|
+
if current is not None and current.getDocumentName() == name:
|
|
179
|
+
return current
|
|
180
|
+
raise ValueError("Hopper document name is ambiguous")
|
|
155
181
|
raise ValueError("Unknown Hopper document")
|
|
156
182
|
if _selected_document is not None:
|
|
157
183
|
for candidate in documents:
|
|
158
184
|
if candidate.getDocumentName() == _selected_document:
|
|
159
185
|
return candidate
|
|
186
|
+
session_document = _session_document()
|
|
187
|
+
if session_document is not None:
|
|
188
|
+
return session_document
|
|
160
189
|
current = api.current_document()
|
|
161
190
|
if current is None:
|
|
162
191
|
raise ValueError("No Hopper document is loaded")
|
|
@@ -225,18 +254,14 @@ def _containing_procedure(document, address):
|
|
|
225
254
|
return (procedure, None) if procedure is not None else (None, "not_in_procedure")
|
|
226
255
|
|
|
227
256
|
|
|
228
|
-
def _instruction_addresses(procedure
|
|
257
|
+
def _instruction_addresses(procedure):
|
|
229
258
|
result = []
|
|
230
259
|
seen = set()
|
|
231
260
|
segment = procedure.getSegment()
|
|
232
|
-
truncated = False
|
|
233
261
|
for block in procedure.basicBlockIterator():
|
|
234
262
|
address = block.getStartingAddress()
|
|
235
263
|
end = block.getEndingAddress()
|
|
236
264
|
while address < end and address not in seen:
|
|
237
|
-
if len(result) >= limit:
|
|
238
|
-
truncated = True
|
|
239
|
-
return result, truncated
|
|
240
265
|
seen.add(address)
|
|
241
266
|
instruction = segment.getInstructionAtAddress(address)
|
|
242
267
|
if instruction is None:
|
|
@@ -246,24 +271,15 @@ def _instruction_addresses(procedure, limit):
|
|
|
246
271
|
if length <= 0:
|
|
247
272
|
break
|
|
248
273
|
address += length
|
|
249
|
-
return result
|
|
274
|
+
return result
|
|
250
275
|
|
|
251
276
|
|
|
252
277
|
def _procedure_references(document, params):
|
|
253
278
|
procedure = _procedure(document, params.get("procedure"))
|
|
254
279
|
direction = params.get("direction", "outgoing")
|
|
255
|
-
offset = params.get("offset", 0)
|
|
256
|
-
limit = params.get("limit", 100)
|
|
257
|
-
max_instructions = params.get("max_instructions", 500)
|
|
258
280
|
if direction not in ("incoming", "outgoing"):
|
|
259
281
|
raise ValueError("direction must be incoming or outgoing")
|
|
260
|
-
|
|
261
|
-
raise ValueError("offset must be a non-negative integer")
|
|
262
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or limit < 1 or limit > 500:
|
|
263
|
-
raise ValueError("limit must be an integer between 1 and 500")
|
|
264
|
-
if not isinstance(max_instructions, int) or isinstance(max_instructions, bool) or max_instructions < 1 or max_instructions > 5000:
|
|
265
|
-
raise ValueError("max_instructions must be an integer between 1 and 5000")
|
|
266
|
-
addresses, scan_truncated = _instruction_addresses(procedure, max_instructions)
|
|
282
|
+
addresses = _instruction_addresses(procedure)
|
|
267
283
|
edges = set()
|
|
268
284
|
for address in addresses:
|
|
269
285
|
segment = _segment(document, address)
|
|
@@ -272,8 +288,7 @@ def _procedure_references(document, params):
|
|
|
272
288
|
edges.add((address, reference) if direction == "outgoing" else (reference, address))
|
|
273
289
|
ordered = sorted(edges)
|
|
274
290
|
items = []
|
|
275
|
-
|
|
276
|
-
for source, target in selected:
|
|
291
|
+
for source, target in ordered:
|
|
277
292
|
source_procedure, _ = _containing_procedure(document, source)
|
|
278
293
|
target_procedure, _ = _containing_procedure(document, target)
|
|
279
294
|
items.append({
|
|
@@ -283,13 +298,9 @@ def _procedure_references(document, params):
|
|
|
283
298
|
"target_procedure": _procedure_identity(target_procedure) if target_procedure is not None else None,
|
|
284
299
|
"kind": _unavailable("Hopper's public Python API does not classify reference kinds"),
|
|
285
300
|
})
|
|
286
|
-
next_offset = offset + len(selected)
|
|
287
|
-
has_more = next_offset < len(ordered)
|
|
288
|
-
truncated = scan_truncated or has_more
|
|
289
301
|
return {
|
|
290
302
|
"procedure": _procedure_identity(procedure), "direction": direction,
|
|
291
|
-
"references":
|
|
292
|
-
"instructions_scanned": len(addresses), "instruction_scan_truncated": scan_truncated,
|
|
303
|
+
"references": items,
|
|
293
304
|
}
|
|
294
305
|
|
|
295
306
|
|
|
@@ -352,230 +363,39 @@ def _search_inventory(document, kind):
|
|
|
352
363
|
return inventory
|
|
353
364
|
|
|
354
365
|
|
|
355
|
-
def
|
|
356
|
-
"""Apply one path-count operation without crossing the static work budget."""
|
|
357
|
-
if operation == "add":
|
|
358
|
-
exceeded = left > MAX_REGEX_BACKTRACKING_PATHS - right
|
|
359
|
-
result = left + right
|
|
360
|
-
else:
|
|
361
|
-
exceeded = right != 0 and left > MAX_REGEX_BACKTRACKING_PATHS // right
|
|
362
|
-
result = left * right
|
|
363
|
-
if exceeded or result > MAX_REGEX_BACKTRACKING_PATHS:
|
|
364
|
-
raise ValueError(
|
|
365
|
-
"Regex exceeds the %d-path backtracking budget"
|
|
366
|
-
% MAX_REGEX_BACKTRACKING_PATHS
|
|
367
|
-
)
|
|
368
|
-
return result
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
def _repeat_regex_paths(child_paths, minimum, maximum):
|
|
372
|
-
"""Count every bounded repetition path, including alternative child paths."""
|
|
373
|
-
paths = 0
|
|
374
|
-
repeated_paths = 1
|
|
375
|
-
for count in range(maximum + 1):
|
|
376
|
-
if count >= minimum:
|
|
377
|
-
paths = _checked_regex_paths(paths, repeated_paths, "add")
|
|
378
|
-
if count < maximum:
|
|
379
|
-
repeated_paths = _checked_regex_paths(
|
|
380
|
-
repeated_paths, child_paths, "multiply"
|
|
381
|
-
)
|
|
382
|
-
return paths
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
def _validate_regex_class(items):
|
|
386
|
-
"""Accept only constant-time character-class operations."""
|
|
387
|
-
allowed = {
|
|
388
|
-
sre_parse.CATEGORY,
|
|
389
|
-
sre_parse.LITERAL,
|
|
390
|
-
sre_parse.NEGATE,
|
|
391
|
-
sre_parse.RANGE,
|
|
392
|
-
}
|
|
393
|
-
if any(operation not in allowed for operation, _ in items):
|
|
394
|
-
raise ValueError("Regex operation is not supported by the bounded matcher")
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
def _validate_regex_node(node, inside_repeat=False):
|
|
398
|
-
"""Return capped path and step bounds for Python regex evaluation."""
|
|
399
|
-
leaf_operations = {
|
|
400
|
-
sre_parse.ANY,
|
|
401
|
-
sre_parse.AT,
|
|
402
|
-
sre_parse.CATEGORY,
|
|
403
|
-
sre_parse.LITERAL,
|
|
404
|
-
sre_parse.NOT_LITERAL,
|
|
405
|
-
}
|
|
406
|
-
forbidden = {
|
|
407
|
-
sre_parse.ASSERT,
|
|
408
|
-
sre_parse.ASSERT_NOT,
|
|
409
|
-
sre_parse.GROUPREF,
|
|
410
|
-
sre_parse.GROUPREF_EXISTS,
|
|
411
|
-
}
|
|
412
|
-
for name in ("GROUPREF_IGNORE", "GROUPREF_LOC_IGNORE", "GROUPREF_UNI_IGNORE"):
|
|
413
|
-
operation = getattr(sre_parse, name, None)
|
|
414
|
-
if operation is not None:
|
|
415
|
-
forbidden.add(operation)
|
|
416
|
-
repeat_tokens = {sre_parse.MAX_REPEAT, sre_parse.MIN_REPEAT}
|
|
417
|
-
possessive = getattr(sre_parse, "POSSESSIVE_REPEAT", None)
|
|
418
|
-
if possessive is not None:
|
|
419
|
-
repeat_tokens.add(possessive)
|
|
420
|
-
atomic = getattr(sre_parse, "ATOMIC_GROUP", None)
|
|
421
|
-
|
|
422
|
-
paths = 1
|
|
423
|
-
steps = 0
|
|
424
|
-
for operation, argument in node:
|
|
425
|
-
if operation in forbidden:
|
|
426
|
-
raise ValueError("Regex lookarounds and backreferences are not supported")
|
|
427
|
-
if operation in leaf_operations:
|
|
428
|
-
operation_paths = 1
|
|
429
|
-
operation_steps = 1
|
|
430
|
-
elif operation == sre_parse.IN:
|
|
431
|
-
_validate_regex_class(argument)
|
|
432
|
-
operation_paths = 1
|
|
433
|
-
operation_steps = 1
|
|
434
|
-
elif operation in repeat_tokens:
|
|
435
|
-
if inside_repeat:
|
|
436
|
-
raise ValueError("Nested regex repetitions are not supported")
|
|
437
|
-
minimum, maximum, child = argument
|
|
438
|
-
if maximum == sre_parse.MAXREPEAT or maximum > 1000:
|
|
439
|
-
raise ValueError(
|
|
440
|
-
"Unbounded or excessive regex repetitions are not supported"
|
|
441
|
-
)
|
|
442
|
-
child_paths, child_steps = _validate_regex_node(child, True)
|
|
443
|
-
operation_paths = _repeat_regex_paths(
|
|
444
|
-
child_paths, minimum, maximum
|
|
445
|
-
)
|
|
446
|
-
operation_steps = maximum * child_steps
|
|
447
|
-
elif operation == sre_parse.SUBPATTERN:
|
|
448
|
-
operation_paths, operation_steps = _validate_regex_node(
|
|
449
|
-
argument[-1], inside_repeat
|
|
450
|
-
)
|
|
451
|
-
elif operation == sre_parse.BRANCH:
|
|
452
|
-
operation_paths = 0
|
|
453
|
-
operation_steps = 0
|
|
454
|
-
for branch in argument[1]:
|
|
455
|
-
branch_paths, branch_steps = _validate_regex_node(
|
|
456
|
-
branch, inside_repeat
|
|
457
|
-
)
|
|
458
|
-
operation_paths = _checked_regex_paths(
|
|
459
|
-
operation_paths,
|
|
460
|
-
branch_paths,
|
|
461
|
-
"add",
|
|
462
|
-
)
|
|
463
|
-
operation_steps = max(operation_steps, branch_steps)
|
|
464
|
-
elif atomic is not None and operation == atomic:
|
|
465
|
-
operation_paths, operation_steps = _validate_regex_node(
|
|
466
|
-
argument, inside_repeat
|
|
467
|
-
)
|
|
468
|
-
else:
|
|
469
|
-
raise ValueError("Regex operation is not supported by the bounded matcher")
|
|
470
|
-
paths = _checked_regex_paths(paths, operation_paths, "multiply")
|
|
471
|
-
steps += operation_steps
|
|
472
|
-
return paths, steps
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
def _bounded_regex_matcher(expression, backtracking_paths, steps_per_path):
|
|
476
|
-
"""Create a matcher with per-candidate and cumulative work bounds."""
|
|
477
|
-
remaining_work = MAX_REGEX_SEARCH_WORK_UNITS
|
|
478
|
-
work_per_character = backtracking_paths * max(steps_per_path, 1)
|
|
479
|
-
|
|
480
|
-
def matches(value):
|
|
481
|
-
nonlocal remaining_work
|
|
482
|
-
if not isinstance(value, str):
|
|
483
|
-
raise ValueError("Regex candidates must be strings")
|
|
484
|
-
if len(value) > MAX_REGEX_CANDIDATE_LENGTH:
|
|
485
|
-
raise ValueError(
|
|
486
|
-
"Regex candidate exceeds the %d-character safety limit"
|
|
487
|
-
% MAX_REGEX_CANDIDATE_LENGTH
|
|
488
|
-
)
|
|
489
|
-
required_work = work_per_character * max(len(value), 1)
|
|
490
|
-
if required_work > remaining_work:
|
|
491
|
-
raise ValueError(
|
|
492
|
-
"Regex search exceeds the %d-unit work budget"
|
|
493
|
-
% MAX_REGEX_SEARCH_WORK_UNITS
|
|
494
|
-
)
|
|
495
|
-
remaining_work -= required_work
|
|
496
|
-
return expression.search(value) is not None
|
|
497
|
-
|
|
498
|
-
return matches
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
def _search_page(document, kind, params):
|
|
366
|
+
def _search_results(document, kind, params):
|
|
502
367
|
pattern = params.get("pattern")
|
|
503
|
-
if not isinstance(pattern, str) or not pattern
|
|
504
|
-
raise ValueError("pattern must
|
|
368
|
+
if not isinstance(pattern, str) or not pattern:
|
|
369
|
+
raise ValueError("pattern must be a non-empty string")
|
|
505
370
|
mode = params.get("mode", "literal")
|
|
506
371
|
if mode not in ("literal", "regex"):
|
|
507
372
|
raise ValueError("mode must be literal or regex")
|
|
508
373
|
case_sensitive = params.get("case_sensitive", False)
|
|
509
374
|
if not isinstance(case_sensitive, bool):
|
|
510
375
|
raise ValueError("case_sensitive must be a boolean")
|
|
511
|
-
offset = params.get("offset", 0)
|
|
512
|
-
limit = params.get("limit", 100)
|
|
513
|
-
if not isinstance(offset, int) or isinstance(offset, bool) or offset < 0:
|
|
514
|
-
raise ValueError("offset must be a non-negative integer")
|
|
515
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or limit < 1 or limit > 100:
|
|
516
|
-
raise ValueError("limit must be an integer between 1 and 100")
|
|
517
376
|
|
|
518
377
|
if mode == "literal":
|
|
519
378
|
needle = pattern if case_sensitive else pattern.casefold()
|
|
520
379
|
matches = lambda value: needle in (value if case_sensitive else value.casefold())
|
|
521
380
|
else:
|
|
522
381
|
try:
|
|
523
|
-
parsed = sre_parse.parse(pattern)
|
|
524
|
-
backtracking_paths, steps_per_path = _validate_regex_node(parsed)
|
|
525
382
|
expression = re.compile(pattern, 0 if case_sensitive else re.IGNORECASE)
|
|
526
383
|
except (re.error, OverflowError) as error:
|
|
527
384
|
raise ValueError("Invalid regex pattern") from error
|
|
528
|
-
matches =
|
|
529
|
-
expression, backtracking_paths, steps_per_path
|
|
530
|
-
)
|
|
385
|
+
matches = lambda value: expression.search(value) is not None
|
|
531
386
|
|
|
532
387
|
selected = []
|
|
533
|
-
total = 0
|
|
534
|
-
page_end = offset + limit
|
|
535
388
|
for item in _search_inventory(document, kind):
|
|
536
389
|
if not matches(item[1]):
|
|
537
390
|
continue
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
total += 1
|
|
541
|
-
next_offset = offset + len(selected)
|
|
542
|
-
has_more = next_offset < total
|
|
543
|
-
return {
|
|
544
|
-
"items": [
|
|
391
|
+
selected.append(item)
|
|
392
|
+
return [
|
|
545
393
|
{
|
|
546
394
|
"address": address,
|
|
547
|
-
"value": value
|
|
548
|
-
"value_truncated": len(value) > MAX_SEARCH_VALUE_LENGTH,
|
|
395
|
+
"value": value,
|
|
549
396
|
}
|
|
550
397
|
for address, value in selected
|
|
551
|
-
]
|
|
552
|
-
"offset": offset,
|
|
553
|
-
"limit": limit,
|
|
554
|
-
"total": total,
|
|
555
|
-
"next_offset": next_offset if has_more else None,
|
|
556
|
-
"has_more": has_more,
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
def _page(values, offset, limit):
|
|
561
|
-
"""Return one deterministically address-sorted page without crossing an unbounded map."""
|
|
562
|
-
if not isinstance(offset, int) or isinstance(offset, bool) or offset < 0:
|
|
563
|
-
raise ValueError("offset must be a non-negative integer")
|
|
564
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or limit < 1 or limit > 500:
|
|
565
|
-
raise ValueError("limit must be an integer between 1 and 500")
|
|
566
|
-
ordered = sorted(values.items(), key=lambda item: int(item[0], 16))
|
|
567
|
-
selected = ordered[offset:offset + limit]
|
|
568
|
-
total = len(ordered)
|
|
569
|
-
next_offset = offset + len(selected)
|
|
570
|
-
has_more = next_offset < total
|
|
571
|
-
return {
|
|
572
|
-
"items": [{"address": address, "value": value} for address, value in selected],
|
|
573
|
-
"offset": offset,
|
|
574
|
-
"limit": limit,
|
|
575
|
-
"total": total,
|
|
576
|
-
"next_offset": next_offset if has_more else None,
|
|
577
|
-
"has_more": has_more,
|
|
578
|
-
}
|
|
398
|
+
]
|
|
579
399
|
|
|
580
400
|
|
|
581
401
|
def _unavailable(reason):
|
|
@@ -583,36 +403,6 @@ def _unavailable(reason):
|
|
|
583
403
|
return {"available": False, "reason": reason}
|
|
584
404
|
|
|
585
405
|
|
|
586
|
-
def _offset(params, name):
|
|
587
|
-
value = params.get(name, 0)
|
|
588
|
-
if not isinstance(value, int) or isinstance(value, bool) or value < 0:
|
|
589
|
-
raise ValueError("%s must be a non-negative integer" % name)
|
|
590
|
-
return value
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
def _collection_offset(params, name):
|
|
594
|
-
values = params.get("collection_offset", {})
|
|
595
|
-
if not isinstance(values, dict):
|
|
596
|
-
raise ValueError("collection_offset must be an object")
|
|
597
|
-
value = values.get(name, 0)
|
|
598
|
-
if not isinstance(value, int) or isinstance(value, bool) or value < 0:
|
|
599
|
-
raise ValueError("collection_offset.%s must be a non-negative integer" % name)
|
|
600
|
-
return value
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
def _bounded(items, offset, limit, total=None, scan_truncated=False):
|
|
604
|
-
selected = items[offset:offset + limit]
|
|
605
|
-
known_total = len(items) if total is None and not scan_truncated else total
|
|
606
|
-
has_more = offset + len(selected) < len(items)
|
|
607
|
-
return {
|
|
608
|
-
"items": selected,
|
|
609
|
-
"total": known_total,
|
|
610
|
-
"returned": len(selected),
|
|
611
|
-
"truncated": scan_truncated or has_more,
|
|
612
|
-
"next_offset": offset + len(selected) if has_more else None,
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
|
|
616
406
|
def _name_map(document):
|
|
617
407
|
result = {}
|
|
618
408
|
for segment in document.getSegmentsList():
|
|
@@ -639,8 +429,8 @@ def _render_instruction(segment, address):
|
|
|
639
429
|
)
|
|
640
430
|
|
|
641
431
|
|
|
642
|
-
def _assembly(procedure
|
|
643
|
-
"""Render
|
|
432
|
+
def _assembly(procedure):
|
|
433
|
+
"""Render assembly while guarding against malformed instruction cycles."""
|
|
644
434
|
lines = []
|
|
645
435
|
segment = procedure.getSegment()
|
|
646
436
|
seen = set()
|
|
@@ -655,8 +445,6 @@ def _assembly(procedure, limit=None):
|
|
|
655
445
|
line = _render_instruction(segment, address)
|
|
656
446
|
if line is not None:
|
|
657
447
|
lines.append(line)
|
|
658
|
-
if limit is not None and len(lines) >= limit:
|
|
659
|
-
return "\n".join(lines)
|
|
660
448
|
length = instruction.getInstructionLength()
|
|
661
449
|
if length <= 0:
|
|
662
450
|
break
|
|
@@ -665,37 +453,18 @@ def _assembly(procedure, limit=None):
|
|
|
665
453
|
|
|
666
454
|
|
|
667
455
|
def _read_function_instructions(document, params):
|
|
668
|
-
"""Read
|
|
456
|
+
"""Read all raw instructions without invoking decompilation."""
|
|
669
457
|
procedure = _procedure(document, params.get("procedure"))
|
|
670
|
-
|
|
671
|
-
limit = params.get("limit", 64)
|
|
672
|
-
if offset > 100000:
|
|
673
|
-
raise ValueError("offset must not exceed 100000")
|
|
674
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or limit < 1 or limit > 500:
|
|
675
|
-
raise ValueError("limit must be an integer between 1 and 500")
|
|
676
|
-
addresses, scan_truncated = _instruction_addresses(
|
|
677
|
-
procedure, offset + limit + 1
|
|
678
|
-
)
|
|
679
|
-
start = min(offset, len(addresses))
|
|
680
|
-
end = min(len(addresses), start + limit)
|
|
458
|
+
addresses = _instruction_addresses(procedure)
|
|
681
459
|
segment = procedure.getSegment()
|
|
682
460
|
items = []
|
|
683
|
-
for address in addresses
|
|
461
|
+
for address in addresses:
|
|
684
462
|
line = _render_instruction(segment, address)
|
|
685
463
|
if line is not None:
|
|
686
464
|
items.append(line)
|
|
687
|
-
has_more = scan_truncated or end < len(addresses)
|
|
688
465
|
return {
|
|
689
466
|
"procedure": _procedure_identity(procedure),
|
|
690
|
-
"instructions":
|
|
691
|
-
"items": items,
|
|
692
|
-
"total": None if scan_truncated else len(addresses),
|
|
693
|
-
"returned": len(items),
|
|
694
|
-
"truncated": has_more,
|
|
695
|
-
"next_offset": end if has_more else None,
|
|
696
|
-
},
|
|
697
|
-
"instructions_scanned": len(addresses),
|
|
698
|
-
"instruction_scan_truncated": scan_truncated,
|
|
467
|
+
"instructions": items,
|
|
699
468
|
"limitations": [
|
|
700
469
|
"Instruction text and ordering are Hopper-specific representations.",
|
|
701
470
|
"The fast path does not decompile the procedure or scan whole-program names and strings.",
|
|
@@ -704,20 +473,9 @@ def _read_function_instructions(document, params):
|
|
|
704
473
|
|
|
705
474
|
|
|
706
475
|
def _analyze_function(document, params):
|
|
707
|
-
"""Collect
|
|
476
|
+
"""Collect the complete function dossier for agent callers."""
|
|
708
477
|
procedure = _procedure(document, params.get("procedure"))
|
|
709
|
-
|
|
710
|
-
max_chars = params.get("max_pseudocode_chars", 20000)
|
|
711
|
-
max_instructions = params.get("max_instructions", 500)
|
|
712
|
-
pseudocode_offset = _offset(params, "pseudocode_offset")
|
|
713
|
-
assembly_offset = _offset(params, "assembly_offset")
|
|
714
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or limit < 1 or limit > 500:
|
|
715
|
-
raise ValueError("limit must be an integer between 1 and 500")
|
|
716
|
-
if not isinstance(max_chars, int) or isinstance(max_chars, bool) or max_chars < 1 or max_chars > 100000:
|
|
717
|
-
raise ValueError("max_pseudocode_chars must be between 1 and 100000")
|
|
718
|
-
if not isinstance(max_instructions, int) or isinstance(max_instructions, bool) or max_instructions < 1 or max_instructions > 5000:
|
|
719
|
-
raise ValueError("max_instructions must be between 1 and 5000")
|
|
720
|
-
addresses, instruction_scan_truncated = _instruction_addresses(procedure, max_instructions)
|
|
478
|
+
addresses = _instruction_addresses(procedure)
|
|
721
479
|
blocks = []
|
|
722
480
|
all_blocks = list(procedure.basicBlockIterator())
|
|
723
481
|
for block in all_blocks:
|
|
@@ -732,7 +490,7 @@ def _analyze_function(document, params):
|
|
|
732
490
|
"successors": sorted(set(successors), key=lambda value: int(value, 16)),
|
|
733
491
|
})
|
|
734
492
|
pseudo = _pseudocode(document, procedure) or ""
|
|
735
|
-
assembly_lines = _assembly(procedure
|
|
493
|
+
assembly_lines = _assembly(procedure).splitlines()
|
|
736
494
|
callers = sorted((_procedure_identity(item) for item in procedure.getAllCallerProcedures()), key=lambda item: int(item["address"], 16))
|
|
737
495
|
callees = sorted((_procedure_identity(item) for item in procedure.getAllCalleeProcedures()), key=lambda item: int(item["address"], 16))
|
|
738
496
|
comments = []
|
|
@@ -785,28 +543,17 @@ def _analyze_function(document, params):
|
|
|
785
543
|
comments.sort(key=lambda item: (int(item["address"], 16), item["kind"]))
|
|
786
544
|
referenced_strings.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
|
|
787
545
|
referenced_names.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
|
|
788
|
-
pseudo_text = pseudo[pseudocode_offset:pseudocode_offset + max_chars]
|
|
789
|
-
pseudo_next = pseudocode_offset + len(pseudo_text)
|
|
790
|
-
def collection(name, items, scan_limited=False):
|
|
791
|
-
return _bounded(items, _collection_offset(params, name), limit, None, scan_limited)
|
|
792
546
|
return {
|
|
793
547
|
"procedure": {"address": _hex(procedure.getEntryPoint()), "name": _procedure_name(procedure), "classification": None, "signature": procedure.signatureString(), "locals": _procedure_locals(procedure)},
|
|
794
|
-
"pseudocode":
|
|
795
|
-
"assembly":
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
"
|
|
803
|
-
"callers": collection("callers", callers), "callees": collection("callees", callees),
|
|
804
|
-
"incoming_references": collection("incoming_references", incoming, instruction_scan_truncated),
|
|
805
|
-
"outgoing_references": collection("outgoing_references", outgoing, instruction_scan_truncated),
|
|
806
|
-
"referenced_strings": collection("referenced_strings", referenced_strings, instruction_scan_truncated),
|
|
807
|
-
"referenced_names": collection("referenced_names", referenced_names, instruction_scan_truncated),
|
|
808
|
-
"basic_blocks": collection("basic_blocks", blocks),
|
|
809
|
-
"instruction_scan": {"scanned": len(addresses), "truncated": instruction_scan_truncated},
|
|
548
|
+
"pseudocode": pseudo,
|
|
549
|
+
"assembly": assembly_lines,
|
|
550
|
+
"comments": comments,
|
|
551
|
+
"callers": callers, "callees": callees,
|
|
552
|
+
"incoming_references": incoming,
|
|
553
|
+
"outgoing_references": outgoing,
|
|
554
|
+
"referenced_strings": referenced_strings,
|
|
555
|
+
"referenced_names": referenced_names,
|
|
556
|
+
"basic_blocks": blocks,
|
|
810
557
|
"limitations": [
|
|
811
558
|
"Hopper's public Python API does not classify reference kinds.",
|
|
812
559
|
"Hopper's public Python API does not expose equivalent external or thunk classification in this dossier.",
|
|
@@ -825,6 +572,13 @@ def _dispatch(method, params):
|
|
|
825
572
|
document = _session_document()
|
|
826
573
|
if document is None:
|
|
827
574
|
return {"shutdown": True, "analysis_stopped": True, "document_closed": True}
|
|
575
|
+
if method == "shutdown" and not REA_OWNS_PROCESS_LIFETIME:
|
|
576
|
+
return {
|
|
577
|
+
"shutdown": True,
|
|
578
|
+
"analysis_stopped": not document.backgroundProcessActive(),
|
|
579
|
+
"document_closed": False,
|
|
580
|
+
"document_retained": True,
|
|
581
|
+
}
|
|
828
582
|
if document.backgroundProcessActive():
|
|
829
583
|
document.requestBackgroundProcessStop()
|
|
830
584
|
if method == "shutdown" and REA_OWNS_PROCESS_LIFETIME:
|
|
@@ -865,8 +619,8 @@ def _dispatch(method, params):
|
|
|
865
619
|
length = params.get("length", 256)
|
|
866
620
|
if isinstance(length, bool) or not isinstance(length, int):
|
|
867
621
|
raise ValueError("Byte-read length must be an integer")
|
|
868
|
-
if length < 1
|
|
869
|
-
raise ValueError("Byte-read length must be
|
|
622
|
+
if length < 1:
|
|
623
|
+
raise ValueError("Byte-read length must be at least 1")
|
|
870
624
|
reader = getattr(document, "readBytes", None)
|
|
871
625
|
if not callable(reader):
|
|
872
626
|
raise CapabilityUnavailableError(
|
|
@@ -968,24 +722,24 @@ def _dispatch(method, params):
|
|
|
968
722
|
})
|
|
969
723
|
return result
|
|
970
724
|
if method == "list_procedures":
|
|
971
|
-
return
|
|
725
|
+
return [{"address": address, "value": value} for address, value in _search_inventory(document, "procedure")]
|
|
972
726
|
if method == "list_strings":
|
|
973
727
|
values = dict(_search_inventory(document, "string"))
|
|
974
728
|
requested = params.get("address")
|
|
975
729
|
if requested is not None:
|
|
976
730
|
key = _hex(_address(document, requested))
|
|
977
731
|
values = {key: values[key]} if key in values else {}
|
|
978
|
-
return
|
|
732
|
+
return [{"address": _hex(address), "value": value} for address, value in sorted(values.items())]
|
|
979
733
|
if method == "list_names":
|
|
980
734
|
result = dict(_search_inventory(document, "name"))
|
|
981
735
|
requested = params.get("address")
|
|
982
736
|
if requested is not None:
|
|
983
737
|
key = _hex(_address(document, requested))
|
|
984
738
|
result = {key: result[key]} if key in result else {}
|
|
985
|
-
return
|
|
739
|
+
return [{"address": _hex(address), "value": value} for address, value in sorted(result.items(), key=lambda item: int(item[0]))]
|
|
986
740
|
if method in ("search_procedures", "search_strings"):
|
|
987
741
|
kind = "procedure" if method == "search_procedures" else "string"
|
|
988
|
-
return
|
|
742
|
+
return _search_results(document, kind, params)
|
|
989
743
|
if method.startswith("procedure_"):
|
|
990
744
|
procedure = _procedure(document, params.get("procedure"))
|
|
991
745
|
if method == "procedure_address":
|
|
@@ -1039,11 +793,11 @@ def _dispatch(method, params):
|
|
|
1039
793
|
|
|
1040
794
|
|
|
1041
795
|
def _serve_connection(connection):
|
|
1042
|
-
"""Serve one
|
|
796
|
+
"""Serve one capability-authenticated NDJSON connection."""
|
|
1043
797
|
file = connection.makefile("rwb")
|
|
1044
798
|
while True:
|
|
1045
|
-
line = file.readline(
|
|
1046
|
-
if not line
|
|
799
|
+
line = file.readline()
|
|
800
|
+
if not line:
|
|
1047
801
|
break
|
|
1048
802
|
request_id = None
|
|
1049
803
|
authenticated = False
|
|
@@ -1119,13 +873,13 @@ def _safe_diagnostic(error):
|
|
|
1119
873
|
"""Project one exception without retaining provider or credential text."""
|
|
1120
874
|
diagnostic_type = _diagnostic_type(error)
|
|
1121
875
|
if diagnostic_type == "capability_unavailable":
|
|
1122
|
-
message = str(error)
|
|
876
|
+
message = str(error)
|
|
1123
877
|
elif diagnostic_type == "authorization":
|
|
1124
878
|
message = "Invalid bridge capability"
|
|
1125
879
|
elif diagnostic_type == "invalid_request":
|
|
1126
880
|
message = "Invalid Hopper bridge request"
|
|
1127
881
|
else:
|
|
1128
|
-
message = "%s: Hopper bridge operation failed" % type(error).__name__
|
|
882
|
+
message = "%s: Hopper bridge operation failed" % type(error).__name__
|
|
1129
883
|
return {"code": -32000, "message": message, "type": diagnostic_type}
|
|
1130
884
|
|
|
1131
885
|
|
|
@@ -1147,6 +901,7 @@ def _run():
|
|
|
1147
901
|
|
|
1148
902
|
|
|
1149
903
|
# Hopper's public objects are bound to its dedicated Python execution thread.
|
|
1150
|
-
# Keep dispatch on that thread; moving calls to
|
|
904
|
+
# Keep dispatch on that thread; moving calls to a worker can deadlock.
|
|
1151
905
|
if __name__ == "__main__":
|
|
906
|
+
_bind_session_document()
|
|
1152
907
|
_run()
|