rea-agents 5.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -655
- package/bridge/android/ReaJadxBridge.java +14 -5
- package/bridge/ghidra/ReaGhidraBridge.java +173 -47
- package/bridge/hopper_bridge.py +310 -128
- package/bridge/mitmproxy/capture.py +208 -0
- package/bridge/native/rea_lldb_tracer.py +839 -0
- package/bridge/process/ProcessRunTokenReader.swift +297 -0
- package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
- package/bridge/pwndbg/core_context.py +101 -0
- package/bridge/pwndbg/launch.py +39 -0
- package/bridge/pwndbg/launch_impl.py +34 -0
- package/bridge/pwntools/decoder_runtime.py +59 -0
- package/bridge/pwntools/layout.py +39 -0
- package/bridge/pwntools/layout_impl.py +309 -0
- package/bridge/pwntools/recorded_crash.py +39 -0
- package/bridge/pwntools/recorded_crash_impl.py +147 -0
- package/dist/android/JadxConfiguration.js +196 -33
- package/dist/android/JadxMcpTransport.js +4 -0
- package/dist/android/JadxProtocol.js +6 -0
- package/dist/android/JadxProvider.js +20 -2
- package/dist/android/JadxSession.js +23 -4
- package/dist/application/AnalysisContextQueries.js +8 -35
- package/dist/application/AnalysisDocument.js +32 -0
- package/dist/application/AppBundleExecutable.js +67 -21
- package/dist/application/CallPathTracing.js +19 -3
- package/dist/application/CapabilityInventory.js +27 -3
- package/dist/application/ClientConfigurationDocument.js +871 -6
- package/dist/application/ClientRegistrationIdentity.js +26 -5
- package/dist/application/ClientRegistrationStatus.js +29 -14
- package/dist/application/DirectAnalysis.js +97 -33
- package/dist/application/Doctor.js +4 -2
- package/dist/application/DoctorScope.js +25 -13
- package/dist/application/EnhancedLiteralTracing.js +22 -25
- package/dist/application/EnhancedTools.js +13 -11
- package/dist/application/EvidenceBundleFiles.js +24 -12
- package/dist/application/FunctionAnalysisEvidence.js +2 -3
- package/dist/application/InventoryProjectionEvidence.js +4 -3
- package/dist/application/InvestigationProviders.js +3 -2
- package/dist/application/JsonFiles.js +50 -28
- package/dist/application/ProcedureAddressResolution.js +11 -0
- package/dist/application/ReconstructionCoverageService.js +7 -4
- package/dist/application/ReconstructionObligationCandidates.js +5 -1
- package/dist/application/ReconstructionObligationLedgerService.js +4 -3
- package/dist/application/Setup.js +13 -1
- package/dist/application/SetupClientConfiguration.js +10 -15
- package/dist/application/SetupHost.js +5 -2
- package/dist/application/SetupPlan.js +5 -3
- package/dist/application/SupportedClients.js +34 -1
- package/dist/application/Uninstall.js +4 -3
- package/dist/application/Update.js +18 -3
- package/dist/application/UpdateRuntime.js +46 -25
- package/dist/application/WebModuleTraceService.js +4 -2
- package/dist/application/WebNetworkCapturePort.js +1 -0
- package/dist/application/WebNetworkCaptureService.js +134 -0
- package/dist/application/WebRuntimeService.js +5 -3
- package/dist/application/WebScriptExportService.js +2 -2
- package/dist/application/WebSourceLocationService.js +4 -2
- package/dist/application/WindowsCapabilities.js +1 -1
- package/dist/application/WorkflowEvidence.js +82 -0
- package/dist/application/binary/AnalysisProviderEvaluation.js +21 -5
- package/dist/application/binary/AnalysisProviderRegistry.js +2 -0
- package/dist/application/binary/AnalysisSnapshotCache.js +52 -12
- package/dist/application/binary/BinarySession.js +131 -76
- package/dist/application/binary/BinarySessionOpen.js +19 -6
- package/dist/application/binary/BinarySessionRecords.js +45 -3
- package/dist/application/binary/BinarySessionStatus.js +17 -1
- package/dist/application/binary/CompositeProvider.js +13 -0
- package/dist/application/binary/LazyAnalysisProvider.js +3 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +59 -0
- package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +62 -0
- package/dist/application/evm/EvmInterfacePort.js +1 -0
- package/dist/application/evm/EvmInterfaceService.js +64 -0
- package/dist/application/investigation/EvidenceLedger.js +21 -7
- package/dist/application/investigation/InvestigationRecords.js +8 -0
- package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +25 -5
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +34 -14
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +47 -27
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +39 -7
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +80 -27
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +33 -12
- package/dist/application/javascript/JavaScriptModuleRelationships.js +37 -8
- package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -1
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +149 -72
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +27 -5
- package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
- package/dist/application/managed/ManagedMemberComparisonService.js +7 -4
- package/dist/application/managed/ManagedNativeVerificationService.js +4 -3
- package/dist/application/managed/ManagedReconstructionService.js +4 -3
- package/dist/application/{ProcessCli.js → process/ProcessCli.js} +23 -15
- package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +8 -7
- package/dist/application/workflowInputError.js +18 -0
- package/dist/artifacts/ArtifactProvider.js +42 -5
- package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +98 -14
- package/dist/artifacts/NativeDmgArtifactReader.js +13 -6
- package/dist/artifacts/ZipArtifactReader.js +3 -0
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +22 -3
- package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +36 -22
- package/dist/artifacts/apple/MachoLoadCommandReader.js +355 -0
- 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/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
- package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +16 -11
- package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
- package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
- package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +14 -17
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
- package/dist/artifacts/readStableArtifact.js +20 -4
- package/dist/browser/CdpCaptureCompleteness.js +2 -0
- package/dist/browser/CdpCaptureEventHandlers.js +165 -12
- package/dist/browser/CdpCaptureEventTypes.js +5 -1
- package/dist/browser/CdpCaptureEvents.js +34 -0
- package/dist/browser/CdpConnection.js +30 -11
- package/dist/browser/CdpOptionalCommand.js +2 -3
- package/dist/browser/CdpPageCapture.js +23 -1
- package/dist/browser/PlaywrightElectronActiveActions.js +32 -23
- package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +130 -122
- package/dist/browser/WebSourceMapFetcher.js +426 -72
- package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
- package/dist/browser/history/CaptureFailures.js +137 -0
- package/dist/browser/history/CaptureFormatError.js +10 -0
- package/dist/browser/history/CaptureRedaction.js +65 -0
- package/dist/browser/history/CaptureRelease.js +17 -0
- package/dist/browser/history/HarCapture.js +165 -0
- package/dist/browser/history/HarCaptureAdapter.js +20 -0
- package/dist/browser/history/HarCaptureProcess.js +57 -0
- package/dist/browser/history/HarJson.js +92 -0
- package/dist/browser/history/HarSchema.js +72 -0
- package/dist/browser/history/HistoricalCaptureDecoder.js +188 -0
- package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
- package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
- package/dist/cli/analysisSelector.js +23 -0
- package/dist/cli/applicationCommands.js +2 -3
- package/dist/cli/artifactCommands.js +26 -1
- package/dist/cli/binaryDiagnosticsCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +78 -20
- package/dist/cli/electronCommands.js +21 -13
- package/dist/cli/evmCommands.js +24 -0
- package/dist/cli/firmwareCommands.js +6 -3
- package/dist/cli/javascriptApplicationAnalysis.js +20 -3
- package/dist/cli/jsonOutput.js +38 -0
- package/dist/cli/nativeCallCommands.js +34 -0
- package/dist/cli/processCommands.js +1 -1
- package/dist/cli/streamedJsonOutput.js +56 -0
- package/dist/cli/utilityCommands.js +2 -0
- package/dist/cli/webNetworkCaptureCommands.js +40 -0
- package/dist/cli/webRuntimeCommands.js +8 -8
- package/dist/cli.js +11 -4
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +6 -1
- package/dist/cliJsonInput.js +35 -1
- package/dist/cliOutput.js +21 -6
- package/dist/composition/binaryDiagnostics.js +8 -0
- package/dist/composition/evm.js +4 -0
- package/dist/composition/webNetworkCaptures.js +6 -0
- package/dist/config/environment.js +4 -0
- package/dist/config/ghidraStartupTimeout.js +17 -0
- package/dist/config/mcpResponseBudget.js +22 -0
- package/dist/config/parseConfig.js +2 -1
- package/dist/contracts/artifactToolContracts.js +6 -0
- package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
- package/dist/contracts/browserToolContracts.js +4 -3
- package/dist/contracts/enhancedInputs.js +5 -3
- package/dist/contracts/enhancedToolContracts.js +3 -3
- package/dist/contracts/errorSchemas.js +8 -1
- package/dist/contracts/evm/evmToolContracts.js +20 -0
- package/dist/contracts/hopperMemoryContracts.js +2 -5
- package/dist/contracts/investigationExamples.js +2 -2
- package/dist/contracts/javascript/electronToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +8 -6
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
- package/dist/contracts/native/nativeToolContracts.js +21 -3
- package/dist/contracts/officialToolContracts.js +26 -24
- package/dist/contracts/process/processCaptureExample.js +2 -0
- package/dist/contracts/promptContracts.js +3 -3
- package/dist/contracts/sessionLifecycleInputs.js +18 -5
- package/dist/contracts/sessionStatusContract.js +8 -2
- package/dist/contracts/sessionToolContracts.js +8 -3
- package/dist/contracts/sessionToolSchemas.js +8 -4
- package/dist/contracts/toolContractExamples.js +1 -2
- package/dist/contracts/toolContractHelpers.js +4 -1
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +30 -1
- package/dist/contracts/toolOutputSchemaGroups.js +33 -28
- package/dist/contracts/toolOutputSchemaPrimitives.js +19 -1
- package/dist/contracts/toolSchemaMetadata.js +69 -10
- package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
- package/dist/domain/analysisErrorBase.js +22 -2
- package/dist/domain/analysisErrorCore.js +61 -5
- package/dist/domain/analysisErrorPresentation.js +95 -12
- package/dist/domain/analysisErrorProjection.js +148 -19
- package/dist/domain/analysisSnapshot.js +166 -2
- package/dist/domain/android/androidAnalysis.js +2 -4
- package/dist/domain/android/androidApplication.js +17 -9
- package/dist/domain/apple/appleApplication.js +41 -14
- package/dist/domain/apple/dyldEnvironment.js +73 -0
- package/dist/domain/apple/dyldPaths.js +81 -0
- package/dist/domain/apple/dylibResolution.js +478 -0
- package/dist/domain/apple/dylibResolutionFindings.js +77 -0
- package/dist/domain/apple/interfaceBuilderGraph.js +25 -13
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
- package/dist/domain/apple/keyedArchive.js +9 -1
- package/dist/domain/apple/machoContainer.js +54 -0
- package/dist/domain/apple/plistNumbers.js +76 -0
- package/dist/domain/artifactIdentity.js +29 -0
- package/dist/domain/artifactInventoryEvidence.js +19 -24
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/bridgeCandidateProjection.js +71 -0
- package/dist/domain/browserCompleteness.js +1 -0
- package/dist/domain/browserObservation.js +1 -1
- package/dist/domain/browserObservationError.js +24 -5
- package/dist/domain/browserObservationSchemas.js +13 -0
- package/dist/domain/browserScenarioValues.js +5 -2
- package/dist/domain/bundleComparison.js +3 -2
- package/dist/domain/callPathSchemas.js +1 -1
- package/dist/domain/canonicalDigest.js +13 -1
- 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/comparisonStatus.js +2 -30
- package/dist/domain/configurationErrors.js +1 -1
- package/dist/domain/conformanceTrustGate.js +0 -16
- package/dist/domain/evidence.js +78 -11
- package/dist/domain/evidenceBundle.js +42 -1
- package/dist/domain/evidenceErrors.js +12 -1
- package/dist/domain/evm/evmInterface.js +63 -0
- package/dist/domain/explicitSensitiveFailure.js +108 -0
- package/dist/domain/explicitSensitiveValues.js +10 -0
- package/dist/domain/firmware/firmwareAnalysis.js +10 -4
- 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 +37 -6
- package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
- package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
- package/dist/domain/javascript/javascriptApplicationGraph.js +13 -0
- package/dist/domain/javascript/javascriptAstValues.js +20 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
- package/dist/domain/javascript/javascriptRecovery.js +3 -8
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +97 -2
- package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +22 -5
- package/dist/domain/javascript/javascriptSemanticGraph.js +34 -5
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +25 -17
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +83 -11
- package/dist/domain/javascript/javascriptSourceParser.js +6 -2
- package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +14 -4
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -16
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
- package/dist/domain/jsonSerialization.js +109 -0
- package/dist/domain/jsonValue.js +91 -3
- package/dist/domain/localPath.js +8 -0
- package/dist/domain/managed/managedApplicationGraph.js +10 -10
- package/dist/domain/managed/managedInspectionEvidence.js +16 -0
- package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
- package/dist/domain/managed/managedNativeVerification.js +3 -9
- package/dist/domain/native/binaryLayout.js +357 -0
- package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
- package/dist/domain/native/nativeCallObservation.js +186 -0
- package/dist/domain/native/nativeCallPartialObservation.js +33 -0
- package/dist/domain/native/objcSwiftMetadata.js +0 -39
- package/dist/domain/native/recordedCrash.js +266 -0
- package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
- package/dist/domain/{processCapture.js → process/processCapture.js} +143 -2
- package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
- package/dist/domain/process/processCaptureParsing.js +54 -0
- package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
- package/dist/domain/{processComparison.js → process/processComparison.js} +39 -5
- package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
- package/dist/domain/{processScenario.js → process/processScenario.js} +11 -10
- package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
- package/dist/domain/propertyListKeys.js +1 -1
- package/dist/domain/propertyListXmlText.js +19 -0
- package/dist/domain/providerAdapterError.js +1 -1
- package/dist/domain/providerOperationHealth.js +54 -0
- package/dist/domain/providerSelectionError.js +4 -2
- package/dist/domain/reconstructionVerification.js +9 -46
- package/dist/domain/reconstructionVerificationSchemas.js +3 -3
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +9 -46
- 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 +1 -0
- package/dist/domain/webNetworkCapture.js +118 -0
- package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
- package/dist/domain/webRuntime.js +19 -5
- package/dist/domain/webSourceLocation.js +1 -0
- package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
- package/dist/dotnet/ManagedMemberInspector.js +4 -2
- package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
- package/dist/dotnet/ManagedMemberRows.js +14 -3
- package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
- package/dist/dotnet/ManagedMetadataInventory.js +38 -28
- package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
- package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
- package/dist/dotnet/ManagedPeReader.js +11 -0
- package/dist/evm/EvmBytecodeCarrier.js +21 -0
- package/dist/evm/EvmWorkerLimits.js +40 -0
- package/dist/evm/EvmoleFailures.js +126 -0
- package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
- package/dist/evm/EvmoleInterfaceProvider.js +273 -0
- package/dist/evm/EvmoleInterfaceWorker.js +87 -0
- package/dist/evm/EvmoleRelease.js +16 -0
- package/dist/firmware/FirmwareCommand.js +1 -0
- package/dist/firmware/FirmwareFiles.js +1 -1
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +5 -0
- package/dist/ghidra/GhidraClient.js +47 -14
- package/dist/ghidra/GhidraDiagnostics.js +7 -7
- package/dist/ghidra/GhidraFunctionValues.js +10 -7
- package/dist/ghidra/GhidraInstallation.js +18 -21
- package/dist/ghidra/GhidraInventoryValues.js +14 -4
- package/dist/ghidra/GhidraJavaLaunch.js +62 -0
- package/dist/ghidra/GhidraLauncher.js +34 -16
- package/dist/ghidra/GhidraProvider.js +2 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +15 -3
- package/dist/ghidra/GhidraProviderClient.js +23 -12
- package/dist/ghidra/GhidraSessionError.js +11 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
- package/dist/ghidra/GhidraTransport.js +20 -0
- package/dist/hopper/BridgeLauncher.js +33 -11
- package/dist/hopper/HopperAnalysisProfile.js +62 -4
- package/dist/hopper/HopperCleanup.js +15 -3
- package/dist/hopper/HopperClient.js +222 -14
- package/dist/hopper/HopperFileOffset.js +237 -0
- package/dist/hopper/HopperMachOImage.js +196 -0
- package/dist/hopper/HopperOperationStage.js +6 -0
- package/dist/hopper/HopperProvider.js +63 -9
- package/dist/hopper/HopperProviderCapabilities.js +19 -1
- package/dist/hopper/HopperRegexSearch.js +137 -0
- package/dist/hopper/HopperRegexWorker.js +27 -0
- package/dist/hopper/HopperRequestQueue.js +68 -19
- package/dist/hopper/HopperTargetLease.js +3 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
- package/dist/inspector/V8InspectorCaptureProjection.js +8 -3
- package/dist/inspector/V8InspectorProvider.js +47 -11
- package/dist/javascript/recovery/WakaruCommand.js +3 -0
- package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +17 -0
- package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
- package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
- package/dist/mcpDoctor.js +62 -2
- package/dist/native/AppleDispatchCoverage.js +47 -6
- package/dist/native/AppleDispatchDecodeFacts.js +6 -0
- package/dist/native/AppleDispatchMetadata.js +6 -3
- package/dist/native/AppleMachoFixups.js +48 -24
- package/dist/native/AppleMachoSelection.js +32 -16
- package/dist/native/AppleObjcCategories.js +6 -2
- package/dist/native/AppleObjcDispatchFacets.js +5 -2
- package/dist/native/AppleObjcProperties.js +2 -1
- package/dist/native/AppleSwiftDispatchFacets.js +27 -21
- package/dist/native/AppleSwiftVtables.js +21 -15
- package/dist/native/CommandRunner.js +82 -84
- package/dist/native/LldbCallTracer.js +541 -0
- package/dist/native/LldbRetainedObservations.js +178 -0
- package/dist/native/NativeCallObservation.js +194 -0
- package/dist/native/NativeMacOSProvider.js +117 -20
- package/dist/native/NativeMacOSProviderMetadata.js +8 -3
- package/dist/native/SignatureTargetBinding.js +155 -0
- package/dist/native/parsers/lipo.js +71 -1
- package/dist/native/pwndbg/PwndbgCoreContext.js +180 -0
- package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
- package/dist/native/pwntools/PwntoolsFailures.js +180 -0
- package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
- package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
- package/dist/native/pwntools/PwntoolsRelease.js +19 -0
- package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
- package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +103 -0
- package/dist/process/DarwinProcessRunTokenReader.js +293 -0
- package/dist/process/ExecFileOutput.js +20 -0
- package/dist/process/OwnedCommand.js +118 -0
- package/dist/process/ProcessOwnership.js +431 -51
- package/dist/process/ProcessOwnershipObservation.js +209 -27
- package/dist/process/ProviderProcess.js +68 -10
- package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
- package/dist/{application → process/capture}/ProcessCaptureError.js +18 -2
- package/dist/process/capture/ProcessCaptureLifecycle.js +681 -0
- package/dist/{application → process/capture}/ProcessHarness.js +195 -29
- package/dist/{application → process/capture}/ProcessSampling.js +2 -2
- package/dist/server/EvidenceMcpServer.js +146 -0
- package/dist/server/createServer.js +37 -8
- package/dist/server/promptCompletion.js +10 -3
- package/dist/server/registerAndroidTools.js +2 -4
- package/dist/server/registerApplicationTools/helpers.js +2 -4
- package/dist/server/registerArtifactComparisonTool.js +11 -7
- package/dist/server/registerBinaryDiagnosticsTools.js +15 -0
- package/dist/server/registerBrowserScenarioTool.js +2 -4
- package/dist/server/registerBrowserTools.js +2 -4
- package/dist/server/registerBundleComparisonTool.js +2 -3
- package/dist/server/registerCloseLifecycleTool.js +8 -18
- package/dist/server/registerElectronTools.js +2 -4
- package/dist/server/registerEnhancedTools.js +18 -59
- package/dist/server/registerEvidenceTools.js +3 -5
- package/dist/server/registerEvmTools.js +15 -0
- package/dist/server/registerFirmwareTools.js +2 -4
- package/dist/server/registerFunctionComparisonTool.js +10 -6
- package/dist/server/registerInvestigationTools.js +7 -7
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -4
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +2 -4
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +2 -4
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +2 -4
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +2 -4
- package/dist/server/registerOfficialTools.js +2 -4
- package/dist/server/registerProcessComparisonTool.js +72 -46
- package/dist/server/registerRecordedCrashTools.js +15 -0
- package/dist/server/registerSessionRecordTools.js +5 -6
- package/dist/server/registerSessionStatusTool.js +17 -3
- package/dist/server/registerSessionTools.js +13 -5
- package/dist/server/registerWebModuleTool.js +2 -4
- package/dist/server/registerWebNetworkCaptureTool.js +26 -0
- package/dist/server/registerWebRuntimeTools.js +3 -7
- package/dist/server/registerWebScriptTool.js +2 -4
- package/dist/server/registerWebSourceLocationTool.js +2 -4
- package/dist/server/runDerivedOperation.js +15 -3
- package/dist/server/sessionAvailabilityPolicy.js +3 -1
- package/dist/server/sessionToolPolicies.js +1 -1
- package/dist/server/toolRegistrationOptions.js +2 -2
- package/dist/server/toolResult.js +63 -11
- package/dist/server/toolResultEncoding.js +33 -0
- package/install.sh +1 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +42 -9
- package/scripts/electron-active-hook-boundaries.cjs +18 -20
- package/scripts/electron-active-hook.cjs +241 -37
- package/scripts/rea.mjs +11 -3
- package/skills/reverse-engineer-anything/SKILL.md +32 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +8 -1
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
- package/third_party/README.md +60 -0
- package/third_party/evmole/LICENSE +21 -0
- package/third_party/evmole/README.md +22 -0
- package/third_party/pwndbg/LICENSE.md +21 -0
- package/third_party/pwndbg/README.md +23 -0
- package/third_party/pwntools/README.md +40 -0
- package/dist/application/AuthorizedArtifactInventory.js +0 -7
- package/dist/application/ProcessCaptureLifecycle.js +0 -299
- package/dist/application/StoreFileLock.js +0 -124
- package/dist/contracts/processCaptureExample.js +0 -2
- package/dist/domain/bytecodeProvider.js +0 -178
- package/dist/domain/customProtocolCapture.js +0 -137
- package/dist/domain/eventProcessTree.js +0 -225
- package/dist/domain/mobileApplicationInvestigation.js +0 -159
- package/dist/domain/packageAnalysis.js +0 -123
- package/dist/domain/peInspection.js +0 -197
- package/dist/domain/processCaptureParsing.js +0 -21
- package/dist/domain/protocolCapture.js +0 -217
- package/dist/domain/runtimeIdentification.js +0 -212
- package/dist/generatedMcpToolCatalog.js +0 -37
- package/dist/ghidra/GhidraDefaults.js +0 -2
- /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
- /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
- /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
- /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
- /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
- /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
- /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
- /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
- /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
- /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
- /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createReadStream } from "node:fs";
|
|
2
|
-
import { stat } from "node:fs/promises";
|
|
2
|
+
import { open as openFile, stat } from "node:fs/promises";
|
|
3
3
|
import { Readable } from "node:stream";
|
|
4
4
|
import { XcrunCommandRunner, } from "../native/CommandRunner.js";
|
|
5
|
-
import { parseLipoArchitectures } from "../native/parsers/lipo.js";
|
|
5
|
+
import { parseLipoArchitectures, } from "../native/parsers/lipo.js";
|
|
6
|
+
import { readMachoImage } from "./apple/MachoLoadCommandReader.js";
|
|
6
7
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
7
8
|
import { streamChunkToBuffer } from "./StreamBytes.js";
|
|
8
9
|
/** Read-only universal Mach-O slice reader backed by native lipo metadata. */
|
|
@@ -28,28 +29,75 @@ export class MachOSliceArtifactReader {
|
|
|
28
29
|
effects: ["read"],
|
|
29
30
|
};
|
|
30
31
|
const fileSize = (await stat(this.path)).size;
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const architectures = parseLipoArchitectures(captured.value.stdout);
|
|
33
|
+
const structural = await readStructuralSlices(this.path, fileSize);
|
|
34
|
+
if (structural.status === "malformed")
|
|
35
|
+
throw new ArtifactReaderFailure("integrity", `Mach-O structural slice index is malformed: ${structural.reason}`);
|
|
36
|
+
if (structural.status === "unsupported")
|
|
37
|
+
throw new ArtifactReaderFailure("format", `Mach-O structural slice index is unsupported: ${structural.reason}`);
|
|
38
|
+
const slices = structural.status === "parsed" ? structural.slices : null;
|
|
39
|
+
const matchingSlices = new Map();
|
|
40
|
+
if (slices !== null) {
|
|
41
|
+
if (slices.length !== architectures.length)
|
|
42
|
+
throw new ArtifactReaderFailure("integrity", "lipo architecture count disagrees with the Mach-O FAT table");
|
|
43
|
+
const unmatched = [...slices];
|
|
44
|
+
for (const reported of architectures) {
|
|
45
|
+
const match = unmatched.findIndex((observed) => lipoMatchesSlice(reported, observed, slices.length === 1));
|
|
46
|
+
if (match < 0)
|
|
47
|
+
throw new ArtifactReaderFailure("integrity", `lipo slice metadata disagrees with the Mach-O FAT table: ${reported.name} (cputype=${reported.cpu_type ?? "unknown"}, cpusubtype=${reported.cpu_subtype ?? "unknown"}, offset=${reported.file_offset ?? "unknown"}, size=${reported.size ?? "unknown"}, alignment=${reported.alignment ?? "unknown"})`);
|
|
48
|
+
const [observed] = unmatched.splice(match, 1);
|
|
49
|
+
if (observed !== undefined)
|
|
50
|
+
matchingSlices.set(reported, observed);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const architecture of architectures) {
|
|
54
|
+
const structuralSlice = matchingSlices.get(architecture);
|
|
55
|
+
const offset = architecture.file_offset ?? structuralSlice?.slice_offset;
|
|
56
|
+
const sliceSize = architecture.size ?? structuralSlice?.slice_size;
|
|
57
|
+
if (offset === undefined || sliceSize === undefined)
|
|
33
58
|
throw new ArtifactReaderFailure("integrity", "lipo omitted a universal slice byte range");
|
|
34
|
-
if (!Number.isSafeInteger(
|
|
35
|
-
!Number.isSafeInteger(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
!Number.isSafeInteger(
|
|
39
|
-
|
|
59
|
+
if (!Number.isSafeInteger(offset) ||
|
|
60
|
+
!Number.isSafeInteger(sliceSize) ||
|
|
61
|
+
offset < 0 ||
|
|
62
|
+
sliceSize <= 0 ||
|
|
63
|
+
!Number.isSafeInteger(offset + sliceSize) ||
|
|
64
|
+
offset + sliceSize > fileSize)
|
|
40
65
|
throw new ArtifactReaderFailure("integrity", `lipo reported an out-of-bounds Mach-O slice: ${architecture.name}`);
|
|
41
66
|
yield {
|
|
42
67
|
path: `slices/${architecture.name}`,
|
|
43
68
|
kind: "slice",
|
|
44
|
-
declaredSize:
|
|
69
|
+
declaredSize: sliceSize,
|
|
45
70
|
compressedSize: null,
|
|
46
71
|
executable: true,
|
|
47
72
|
encrypted: false,
|
|
48
|
-
byteOffset:
|
|
73
|
+
byteOffset: offset,
|
|
49
74
|
declaredSha256: null,
|
|
50
75
|
unpacked: false,
|
|
51
|
-
limitations: [
|
|
52
|
-
|
|
76
|
+
limitations: [
|
|
77
|
+
...(structural.status === "not-mach-o"
|
|
78
|
+
? [
|
|
79
|
+
"Structural Mach-O facts were unavailable; slice range is based on lipo output.",
|
|
80
|
+
]
|
|
81
|
+
: []),
|
|
82
|
+
...(architecture.file_offset === null || architecture.size === null
|
|
83
|
+
? [
|
|
84
|
+
"Slice range was derived from structural Mach-O facts because lipo omitted it.",
|
|
85
|
+
]
|
|
86
|
+
: []),
|
|
87
|
+
...(architecture.cpu_type !== null &&
|
|
88
|
+
architecture.cpu_type_code === null
|
|
89
|
+
? [
|
|
90
|
+
`lipo CPU type is retained as unnormalized source text: ${architecture.cpu_type}`,
|
|
91
|
+
]
|
|
92
|
+
: []),
|
|
93
|
+
...(architecture.cpu_subtype !== null &&
|
|
94
|
+
architecture.cpu_subtype_code === null
|
|
95
|
+
? [
|
|
96
|
+
`lipo CPU subtype is retained as unnormalized source text: ${architecture.cpu_subtype}${architecture.capabilities === null ? "" : `; capabilities ${architecture.capabilities}`}`,
|
|
97
|
+
]
|
|
98
|
+
: []),
|
|
99
|
+
],
|
|
100
|
+
adapterKey: `${String(offset)}:${String(sliceSize)}`,
|
|
53
101
|
};
|
|
54
102
|
}
|
|
55
103
|
}
|
|
@@ -103,6 +151,42 @@ export class MachOSliceArtifactReader {
|
|
|
103
151
|
return Promise.resolve();
|
|
104
152
|
}
|
|
105
153
|
}
|
|
154
|
+
/** Compare lipo's independent ranges with structurally parsed slice identity. */
|
|
155
|
+
const readStructuralSlices = async (path, size) => {
|
|
156
|
+
const file = await openFile(path, "r");
|
|
157
|
+
try {
|
|
158
|
+
const readAt = async (offset, length) => {
|
|
159
|
+
const bytes = Buffer.alloc(length);
|
|
160
|
+
const { bytesRead } = await file.read(bytes, 0, length, offset);
|
|
161
|
+
return bytes.subarray(0, bytesRead);
|
|
162
|
+
};
|
|
163
|
+
const facts = await readMachoImage(readAt, size);
|
|
164
|
+
return facts;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
await file.close();
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
|
|
171
|
+
const observedCpuType = observed.fat_cpu_type ?? observed.cpu_type;
|
|
172
|
+
const observedCpuSubtype = observed.fat_cpu_subtype ?? observed.cpu_subtype;
|
|
173
|
+
const hasPhysicalIdentity = reported.file_offset !== null ||
|
|
174
|
+
reported.size !== null ||
|
|
175
|
+
reported.cpu_type_code !== null ||
|
|
176
|
+
reported.cpu_subtype_code !== null;
|
|
177
|
+
return ((hasPhysicalIdentity || structurallyUnique) &&
|
|
178
|
+
reported.name === observed.architecture &&
|
|
179
|
+
(reported.file_offset === null ||
|
|
180
|
+
reported.file_offset === observed.slice_offset) &&
|
|
181
|
+
(reported.size === null || reported.size === observed.slice_size) &&
|
|
182
|
+
(reported.cpu_type_code === null ||
|
|
183
|
+
reported.cpu_type_code === observedCpuType) &&
|
|
184
|
+
(reported.cpu_subtype_code === null ||
|
|
185
|
+
reported.cpu_subtype_code === observedCpuSubtype) &&
|
|
186
|
+
(reported.alignment === null ||
|
|
187
|
+
observed.fat_alignment_exponent === null ||
|
|
188
|
+
reported.alignment === 2 ** observed.fat_alignment_exponent));
|
|
189
|
+
};
|
|
106
190
|
const parseSliceKeyInteger = (value) => {
|
|
107
191
|
if (value === undefined || !/^\d+$/u.test(value))
|
|
108
192
|
return null;
|
|
@@ -80,6 +80,7 @@ export class NativeDmgArtifactReader {
|
|
|
80
80
|
}
|
|
81
81
|
async close() {
|
|
82
82
|
let detachFailure;
|
|
83
|
+
const remainingDevices = [];
|
|
83
84
|
for (const device of [...this.#devices].reverse()) {
|
|
84
85
|
try {
|
|
85
86
|
await runChecked(this.host, ["detach", device], undefined, {
|
|
@@ -91,17 +92,22 @@ export class NativeDmgArtifactReader {
|
|
|
91
92
|
// Detaching a synthesized APFS container also ejects the image that
|
|
92
93
|
// backs it, so a later whole disk of the same image may already be
|
|
93
94
|
// gone. Only a device that is still attached is a cleanup failure.
|
|
94
|
-
if (await this.#isAttached(device))
|
|
95
|
+
if (await this.#isAttached(device)) {
|
|
96
|
+
remainingDevices.push(device);
|
|
95
97
|
detachFailure ??= cause;
|
|
98
|
+
}
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
|
-
this.#devices =
|
|
99
|
-
if (this.#mountRoot !== undefined)
|
|
100
|
-
await rm(this.#mountRoot, { recursive: true, force: true }).
|
|
101
|
+
this.#devices = remainingDevices.reverse();
|
|
102
|
+
if (this.#devices.length === 0 && this.#mountRoot !== undefined)
|
|
103
|
+
await rm(this.#mountRoot, { recursive: true, force: true }).then(() => {
|
|
104
|
+
this.#mountRoot = undefined;
|
|
105
|
+
this.#directory = undefined;
|
|
106
|
+
}, (cause) => {
|
|
101
107
|
detachFailure ??= cause;
|
|
102
108
|
});
|
|
103
109
|
if (detachFailure !== undefined)
|
|
104
|
-
throw new ArtifactReaderFailure("unavailable",
|
|
110
|
+
throw new ArtifactReaderFailure("unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, { cause: detachFailure });
|
|
105
111
|
}
|
|
106
112
|
/**
|
|
107
113
|
* Report whether hdiutil still lists a device; unknown state counts as
|
|
@@ -169,11 +175,12 @@ export class NativeDmgArtifactReader {
|
|
|
169
175
|
cleanupFailure = cleanupCause;
|
|
170
176
|
}
|
|
171
177
|
if (cleanupFailure !== undefined)
|
|
172
|
-
throw new ArtifactReaderFailure("unavailable",
|
|
178
|
+
throw new ArtifactReaderFailure("unavailable", `DMG attach failed and cleanup could not detach every device: ${failureMessage(cause)}; cleanup: ${failureMessage(cleanupFailure)}`, { cause: new AggregateError([cause, cleanupFailure]) });
|
|
173
179
|
throw cause;
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
182
|
}
|
|
183
|
+
const failureMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
177
184
|
const runChecked = async (host, arguments_, signal, options) => {
|
|
178
185
|
let result;
|
|
179
186
|
try {
|
|
@@ -39,6 +39,9 @@ export class ZipArtifactReader {
|
|
|
39
39
|
this.#reader = new ZipReader(this.#source, {
|
|
40
40
|
checkSignature: true,
|
|
41
41
|
checkOverlappingEntry: true,
|
|
42
|
+
// REA applies its own provider-neutral path validation in scanReader and
|
|
43
|
+
// must preserve that typed failure instead of zip.js rejecting first.
|
|
44
|
+
filenameValidation: "tolerant",
|
|
42
45
|
});
|
|
43
46
|
}
|
|
44
47
|
async *entries(signal) {
|
|
@@ -26,11 +26,16 @@ export const analyzeAppleAssetCatalogs = async (input) => {
|
|
|
26
26
|
const page = appleAssetCatalogInputSchema.parse(input.page ?? {});
|
|
27
27
|
const reader = new DirectoryArtifactReader(input.bundlePath);
|
|
28
28
|
const catalogs = [];
|
|
29
|
+
const uninspected = [];
|
|
29
30
|
let totalMetadataBytes = 0;
|
|
30
31
|
try {
|
|
31
32
|
for await (const entry of reader.entries(input.signal)) {
|
|
32
|
-
if (
|
|
33
|
+
if (!entry.path.endsWith("Assets.car"))
|
|
33
34
|
continue;
|
|
35
|
+
if (entry.kind !== "file") {
|
|
36
|
+
uninspected.push(`${entry.path} (${entry.kind})`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
34
39
|
const inspected = await inspectAssetCatalogEntry({
|
|
35
40
|
reader,
|
|
36
41
|
entry,
|
|
@@ -46,8 +51,10 @@ export const analyzeAppleAssetCatalogs = async (input) => {
|
|
|
46
51
|
finally {
|
|
47
52
|
await reader.close();
|
|
48
53
|
}
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
// Without any readable catalog, unmatched resource keys would overstate an
|
|
55
|
+
// absence that a skipped catalog entry may contradict.
|
|
56
|
+
if (catalogs.length === 0 && uninspected.length > 0)
|
|
57
|
+
throw new ArtifactReaderFailure("path", `Asset catalog entries are not regular files and were not inspected: ${uninspected.join(", ")}`);
|
|
51
58
|
const interfaceBuilder = await analyzeInterfaceBuilderBundle({
|
|
52
59
|
bundlePath: input.bundlePath,
|
|
53
60
|
targetSha256: input.targetSha256,
|
|
@@ -65,6 +72,18 @@ export const analyzeAppleAssetCatalogs = async (input) => {
|
|
|
65
72
|
...result,
|
|
66
73
|
limitations: [
|
|
67
74
|
...result.limitations,
|
|
75
|
+
// An app without a compiled catalog is an observed empty inventory, not
|
|
76
|
+
// a missing host tool.
|
|
77
|
+
...(catalogs.length === 0
|
|
78
|
+
? [
|
|
79
|
+
"No compiled Assets.car catalog was found among the app bundle's regular files (symlinks are not followed); any resource keys are reported as unmatched.",
|
|
80
|
+
]
|
|
81
|
+
: []),
|
|
82
|
+
...(uninspected.length === 0
|
|
83
|
+
? []
|
|
84
|
+
: [
|
|
85
|
+
`Asset catalog entries that are not regular files were not inspected, so resource keys reported as unmatched may resolve there: ${uninspected.join(", ")}`,
|
|
86
|
+
]),
|
|
68
87
|
"Exact resource-key joins use only recognized image or asset key fields on decoded Interface Builder resource objects; other archive resource references are not inferred.",
|
|
69
88
|
...(interfaceBuilder.graph.truncated
|
|
70
89
|
? [
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { lstat, open, readlink, realpath } from "node:fs/promises";
|
|
4
|
+
import { join, relative, sep } from "node:path";
|
|
5
|
+
import { resolveTreePath } from "../../domain/apple/dyldPaths.js";
|
|
6
|
+
import { dylibResolutionInputSchema, dylibResolutionResultSchema, traceDylibLoading, } from "../../domain/apple/dylibResolution.js";
|
|
7
|
+
import { ArtifactReaderFailure } from "../ArtifactReader.js";
|
|
8
|
+
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
|
9
|
+
import { hasMachoMagic, readMachoImage } from "./MachoLoadCommandReader.js";
|
|
10
|
+
const HASH_CHUNK_BYTES = 1024 * 1024;
|
|
11
|
+
/** Lazily probed, symlink-preserving view of one analyzed directory. */
|
|
12
|
+
class FilesystemTreeView {
|
|
13
|
+
root;
|
|
14
|
+
signal;
|
|
15
|
+
#entries = new Map();
|
|
16
|
+
#images = new Map();
|
|
17
|
+
#identities = new Map();
|
|
18
|
+
constructor(root, signal) {
|
|
19
|
+
this.root = root;
|
|
20
|
+
this.signal = signal;
|
|
21
|
+
}
|
|
22
|
+
entry(path) {
|
|
23
|
+
const cached = this.#entries.get(path);
|
|
24
|
+
if (cached !== undefined)
|
|
25
|
+
return cached;
|
|
26
|
+
const pending = this.#readEntry(path);
|
|
27
|
+
this.#entries.set(path, pending);
|
|
28
|
+
return pending;
|
|
29
|
+
}
|
|
30
|
+
image(path) {
|
|
31
|
+
const cached = this.#images.get(path);
|
|
32
|
+
if (cached !== undefined)
|
|
33
|
+
return cached;
|
|
34
|
+
const pending = readImage(join(this.root, path), this.signal).then(({ facts, identity }) => {
|
|
35
|
+
this.#identities.set(path, identity);
|
|
36
|
+
return facts;
|
|
37
|
+
});
|
|
38
|
+
this.#images.set(path, pending);
|
|
39
|
+
return pending;
|
|
40
|
+
}
|
|
41
|
+
/** Identity of the file whose header bytes `image()` parsed. */
|
|
42
|
+
identity(path) {
|
|
43
|
+
return this.#identities.get(path);
|
|
44
|
+
}
|
|
45
|
+
async #readEntry(path) {
|
|
46
|
+
cancelled(this.signal);
|
|
47
|
+
const absolute = join(this.root, path);
|
|
48
|
+
try {
|
|
49
|
+
const metadata = await lstat(absolute);
|
|
50
|
+
if (metadata.isSymbolicLink())
|
|
51
|
+
return { kind: "symlink", target: await readlink(absolute) };
|
|
52
|
+
if (metadata.isDirectory())
|
|
53
|
+
return { kind: "directory" };
|
|
54
|
+
return metadata.isFile() ? { kind: "file" } : undefined;
|
|
55
|
+
}
|
|
56
|
+
catch (cause) {
|
|
57
|
+
if (missing(cause))
|
|
58
|
+
return undefined;
|
|
59
|
+
throw cause;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Resolve dyld load paths for the active Mach-O or every executable in its bundle. */
|
|
64
|
+
export const traceDylibResolution = async (options) => {
|
|
65
|
+
const parsed = dylibResolutionInputSchema.safeParse(options.parameters);
|
|
66
|
+
if (!parsed.success)
|
|
67
|
+
throw new ArtifactReaderFailure("path", "roots must be normalized paths relative to the analyzed root");
|
|
68
|
+
// Canonicalization is inside the translated region: a revoked permission
|
|
69
|
+
// keeps its reason and path.
|
|
70
|
+
let root = options.rootPath;
|
|
71
|
+
try {
|
|
72
|
+
root = await realpath(options.rootPath);
|
|
73
|
+
const target = relative(root, await realpath(options.targetPath))
|
|
74
|
+
.split(sep)
|
|
75
|
+
.join("/");
|
|
76
|
+
const view = new FilesystemTreeView(root, options.signal);
|
|
77
|
+
const { roots: requested, unclassified } = parsed.data.roots !== undefined
|
|
78
|
+
? { roots: parsed.data.roots, unclassified: [] }
|
|
79
|
+
: options.enumerateRoots
|
|
80
|
+
? await executableRoots(root, view, options.signal)
|
|
81
|
+
: { roots: [target], unclassified: [] };
|
|
82
|
+
const roots = await requireMachoRoots(view, requested);
|
|
83
|
+
const trace = await traceDylibLoading(view, {
|
|
84
|
+
roots,
|
|
85
|
+
unclassified,
|
|
86
|
+
...(parsed.data.architecture === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: { architecture: parsed.data.architecture }),
|
|
89
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
90
|
+
});
|
|
91
|
+
// Each digest must describe the same file whose headers were parsed.
|
|
92
|
+
const digests = new Map();
|
|
93
|
+
for (const { path } of trace.images)
|
|
94
|
+
digests.set(path, await fileSha256(join(root, path), {
|
|
95
|
+
path,
|
|
96
|
+
expected: view.identity(path),
|
|
97
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
98
|
+
}));
|
|
99
|
+
const targetDigest = digests.get(target) ??
|
|
100
|
+
(await fileSha256(join(root, target), {
|
|
101
|
+
path: target,
|
|
102
|
+
expected: undefined,
|
|
103
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
104
|
+
}));
|
|
105
|
+
if (targetDigest !== options.targetSha256)
|
|
106
|
+
throw new ArtifactReaderFailure("integrity", `Active target digest changed: expected ${options.targetSha256}, observed ${targetDigest}`);
|
|
107
|
+
return dylibResolutionResultSchema.parse({
|
|
108
|
+
...trace,
|
|
109
|
+
root_path: options.rootPath,
|
|
110
|
+
target_sha256: options.targetSha256,
|
|
111
|
+
images: trace.images.map((image) => ({
|
|
112
|
+
...image,
|
|
113
|
+
sha256: digests.get(image.path),
|
|
114
|
+
})),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (cause) {
|
|
118
|
+
if (options.signal?.aborted === true)
|
|
119
|
+
throw new ArtifactReaderFailure("cancelled", "Dylib resolution was cancelled", { cause });
|
|
120
|
+
const denied = permissionDenied(cause);
|
|
121
|
+
if (denied !== undefined)
|
|
122
|
+
throw new ArtifactReaderFailure("unavailable", `Permission denied (${denied.code}) reading ${deniedPath(root, denied.path)}`, { cause });
|
|
123
|
+
throw cause;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Every Mach-O in the bundle with an executable slice is its own process root.
|
|
128
|
+
* Mach-O files that do not parse are returned separately: whether they are
|
|
129
|
+
* executables is unknown, so they make coverage partial instead of vanishing.
|
|
130
|
+
*/
|
|
131
|
+
const executableRoots = async (root, view, signal) => {
|
|
132
|
+
const roots = [];
|
|
133
|
+
const unclassified = [];
|
|
134
|
+
for await (const entry of new DirectoryArtifactReader(root).entries(signal)) {
|
|
135
|
+
if (entry.kind !== "file" ||
|
|
136
|
+
!(await startsWithMachoMagic(entry.adapterKey)))
|
|
137
|
+
continue;
|
|
138
|
+
const facts = await view.image(entry.path);
|
|
139
|
+
if (facts.status === "malformed" || facts.status === "unsupported")
|
|
140
|
+
unclassified.push(entry.path);
|
|
141
|
+
else if (facts.status === "parsed" &&
|
|
142
|
+
facts.slices.some(({ file_type: type }) => type === "execute"))
|
|
143
|
+
roots.push(entry.path);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
roots: roots.sort(compare),
|
|
147
|
+
unclassified: unclassified.sort(compare),
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
151
|
+
/**
|
|
152
|
+
* Resolve each root segment by segment, as dependency candidates are, so a
|
|
153
|
+
* symlink in an intermediate directory cannot lead outside the analyzed root.
|
|
154
|
+
*/
|
|
155
|
+
const requireMachoRoots = async (view, roots) => {
|
|
156
|
+
const resolved = [];
|
|
157
|
+
for (const path of roots) {
|
|
158
|
+
const lookup = await resolveTreePath(view, path);
|
|
159
|
+
if (lookup.kind === "escapes")
|
|
160
|
+
throw new ArtifactReaderFailure("path", `Root ${path} resolves outside the analyzed root`);
|
|
161
|
+
if (lookup.kind !== "file")
|
|
162
|
+
throw new ArtifactReaderFailure("path", `Root ${path} is not a regular file in the analyzed root`);
|
|
163
|
+
if ((await view.image(lookup.path)).status === "not-mach-o")
|
|
164
|
+
throw new ArtifactReaderFailure("format", `Root ${path} is not a Mach-O image`);
|
|
165
|
+
if (!resolved.includes(lookup.path))
|
|
166
|
+
resolved.push(lookup.path);
|
|
167
|
+
}
|
|
168
|
+
return resolved;
|
|
169
|
+
};
|
|
170
|
+
const startsWithMachoMagic = async (path) => {
|
|
171
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
172
|
+
try {
|
|
173
|
+
const buffer = new Uint8Array(4);
|
|
174
|
+
const { bytesRead } = await handle.read(buffer, 0, 4, 0);
|
|
175
|
+
return hasMachoMagic(buffer.subarray(0, bytesRead));
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
await handle.close();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const identityOf = (metadata) => [
|
|
182
|
+
metadata.dev,
|
|
183
|
+
metadata.ino,
|
|
184
|
+
metadata.size,
|
|
185
|
+
metadata.mtimeNs,
|
|
186
|
+
metadata.ctimeNs,
|
|
187
|
+
].join(":");
|
|
188
|
+
const readImage = async (path, signal) => {
|
|
189
|
+
cancelled(signal);
|
|
190
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
191
|
+
try {
|
|
192
|
+
const metadata = await handle.stat({ bigint: true });
|
|
193
|
+
const size = Number(metadata.size);
|
|
194
|
+
const facts = await readMachoImage(async (offset, length) => {
|
|
195
|
+
cancelled(signal);
|
|
196
|
+
const buffer = new Uint8Array(Math.max(0, Math.min(length, size - offset)));
|
|
197
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, offset);
|
|
198
|
+
return buffer.subarray(0, bytesRead);
|
|
199
|
+
}, size);
|
|
200
|
+
return { facts, identity: identityOf(metadata) };
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
await handle.close();
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
/** Hash a file, failing if it is not the file (or the version) that was parsed. */
|
|
207
|
+
const fileSha256 = async (absolute, options) => {
|
|
208
|
+
const { signal } = options;
|
|
209
|
+
const handle = await open(absolute, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
210
|
+
const unchanged = async () => {
|
|
211
|
+
if (options.expected !== undefined &&
|
|
212
|
+
identityOf(await handle.stat({ bigint: true })) !== options.expected)
|
|
213
|
+
throw new ArtifactReaderFailure("integrity", `${options.path} changed while its dyld load commands were traced`);
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
await unchanged();
|
|
217
|
+
const hash = createHash("sha256");
|
|
218
|
+
const buffer = new Uint8Array(HASH_CHUNK_BYTES);
|
|
219
|
+
for (;;) {
|
|
220
|
+
cancelled(signal);
|
|
221
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
|
|
222
|
+
if (bytesRead === 0)
|
|
223
|
+
break;
|
|
224
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
225
|
+
}
|
|
226
|
+
await unchanged();
|
|
227
|
+
return hash.digest("hex");
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
await handle.close();
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const cancelled = (signal) => {
|
|
234
|
+
if (signal?.aborted === true)
|
|
235
|
+
throw new ArtifactReaderFailure("cancelled", "Dylib resolution was cancelled");
|
|
236
|
+
};
|
|
237
|
+
/** A denied path relative to the analyzed root, or absolute when outside it. */
|
|
238
|
+
const deniedPath = (root, path) => {
|
|
239
|
+
if (path === undefined)
|
|
240
|
+
return "a file in the analyzed root";
|
|
241
|
+
const inside = relative(root, path);
|
|
242
|
+
return inside === "" || inside.startsWith("..") ? path : inside;
|
|
243
|
+
};
|
|
244
|
+
/** Host permission denials, kept distinct from malformed or missing files. */
|
|
245
|
+
const permissionDenied = (cause) => {
|
|
246
|
+
if (!(cause instanceof Error) || !("code" in cause))
|
|
247
|
+
return undefined;
|
|
248
|
+
if (cause.code !== "EACCES" && cause.code !== "EPERM")
|
|
249
|
+
return undefined;
|
|
250
|
+
return {
|
|
251
|
+
code: cause.code,
|
|
252
|
+
path: "path" in cause && typeof cause.path === "string"
|
|
253
|
+
? cause.path
|
|
254
|
+
: undefined,
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
const missing = (cause) => cause instanceof Error &&
|
|
258
|
+
"code" in cause &&
|
|
259
|
+
(cause.code === "ENOENT" || cause.code === "ENOTDIR");
|