rea-agents 6.0.0 → 6.1.0

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