rea-agents 4.0.1 → 4.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 (416) hide show
  1. package/README.md +93 -30
  2. package/bridge/ghidra/ReaGhidraBridge.java +358 -15
  3. package/bridge/ghidra/ReaGhidraExtensions.java +113 -0
  4. package/bridge/ghidra/ReaGhidraPrepareCom.java +32 -0
  5. package/dist/android/AndroidTargetSnapshot.js +34 -0
  6. package/dist/android/JadxAnalysis.js +191 -0
  7. package/dist/android/JadxConfiguration.js +41 -0
  8. package/dist/android/JadxMcpTransport.js +145 -0
  9. package/dist/android/JadxProtocol.js +101 -0
  10. package/dist/android/JadxProvider.js +170 -0
  11. package/dist/android/JadxRelease.js +19 -0
  12. package/dist/android/JadxSession.js +97 -0
  13. package/dist/application/AnalysisContextQueries.js +2 -1
  14. package/dist/application/AnalysisProviderEvaluation.js +5 -3
  15. package/dist/application/AnalysisProviderRegistry.js +2 -1
  16. package/dist/application/AnalysisSnapshotCache.js +4 -1
  17. package/dist/application/AnalysisSnapshotFiles.js +1 -1
  18. package/dist/application/AndroidAnalysisPort.js +1 -0
  19. package/dist/application/AndroidAnalysisService.js +37 -0
  20. package/dist/application/ArtifactExtraction.js +7 -4
  21. package/dist/application/ArtifactGraphConstruction.js +10 -17
  22. package/dist/application/ArtifactInventory/scanCanonical.js +8 -7
  23. package/dist/application/BinarySession.js +16 -3
  24. package/dist/application/BinarySessionExecution.js +4 -1
  25. package/dist/application/BinarySessionOpen.js +3 -2
  26. package/dist/application/BinarySessionRecords.js +9 -3
  27. package/dist/application/BinaryTargetResolver.js +25 -6
  28. package/dist/application/BrowserObservationService.js +2 -1
  29. package/dist/application/BrowserScenarioCaptureService.js +2 -1
  30. package/dist/application/BrowserScenarioEvidence.js +2 -2
  31. package/dist/application/CallPathTracing.js +2 -1
  32. package/dist/application/CapabilityInventory.js +18 -0
  33. package/dist/application/ClientConfigPath.js +3 -1
  34. package/dist/application/ClientConfigurationDocument.js +11 -1
  35. package/dist/application/ClientRegistrationStatus.js +8 -1
  36. package/dist/application/CompositeProvider.js +1 -1
  37. package/dist/application/DirectAnalysis.js +23 -7
  38. package/dist/application/DirectAnalysisStatus.js +3 -3
  39. package/dist/application/Doctor.js +48 -8
  40. package/dist/application/DoctorDiagnostics.js +7 -5
  41. package/dist/application/DoctorScope.js +1 -1
  42. package/dist/application/ElectronActiveEvidence.js +2 -2
  43. package/dist/application/ElectronActiveObservationService.js +2 -1
  44. package/dist/application/ElectronBoundaryAnalysis.js +1 -1
  45. package/dist/application/ElectronObservationService.js +2 -1
  46. package/dist/application/EnhancedLiteralTracing.js +2 -1
  47. package/dist/application/EnhancedToolTypes.js +2 -1
  48. package/dist/application/EnhancedTools.js +3 -1
  49. package/dist/application/EvidenceBundleCommands.js +2 -1
  50. package/dist/application/EvidenceBundleFiles.js +1 -1
  51. package/dist/application/EvidenceInputResolver.js +30 -0
  52. package/dist/application/EvidenceLedger.js +2 -1
  53. package/dist/application/FirmwareAnalysisPort.js +1 -0
  54. package/dist/application/FirmwareAnalysisService.js +35 -0
  55. package/dist/application/FunctionAnalysisEvidence.js +32 -0
  56. package/dist/application/InventoryProjectionEvidence.js +2 -1
  57. package/dist/application/JavaScriptApplicationService.js +50 -3
  58. package/dist/application/JavaScriptApplicationWorkflowService.js +2 -1
  59. package/dist/application/JavaScriptArtifactAnalysis.js +4 -2
  60. package/dist/application/JavaScriptArtifactFiles.js +4 -2
  61. package/dist/application/JavaScriptArtifactPathResolution.js +6 -2
  62. package/dist/application/JavaScriptJsonModules.js +3 -2
  63. package/dist/application/JavaScriptModuleRelationships.js +4 -2
  64. package/dist/application/JavaScriptRuntimeObservationService.js +2 -1
  65. package/dist/application/JavaScriptRuntimeReconciliationService.js +2 -1
  66. package/dist/application/JavaScriptSemanticGraphProjection.js +1 -1
  67. package/dist/application/JavaScriptSemanticTraceService.js +2 -1
  68. package/dist/application/JsonFiles.js +1 -1
  69. package/dist/application/LazyAnalysisProvider.js +3 -1
  70. package/dist/application/LinuxHopper.js +12 -4
  71. package/dist/application/MacHopper.js +20 -7
  72. package/dist/application/ManagedApplicationGraphService.js +2 -1
  73. package/dist/application/ManagedMemberComparisonService.js +3 -1
  74. package/dist/application/ManagedNativeVerificationService.js +2 -1
  75. package/dist/application/ManagedReconstructionService.js +2 -1
  76. package/dist/application/NativeCallRoutes.js +1 -1
  77. package/dist/application/NativeDispatchMetadataInspection.js +1 -1
  78. package/dist/application/NativeUiActionTrace.js +2 -1
  79. package/dist/application/NativeValueTrace.js +1 -1
  80. package/dist/application/ProcessCaptureError.js +1 -1
  81. package/dist/application/ProcessCaptureJournal.js +3 -1
  82. package/dist/application/ProcessCaptureLifecycle.js +6 -3
  83. package/dist/application/ProcessCli.js +9 -5
  84. package/dist/application/ProcessEvidence.js +2 -6
  85. package/dist/application/ProcessHarness.js +3 -2
  86. package/dist/application/ProcessNormalization.js +12 -5
  87. package/dist/application/ProcessSampling.js +3 -1
  88. package/dist/application/ReconstructionCoverageService.js +2 -1
  89. package/dist/application/ReconstructionObligationLedgerService.js +2 -1
  90. package/dist/application/ReferenceSourceImportEntries.js +2 -0
  91. package/dist/application/ReferenceSourceImportPolicy.js +4 -2
  92. package/dist/application/ReferenceSourceVcsAdapter.js +35 -4
  93. package/dist/application/SessionProviderRouter.js +4 -1
  94. package/dist/application/Setup.js +1 -128
  95. package/dist/application/SetupClientConfiguration.js +17 -6
  96. package/dist/application/SetupHost.js +111 -0
  97. package/dist/application/SetupRegistrationEnvironment.js +1 -2
  98. package/dist/application/SetupSkill.js +9 -3
  99. package/dist/application/SetupTypes.js +17 -0
  100. package/dist/application/StoreFileLock.js +7 -2
  101. package/dist/application/SupportedClients.js +8 -0
  102. package/dist/application/Uninstall.js +9 -4
  103. package/dist/application/UpdateRuntime.js +5 -2
  104. package/dist/application/WindowsCapabilities.js +7 -7
  105. package/dist/application/runtime.js +3 -1
  106. package/dist/artifacts/ArtifactProvider.js +3 -1
  107. package/dist/artifacts/DirectoryArtifactReader.js +2 -0
  108. package/dist/artifacts/NativeDmgArtifactReader.js +10 -3
  109. package/dist/artifacts/NibArchive.js +4 -2
  110. package/dist/artifacts/SafeOutputTree.js +26 -10
  111. package/dist/artifacts/ZipArtifactReader.js +1 -0
  112. package/dist/browser/BrowserProcessStartup.js +3 -1
  113. package/dist/browser/CdpAuthorizedMainFrame.js +1 -1
  114. package/dist/browser/CdpBrowserProvider.js +4 -1
  115. package/dist/browser/CdpCaptureDocuments.js +3 -1
  116. package/dist/browser/CdpCaptureEventHandlers.js +6 -2
  117. package/dist/browser/CdpCaptureStorageFingerprints.js +1 -1
  118. package/dist/browser/CdpCaptureValues.js +6 -2
  119. package/dist/browser/CdpConnection.js +8 -6
  120. package/dist/browser/CdpElectronInspection.js +3 -3
  121. package/dist/browser/CdpElectronProvider.js +4 -1
  122. package/dist/browser/CdpElectronScripts.js +2 -2
  123. package/dist/browser/CdpEndpoint.js +22 -10
  124. package/dist/browser/CdpObservationSession.js +2 -1
  125. package/dist/browser/CdpOptionalCommand.js +1 -1
  126. package/dist/browser/CdpPageCapture.js +2 -1
  127. package/dist/browser/CdpSafeMetadata.js +53 -8
  128. package/dist/browser/CdpScreenshot.js +1 -1
  129. package/dist/browser/CdpTargetSession.js +8 -5
  130. package/dist/browser/CdpWebMcpDiscovery.js +1 -1
  131. package/dist/browser/ElectronFileScope.js +9 -3
  132. package/dist/browser/JavaScriptRuntimeScope.js +3 -1
  133. package/dist/browser/PlaywrightBrowserScenarioProvider.js +3 -1
  134. package/dist/browser/PlaywrightElectronActiveActions.js +1 -1
  135. package/dist/browser/PlaywrightElectronActiveProvider.js +6 -2
  136. package/dist/browser/PlaywrightExecutionBoundary.js +1 -1
  137. package/dist/browser/PlaywrightScenarioArtifacts.js +10 -5
  138. package/dist/browser/PlaywrightScenarioBrowser.js +3 -1
  139. package/dist/browser/PlaywrightScenarioEvents.js +6 -2
  140. package/dist/browser/PlaywrightScenarioSession.js +5 -2
  141. package/dist/browser/V8InspectorEndpoint.js +2 -1
  142. package/dist/browser/V8InspectorProvider.js +6 -1
  143. package/dist/browser/WebSourceMapFetcher.js +24 -11
  144. package/dist/cli/androidCommands.js +81 -0
  145. package/dist/{cliApplicationCommands.js → cli/applicationCommands.js} +18 -16
  146. package/dist/{cliBrowserAdvancedCommands.js → cli/browserAdvancedCommands.js} +13 -16
  147. package/dist/{cliBrowserCommands.js → cli/browserCommands.js} +9 -9
  148. package/dist/cli/commandCancellation.js +24 -0
  149. package/dist/cli/coreAnalysisCommands.js +110 -17
  150. package/dist/{cliElectronCommands.js → cli/electronCommands.js} +14 -13
  151. package/dist/cli/firmwareCommands.js +75 -0
  152. package/dist/{cliSetup.js → cli/interactiveSetup.js} +1 -1
  153. package/dist/cli/javascriptApplicationAnalysis.js +1 -1
  154. package/dist/cli/managedCommands.js +1 -1
  155. package/dist/cli/managedProjectGraphCommand.js +1 -1
  156. package/dist/cli/options.js +7 -1
  157. package/dist/{cliProcessCommands.js → cli/processCommands.js} +3 -3
  158. package/dist/cli/referenceSourceImportStatus.js +10 -0
  159. package/dist/cli/setupCommands.js +4 -2
  160. package/dist/cli/utilityCommands.js +3 -2
  161. package/dist/cli.js +10 -15
  162. package/dist/cliBrowserContext.js +1 -1
  163. package/dist/cliBrowserScenarioCommands.js +2 -1
  164. package/dist/cliCommandNames.js +11 -2
  165. package/dist/cliEvidenceCommands.js +2 -1
  166. package/dist/cliJavaScriptRuntimeCommands.js +2 -1
  167. package/dist/cliJsonInput.js +26 -11
  168. package/dist/cliLogging.js +2 -1
  169. package/dist/cliOutput.js +15 -16
  170. package/dist/config/environment.js +11 -1
  171. package/dist/config/parseConfig.js +7 -1
  172. package/dist/config/parsers.js +1 -1
  173. package/dist/contracts/androidToolContracts.js +77 -0
  174. package/dist/contracts/applicationToolContracts.js +32 -5
  175. package/dist/contracts/applicationWorkflowInputContracts.js +13 -13
  176. package/dist/contracts/artifactComparisonExample.js +7 -14
  177. package/dist/contracts/enhancedToolContracts.js +31 -0
  178. package/dist/contracts/errorSchemas.js +4 -2
  179. package/dist/contracts/evidenceInputContracts.js +13 -0
  180. package/dist/contracts/firmwareToolContracts.js +38 -0
  181. package/dist/contracts/officialToolContracts.js +66 -0
  182. package/dist/contracts/promptContracts.js +1 -1
  183. package/dist/contracts/sessionLifecycleInputs.js +4 -0
  184. package/dist/contracts/sessionToolContracts.js +43 -0
  185. package/dist/contracts/sessionToolSchemas.js +1 -1
  186. package/dist/contracts/toolContractExamples.js +5 -0
  187. package/dist/contracts/toolContractTypes.js +2 -0
  188. package/dist/contracts/toolContracts.js +7 -130
  189. package/dist/contracts/toolEffects.js +43 -0
  190. package/dist/contracts/toolOutputSchemaGroups.js +4 -0
  191. package/dist/contracts/toolOutputSchemaPrimitives.js +1 -0
  192. package/dist/doctorRuntime.js +5 -1
  193. package/dist/domain/analysisErrorBase.js +33 -0
  194. package/dist/domain/analysisErrorCore.js +60 -0
  195. package/dist/domain/analysisErrorPresentation.js +22 -2
  196. package/dist/domain/analysisErrorProjection.js +24 -3
  197. package/dist/domain/analysisSnapshot.js +1 -0
  198. package/dist/domain/androidAnalysis.js +141 -0
  199. package/dist/domain/appleAssetCatalog.js +1 -1
  200. package/dist/domain/artifactGraph.js +1 -0
  201. package/dist/domain/artifactInspection.js +19 -17
  202. package/dist/domain/artifactInventoryEvidence.js +20 -25
  203. package/dist/domain/artifactOperationError.js +16 -0
  204. package/dist/domain/browserObservation.js +12 -4
  205. package/dist/domain/browserObservationError.js +23 -0
  206. package/dist/domain/browserScenario.js +1 -1
  207. package/dist/domain/browserScenarioCapture.js +1 -1
  208. package/dist/domain/browserScenarioDiff.js +1 -1
  209. package/dist/domain/browserScenarioNormalization.js +6 -11
  210. package/dist/domain/browserScenarioValues.js +3 -1
  211. package/dist/domain/callPath.js +47 -7
  212. package/dist/domain/canonicalDigest.js +65 -0
  213. package/dist/domain/canonicalOrdering.js +11 -0
  214. package/dist/domain/changedBehavior.js +8 -7
  215. package/dist/domain/comparisonSemantics.js +2 -4
  216. package/dist/domain/configurationErrors.js +25 -0
  217. package/dist/domain/dosCom.js +8 -0
  218. package/dist/domain/electronActiveObservation.js +3 -1
  219. package/dist/domain/electronStaticAnalysisBrowser.js +13 -23
  220. package/dist/domain/electronStaticAnalysisNative.js +2 -1
  221. package/dist/domain/electronStaticAnalysisValues.js +23 -3
  222. package/dist/domain/evidence.js +3 -11
  223. package/dist/domain/evidenceErrors.js +30 -0
  224. package/dist/domain/firmwareAnalysis.js +121 -0
  225. package/dist/domain/functionComparison.js +4 -2
  226. package/dist/domain/functionComparisonDimensions.js +6 -4
  227. package/dist/domain/functionComparisonNormalization.js +8 -1
  228. package/dist/domain/functionComparisonResults.js +1 -4
  229. package/dist/domain/hopperErrors.js +78 -0
  230. package/dist/domain/hopperValues.js +2 -1
  231. package/dist/domain/interfaceBuilderGraph.js +3 -1
  232. package/dist/domain/javascriptApplicationChangeGraph.js +2 -2
  233. package/dist/domain/javascriptApplicationGraph.js +13 -22
  234. package/dist/domain/javascriptApplicationVersionComparison.js +3 -11
  235. package/dist/domain/javascriptApplicationVersionItems.js +3 -3
  236. package/dist/domain/javascriptApplicationVersionKeys.js +1 -1
  237. package/dist/domain/javascriptAstFingerprint.js +1 -1
  238. package/dist/domain/javascriptExportShapeComparison.js +1 -2
  239. package/dist/domain/javascriptExportShapeSelection.js +1 -1
  240. package/dist/domain/javascriptExportShapeVariants.js +7 -3
  241. package/dist/domain/javascriptFeatureSeed.js +29 -9
  242. package/dist/domain/javascriptFeatureTrace.js +9 -13
  243. package/dist/domain/javascriptFeatureTraversal.js +2 -1
  244. package/dist/domain/javascriptNativeHandoff.js +2 -1
  245. package/dist/domain/javascriptRuntimeLoadState.js +2 -2
  246. package/dist/domain/javascriptRuntimeReconciliationActive.js +3 -10
  247. package/dist/domain/javascriptRuntimeReconciliationGraph.js +2 -2
  248. package/dist/domain/javascriptRuntimeReconciliationMatching.js +4 -3
  249. package/dist/domain/javascriptRuntimeReconciliationParsing.js +8 -14
  250. package/dist/domain/javascriptRuntimeReconciliationResult.js +4 -4
  251. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +5 -2
  252. package/dist/domain/javascriptRuntimeStaticCandidates.js +8 -4
  253. package/dist/domain/javascriptSemanticAnalysis.js +40 -3
  254. package/dist/domain/javascriptSemanticCallResolution.js +2 -1
  255. package/dist/domain/javascriptSemanticChildProcesses.js +2 -1
  256. package/dist/domain/javascriptSemanticDataEffects.js +2 -1
  257. package/dist/domain/javascriptSemanticFingerprints.js +1 -1
  258. package/dist/domain/javascriptSemanticGraph.js +23 -28
  259. package/dist/domain/javascriptSemanticPrimitives.js +9 -2
  260. package/dist/domain/javascriptSemanticProjection.js +2 -1
  261. package/dist/domain/javascriptSemanticPromises.js +2 -1
  262. package/dist/domain/javascriptSemanticProvenance.js +1 -1
  263. package/dist/domain/javascriptSemanticQuery.js +7 -8
  264. package/dist/domain/javascriptSemanticQueryAssessment.js +1 -2
  265. package/dist/domain/javascriptSemanticQueryIdentity.js +1 -2
  266. package/dist/domain/javascriptSemanticReturns.js +2 -1
  267. package/dist/domain/javascriptSemanticValues.js +50 -16
  268. package/dist/domain/javascriptSourceParser.js +4 -2
  269. package/dist/domain/javascriptStaticAnalysis.js +1 -1
  270. package/dist/domain/javascriptStaticAnalysisBundler.js +2 -1
  271. package/dist/domain/javascriptStaticAnalysisCalls.js +14 -6
  272. package/dist/domain/javascriptStaticAnalysisHelpers.js +31 -4
  273. package/dist/domain/jsonShape.js +6 -2
  274. package/dist/domain/managedMemberComparison.js +1 -0
  275. package/dist/domain/managedMemberComparisonItems.js +2 -0
  276. package/dist/domain/managedNativeVerificationMatch.js +5 -3
  277. package/dist/domain/nativeDataType.js +2 -0
  278. package/dist/domain/nativeFunctionAnnotations.js +43 -0
  279. package/dist/domain/nativeLoadImage.js +95 -0
  280. package/dist/domain/nativeMetadataRecovery.js +55 -0
  281. package/dist/domain/processCapture.js +0 -1
  282. package/dist/domain/processEvidenceProvider.js +11 -0
  283. package/dist/domain/processTraceComparison.js +1 -1
  284. package/dist/domain/providerAdapterError.js +17 -0
  285. package/dist/domain/providerCleanupError.js +1 -1
  286. package/dist/domain/providerSelectionError.js +44 -0
  287. package/dist/domain/reconstructionUnknowns.js +1 -1
  288. package/dist/domain/reconstructionVerification.js +22 -8
  289. package/dist/domain/referenceSourceClassification.js +5 -6
  290. package/dist/domain/referenceSourceGraph.js +9 -17
  291. package/dist/domain/referenceSourceImportParsing.js +38 -23
  292. package/dist/domain/runtimeIdentification.js +1 -1
  293. package/dist/domain/runtimeVersion.js +4 -7
  294. package/dist/domain/safeJson.js +13 -0
  295. package/dist/domain/sourceToBundleComparison.js +5 -7
  296. package/dist/domain/sourceToBundleSignals.js +6 -6
  297. package/dist/domain/staticRuntimeCorrelation.js +9 -7
  298. package/dist/domain/unknownRegistryError.js +10 -0
  299. package/dist/domain/webBundleAnalyzerAst.js +22 -5
  300. package/dist/domain/webBundleAnalyzerInspection.js +20 -14
  301. package/dist/dotnet/ManagedMemberRows.js +1 -1
  302. package/dist/dotnet/ManagedMetadataHeaps.js +3 -2
  303. package/dist/dotnet/ManagedMetadataInventoryRows.js +4 -2
  304. package/dist/dotnet/ManagedMethodBodyReader.js +8 -1
  305. package/dist/dotnet/ManagedStaticProvider.js +3 -1
  306. package/dist/firmware/FirmwareCommand.js +163 -0
  307. package/dist/firmware/FirmwareFiles.js +190 -0
  308. package/dist/firmware/FirmwareProvider.js +258 -0
  309. package/dist/firmware/FirmwarePublication.js +84 -0
  310. package/dist/firmware/FirmwareRelease.js +32 -0
  311. package/dist/firmware/FirmwareReports.js +223 -0
  312. package/dist/generatedMcpToolCatalog.js +1 -1
  313. package/dist/generatedPackageMetadata.js +5 -5
  314. package/dist/ghidra/GhidraAnalysisProfile.js +37 -8
  315. package/dist/ghidra/GhidraClient.js +52 -6
  316. package/dist/ghidra/GhidraDiagnostics.js +3 -0
  317. package/dist/ghidra/GhidraDoctor.js +38 -14
  318. package/dist/ghidra/GhidraFunctionValues.js +10 -4
  319. package/dist/ghidra/GhidraInstallation.js +10 -4
  320. package/dist/ghidra/GhidraInventoryValues.js +39 -2
  321. package/dist/ghidra/GhidraLauncher.js +91 -26
  322. package/dist/ghidra/GhidraLoadImageValues.js +199 -0
  323. package/dist/ghidra/GhidraProvider.js +129 -13
  324. package/dist/ghidra/GhidraProviderCapabilities.js +52 -15
  325. package/dist/ghidra/GhidraRequestQueue.js +2 -2
  326. package/dist/ghidra/GhidraSessionError.js +31 -4
  327. package/dist/ghidra/GhidraSessionValues.js +10 -7
  328. package/dist/ghidra/GhidraTargetSnapshot.js +16 -2
  329. package/dist/ghidra/GhidraTransport.js +12 -0
  330. package/dist/ghidra/extensions/GhidraExtensionFailures.js +20 -0
  331. package/dist/ghidra/extensions/GhidraExtensions.js +170 -0
  332. package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +21 -0
  333. package/dist/ghidra/extensions/nativeaot/NativeAotReport.js +84 -0
  334. package/dist/hopper/BridgeLauncher.js +4 -2
  335. package/dist/hopper/HopperAnalysisProfile.js +7 -2
  336. package/dist/hopper/HopperCleanup.js +55 -9
  337. package/dist/hopper/HopperClient.js +14 -4
  338. package/dist/hopper/HopperProcessDiagnostic.js +1 -1
  339. package/dist/hopper/HopperProvider.js +8 -4
  340. package/dist/hopper/HopperRequestQueue.js +7 -3
  341. package/dist/hopper/HopperSessionValues.js +1 -1
  342. package/dist/hopper/HopperSocketConnection.js +1 -1
  343. package/dist/hopper/HopperTargetLease.js +23 -15
  344. package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +7 -8
  345. package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -2
  346. package/dist/hopper/protocol.js +8 -8
  347. package/dist/ida/IdaConfiguration.js +56 -0
  348. package/dist/ida/IdaDoctor.js +53 -0
  349. package/dist/ida/IdaInput.js +62 -0
  350. package/dist/ida/IdaMcpConnection.js +111 -0
  351. package/dist/ida/IdaOperationRunner.js +299 -0
  352. package/dist/ida/IdaProtocolValues.js +178 -0
  353. package/dist/ida/IdaProvider.js +126 -0
  354. package/dist/ida/IdaProviderCapabilities.js +60 -0
  355. package/dist/ida/IdaSessionClient.js +306 -0
  356. package/dist/ida/IdaWorkspace.js +54 -0
  357. package/dist/main/shutdown.js +21 -1
  358. package/dist/main/startup.js +1 -1
  359. package/dist/main/transport.js +8 -4
  360. package/dist/main.js +5 -2
  361. package/dist/native/AppleDispatchMetadata.js +31 -10
  362. package/dist/native/NativeMacOSProvider.js +87 -15
  363. package/dist/native/NativeMachoInspection.js +42 -12
  364. package/dist/native/NativeUiHelperRuntime.js +7 -1
  365. package/dist/native/NativeUiObservation.js +6 -2
  366. package/dist/native/parsers/demangle.js +1 -1
  367. package/dist/native/parsers/dyldInfo.js +3 -3
  368. package/dist/native/parsers/otool.js +4 -1
  369. package/dist/native/parsers/plist.js +11 -3
  370. package/dist/process/PrivateRuntimeRoot.js +13 -3
  371. package/dist/process/ProcessOwnership.js +5 -73
  372. package/dist/process/ProcessOwnershipObservation.js +62 -2
  373. package/dist/process/ProcessOwnershipProcessTree.js +13 -0
  374. package/dist/process/ProviderProcess.js +24 -7
  375. package/dist/process/ProviderRunLineage.js +1 -1
  376. package/dist/process/WindowsAuthority.js +20 -1
  377. package/dist/reference/ReferenceSourceReaderEntries.js +5 -1
  378. package/dist/reference/ReferenceSourceReaderFile.js +1 -0
  379. package/dist/server/createServer.js +25 -2
  380. package/dist/server/mcpProgress.js +2 -1
  381. package/dist/server/promptCompletion.js +3 -3
  382. package/dist/server/registerAndroidTools.js +30 -0
  383. package/dist/server/registerApplicationTools/compareExportShapes.js +5 -1
  384. package/dist/server/registerApplicationTools/compareSourceToBundle.js +7 -2
  385. package/dist/server/registerApplicationTools/compareVersions.js +5 -1
  386. package/dist/server/registerApplicationTools/traceFeature.js +7 -2
  387. package/dist/server/registerApplicationTools/traceSemantics.js +7 -2
  388. package/dist/server/registerEnhancedTools.js +28 -1
  389. package/dist/server/registerFirmwareTools.js +22 -0
  390. package/dist/server/registerFunctionComparisonTool.js +1 -1
  391. package/dist/server/registerInvestigationTools/helpers.js +2 -1
  392. package/dist/server/registerManagedTools.js +1 -1
  393. package/dist/server/registerManagedWorkflowTools/evidence.js +1 -1
  394. package/dist/server/registerOfficialTools.js +4 -1
  395. package/dist/server/registerProcessComparisonTool.js +5 -2
  396. package/dist/server/registerSessionTools.js +3 -1
  397. package/dist/server/runDerivedOperation.js +1 -1
  398. package/dist/server/sessionAvailabilityPolicy.js +3 -0
  399. package/dist/server/sessionEvidence.js +1 -1
  400. package/dist/server/toolResult.js +2 -1
  401. package/dist/windows/WindowsNativeLoader.js +108 -0
  402. package/dist/windows/WindowsOwnedProcess.js +168 -0
  403. package/dist/windows/WindowsPrivateRuntime.js +137 -0
  404. package/install.sh +4 -6
  405. package/native/windows/README.md +102 -0
  406. package/native/windows/build/manifest.json +9 -0
  407. package/native/windows/build/rea-windows-x64.node +0 -0
  408. package/package.json +38 -24
  409. package/scripts/rea.mjs +1 -1
  410. package/scripts/verify-windows-native-artifact.mjs +39 -0
  411. package/skills/reverse-engineer-anything/SKILL.md +92 -24
  412. package/skills/reverse-engineer-anything/references/android-applications.md +31 -0
  413. package/skills/reverse-engineer-anything/references/javascript-applications.md +19 -2
  414. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +52 -4
  415. package/dist/browser/CdpCanonicalJsonDigest.js +0 -9
  416. package/dist/domain/errors.js +0 -324
@@ -73,6 +73,11 @@ import ghidra.program.model.listing.Instruction;
73
73
  import ghidra.program.model.listing.InstructionIterator;
74
74
  import ghidra.program.model.listing.Variable;
75
75
  import ghidra.program.model.mem.MemoryBlock;
76
+ import ghidra.program.model.mem.MemoryBlockSourceInfo;
77
+ import ghidra.program.database.mem.FileBytes;
78
+ import ghidra.program.model.address.SegmentedAddress;
79
+ import ghidra.program.model.reloc.Relocation;
80
+ import java.io.ByteArrayOutputStream;
76
81
  import ghidra.program.model.symbol.RefType;
77
82
  import ghidra.program.model.symbol.Reference;
78
83
  import ghidra.program.model.symbol.ReferenceIterator;
@@ -112,6 +117,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
112
117
  "params"
113
118
  );
114
119
  private static final String[] CAPABILITIES = {
120
+ "annotate_native_function",
121
+ "inspect_native_load_image",
122
+ "read_bytes",
123
+ "address_to_file_offset",
115
124
  "ping",
116
125
  "shutdown",
117
126
  "address_name",
@@ -142,6 +151,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
142
151
  private List<FunctionEntry> procedureInventory;
143
152
  private List<InventoryItem> stringInventory;
144
153
  private DecompInterface decompiler;
154
+ private final ReaGhidraExtensions analysisExtensions = new ReaGhidraExtensions();
145
155
  private static AddressSpace sessionDefaultAddressSpace;
146
156
 
147
157
  @Override
@@ -152,12 +162,24 @@ public final class ReaGhidraBridge extends HeadlessScript {
152
162
  }
153
163
  Path descriptorPath = Path.of(arguments[0]);
154
164
  SessionDescriptor descriptor = readDescriptor(descriptorPath);
155
- Files.deleteIfExists(descriptorPath);
165
+ // Windows retains a native immutable bearer descriptor lease until
166
+ // runtime_close; POSIX removes it after this read. Normal cleanup removes
167
+ // the Windows file, while abrupt owner death can leave private residue.
168
+ // Its protected runtime DACL also protects the bearer token while the
169
+ // bridge is running. POSIX keeps its existing consume-and-delete flow.
170
+ if (!isWindowsHost()) {
171
+ Files.deleteIfExists(descriptorPath);
172
+ }
156
173
  if (currentProgram == null) {
157
174
  throw new IllegalStateException("REA bridge requires an imported program");
158
175
  }
159
176
  sessionDefaultAddressSpace =
160
177
  currentProgram.getAddressFactory().getDefaultAddressSpace();
178
+ if (currentProgram.getExecutableFormat().equals("Raw Binary") &&
179
+ !currentProgram.getOptions(ghidra.program.model.listing.Program.PROGRAM_INFO)
180
+ .getBoolean("REA DOS COM prepared", false)) {
181
+ throw new IllegalStateException("REA DOS COM entry/context preparation failed");
182
+ }
161
183
  if (!Application.getApplicationVersion().equals(descriptor.providerVersion)) {
162
184
  throw new IllegalStateException("Ghidra provider version does not match the session");
163
185
  }
@@ -171,7 +193,13 @@ public final class ReaGhidraBridge extends HeadlessScript {
171
193
  "Ghidra imported-byte digest does not match the admitted target"
172
194
  );
173
195
  }
196
+ // GhidraScript wraps run() in a transaction. End it before serving so
197
+ // each edit owns a real outer transaction and can roll back immediately.
198
+ end(true);
174
199
  try {
200
+ if (!descriptor.transport.equals("unix-socket") && descriptor.analysisExtensions.size() > 0)
201
+ throw new IOException("Windows Ghidra P0 does not admit metadata recovery or database mutation.");
202
+ analysisExtensions.analyze(descriptor.analysisExtensions, currentProgram, monitor);
175
203
  initializeDecompiler();
176
204
  serve(descriptor);
177
205
  }
@@ -180,6 +208,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
180
208
  decompiler.dispose();
181
209
  decompiler = null;
182
210
  }
211
+ analysisExtensions.close();
183
212
  }
184
213
  }
185
214
 
@@ -219,18 +248,23 @@ public final class ReaGhidraBridge extends HeadlessScript {
219
248
  JsonObject endpoint = new JsonObject();
220
249
  endpoint.addProperty("host", "127.0.0.1");
221
250
  endpoint.addProperty("port", address.getPort());
251
+ // The Windows native reader refuses a file while a writer still
252
+ // owns it. Closing CREATE_NEW publishes the complete record without
253
+ // requesting rename rights on the retained private directory guard.
222
254
  Files.writeString(
223
- pendingPath,
255
+ isWindowsHost() ? endpointPath : pendingPath,
224
256
  GSON.toJson(endpoint) + "\n",
225
257
  StandardCharsets.UTF_8,
226
258
  StandardOpenOption.CREATE_NEW,
227
259
  StandardOpenOption.WRITE
228
260
  );
229
- try {
230
- Files.move(pendingPath, endpointPath, StandardCopyOption.ATOMIC_MOVE);
231
- }
232
- catch (AtomicMoveNotSupportedException exception) {
233
- Files.move(pendingPath, endpointPath);
261
+ if (!isWindowsHost()) {
262
+ try {
263
+ Files.move(pendingPath, endpointPath, StandardCopyOption.ATOMIC_MOVE);
264
+ }
265
+ catch (AtomicMoveNotSupportedException exception) {
266
+ Files.move(pendingPath, endpointPath);
267
+ }
234
268
  }
235
269
  acceptClient(server, descriptor);
236
270
  }
@@ -240,6 +274,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
240
274
  }
241
275
  }
242
276
 
277
+ private static boolean isWindowsHost() {
278
+ return System.getProperty("os.name", "").startsWith("Windows");
279
+ }
280
+
243
281
  private void acceptClient(
244
282
  ServerSocketChannel server,
245
283
  SessionDescriptor descriptor) throws Exception {
@@ -309,6 +347,9 @@ public final class ReaGhidraBridge extends HeadlessScript {
309
347
  );
310
348
  }
311
349
  return switch (request.method) {
350
+ case "inspect_native_load_image" -> inspectNativeLoadImage(request.params);
351
+ case "read_bytes" -> readMemoryBytes(request.params);
352
+ case "address_to_file_offset" -> addressToFileOffset(request.params);
312
353
  case "address_name" -> addressName(request.params);
313
354
  case "list_documents" -> listDocuments(request.params);
314
355
  case "list_names" -> listNames(request.params);
@@ -331,6 +372,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
331
372
  case "resolve_native_call_targets" -> resolveNativeCallTargets(request.params);
332
373
  case "xrefs" -> xrefs(request.params);
333
374
  case "analyze_function" -> analyzeFunction(request.params);
375
+ case "annotate_native_function" -> {
376
+ if (!descriptor.transport.equals("unix-socket"))
377
+ throw new RequestFailure("method_unavailable", "Windows P0 does not admit database mutation");
378
+ yield annotateNativeFunction(request.params);
379
+ }
334
380
  default -> throw new RequestFailure(
335
381
  "method_unavailable",
336
382
  "Bridge method is unavailable"
@@ -363,11 +409,217 @@ public final class ReaGhidraBridge extends HeadlessScript {
363
409
  result.addProperty("run_id", descriptor.runId);
364
410
  result.addProperty("profile_digest", descriptor.profileDigest);
365
411
  result.add("provider", provider);
366
- result.addProperty("read_only", true);
412
+ boolean readOnly = !descriptor.transport.equals("unix-socket");
413
+ result.addProperty("read_only", readOnly);
367
414
  result.addProperty("analysis_complete", !timedOut);
368
415
  result.addProperty("analysis_timed_out", timedOut);
369
- result.add("capabilities", GSON.toJsonTree(CAPABILITIES));
416
+ result.add("capabilities", GSON.toJsonTree(
417
+ java.util.Arrays.stream(CAPABILITIES)
418
+ .filter(value -> !readOnly || !value.equals("annotate_native_function"))
419
+ .toArray(String[]::new)
420
+ ));
370
421
  result.add("target", target);
422
+ JsonArray extensions = analysisExtensions.reports();
423
+ if (extensions.size() > 0) result.add("analysis_extensions", extensions);
424
+ return result;
425
+ }
426
+
427
+ private static String bytesHex(byte[] bytes) {
428
+ return java.util.HexFormat.of().formatHex(bytes);
429
+ }
430
+
431
+ private String hashFileBytes(FileBytes source, boolean modified) throws Exception {
432
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
433
+ byte[] chunk = new byte[65536];
434
+ for (long offset = 0; offset < source.getSize();) {
435
+ monitor.checkCancelled();
436
+ int length = (int) Math.min(chunk.length, source.getSize() - offset);
437
+ int read = modified
438
+ ? source.getModifiedBytes(offset, chunk, 0, length)
439
+ : source.getOriginalBytes(offset, chunk, 0, length);
440
+ if (read != length) throw new IOException("Incomplete FileBytes read at " + offset);
441
+ digest.update(chunk, 0, read);
442
+ offset += read;
443
+ }
444
+ return bytesHex(digest.digest());
445
+ }
446
+
447
+ private String hashMemory(Address start, long length) throws Exception {
448
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
449
+ byte[] chunk = new byte[65536];
450
+ for (long offset = 0; offset < length;) {
451
+ monitor.checkCancelled();
452
+ int count = (int) Math.min(chunk.length, length - offset);
453
+ int read = currentProgram.getMemory().getBytes(start.add(offset), chunk, 0, count);
454
+ if (read != count) throw new IOException("Incomplete memory read at " + start.add(offset));
455
+ digest.update(chunk, 0, read);
456
+ offset += read;
457
+ }
458
+ return bytesHex(digest.digest());
459
+ }
460
+
461
+ private JsonObject inspectNativeLoadImage(JsonObject params) throws Exception {
462
+ requireKeys(params, Set.of());
463
+ JsonObject result = new JsonObject();
464
+ JsonArray recovery = analysisExtensions.inspectImage();
465
+ if (recovery.size() > 0) result.add("metadata_recovery", recovery);
466
+ result.addProperty("executable_format", currentProgram.getExecutableFormat());
467
+ result.addProperty("language_id", currentProgram.getLanguageID().getIdAsString());
468
+ result.addProperty("compiler_spec_id", currentProgram.getCompilerSpec().getCompilerSpecID().getIdAsString());
469
+ result.addProperty("image_base", canonicalAddress(currentProgram.getImageBase()));
470
+ result.addProperty("default_address_space", sessionDefaultAddressSpace.getName());
471
+ List<FileBytes> files = currentProgram.getMemory().getAllFileBytes();
472
+ JsonArray sources = new JsonArray();
473
+ for (FileBytes file : files) {
474
+ JsonObject source = new JsonObject();
475
+ source.addProperty("name", file.getFilename());
476
+ source.addProperty("size", file.getSize());
477
+ source.addProperty("original_sha256", hashFileBytes(file, false));
478
+ source.addProperty("modified_sha256", hashFileBytes(file, true));
479
+ sources.add(source);
480
+ }
481
+ result.add("source_files", sources);
482
+ JsonArray mappings = new JsonArray();
483
+ for (MemoryBlock block : currentProgram.getMemory().getBlocks()) {
484
+ for (MemoryBlockSourceInfo source : block.getSourceInfos()) {
485
+ monitor.checkCancelled();
486
+ JsonObject mapping = new JsonObject();
487
+ mapping.addProperty("block", block.getName());
488
+ mapping.addProperty("start", canonicalAddress(source.getMinAddress()));
489
+ mapping.addProperty("end", canonicalAddress(source.getMaxAddress()));
490
+ mapping.addProperty("address_space", source.getMinAddress().getAddressSpace().getName());
491
+ mapping.addProperty("initialized", block.isInitialized());
492
+ mapping.addProperty("loaded", block.isLoaded());
493
+ mapping.addProperty("overlay", block.isOverlay());
494
+ mapping.addProperty("length", source.getLength());
495
+ FileBytes backing = source.getFileBytes().orElse(null);
496
+ int sourceIndex = backing == null ? -1 : files.indexOf(backing);
497
+ if (sourceIndex < 0) mapping.add("source_file_index", JsonNull.INSTANCE);
498
+ else mapping.addProperty("source_file_index", sourceIndex);
499
+ long offset = source.getFileBytesOffset();
500
+ if (offset < 0) mapping.add("file_offset", JsonNull.INSTANCE);
501
+ else mapping.addProperty("file_offset", offset);
502
+ if (block.isInitialized()) mapping.addProperty("sha256", hashMemory(source.getMinAddress(), source.getLength()));
503
+ else mapping.add("sha256", JsonNull.INSTANCE);
504
+ mappings.add(mapping);
505
+ }
506
+ }
507
+ result.add("mappings", mappings);
508
+ JsonArray relocations = new JsonArray();
509
+ Iterator<Relocation> iterator = currentProgram.getRelocationTable().getRelocations();
510
+ while (iterator.hasNext()) {
511
+ monitor.checkCancelled();
512
+ Relocation relocation = iterator.next();
513
+ Address location = relocation.getAddress();
514
+ JsonObject row = new JsonObject();
515
+ row.addProperty("address", canonicalAddress(location));
516
+ if (location instanceof SegmentedAddress segmented) {
517
+ row.addProperty("segment", segmented.getSegment());
518
+ row.addProperty("offset", segmented.getSegmentOffset());
519
+ } else {
520
+ row.add("segment", JsonNull.INSTANCE);
521
+ row.add("offset", JsonNull.INSTANCE);
522
+ }
523
+ row.addProperty("status", relocation.getStatus().toString());
524
+ row.addProperty("type", relocation.getType());
525
+ row.add("values", GSON.toJsonTree(relocation.getValues() == null ? new long[0] : relocation.getValues()));
526
+ byte[] original = relocation.getBytes();
527
+ row.add("original_bytes_hex", original == null ? JsonNull.INSTANCE : GSON.toJsonTree(bytesHex(original)));
528
+ if (original != null && original.length > 0) {
529
+ byte[] memory = new byte[original.length];
530
+ int read = currentProgram.getMemory().getBytes(location, memory);
531
+ row.add("memory_bytes_hex", read == memory.length ? GSON.toJsonTree(bytesHex(memory)) : JsonNull.INSTANCE);
532
+ } else row.add("memory_bytes_hex", JsonNull.INSTANCE);
533
+ relocations.add(row);
534
+ }
535
+ result.add("relocations", relocations);
536
+ List<Address> entries = new ArrayList<>();
537
+ var entryIterator = currentProgram.getSymbolTable().getExternalEntryPointIterator();
538
+ while (entryIterator.hasNext()) entries.add(entryIterator.next());
539
+ entries.sort(Address::compareTo);
540
+ JsonArray entryPoints = new JsonArray();
541
+ for (Address entry : entries) entryPoints.add(canonicalAddress(entry));
542
+ result.add("entry_points", entryPoints);
543
+ JsonArray contexts = new JsonArray();
544
+ for (Address entry : entries) {
545
+ JsonObject context = new JsonObject();
546
+ context.addProperty("address", canonicalAddress(entry));
547
+ JsonArray registers = new JsonArray();
548
+ for (String name : new String[] { "CS", "DS", "ES", "SS" }) {
549
+ Register register = currentProgram.getRegister(name);
550
+ if (register == null) continue;
551
+ JsonObject row = new JsonObject();
552
+ row.addProperty("name", name);
553
+ BigInteger value = currentProgram.getProgramContext().getValue(register, entry, false);
554
+ row.add("value_hex", value == null ? JsonNull.INSTANCE : GSON.toJsonTree("0x" + value.toString(16)));
555
+ registers.add(row);
556
+ }
557
+ context.add("registers", registers);
558
+ contexts.add(context);
559
+ }
560
+ result.add("entry_context", contexts);
561
+ return result;
562
+ }
563
+
564
+ private JsonObject readMemoryBytes(JsonObject params) throws Exception {
565
+ requireKeys(params, Set.of("document", "address", "length"));
566
+ requireDocument(params);
567
+ Address start = requireAddress(params, "address");
568
+ JsonElement requested = params.get("length");
569
+ long length;
570
+ try {
571
+ if (requested == null || !requested.isJsonPrimitive() || !requested.getAsJsonPrimitive().isNumber())
572
+ throw new IllegalArgumentException();
573
+ length = requested.getAsBigDecimal().longValueExact();
574
+ if (length < 1 || length > 9007199254740991L) throw new IllegalArgumentException();
575
+ } catch (RuntimeException failure) {
576
+ throw new RequestFailure("invalid_request", "Byte length must be a positive safe integer");
577
+ }
578
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
579
+ byte[] chunk = new byte[65536];
580
+ for (long offset = 0; offset < length;) {
581
+ monitor.checkCancelled();
582
+ Address at;
583
+ try { at = start.addNoWrap(offset); }
584
+ catch (Exception endOfSpace) { break; }
585
+ MemoryBlock block = currentProgram.getMemory().getBlock(at);
586
+ if (block == null || !block.isInitialized()) break;
587
+ int count = (int) Math.min(chunk.length, Math.min(length - offset, block.getEnd().subtract(at) + 1));
588
+ int read = currentProgram.getMemory().getBytes(at, chunk, 0, count);
589
+ bytes.write(chunk, 0, read);
590
+ if (read != count) break;
591
+ offset += read;
592
+ }
593
+ JsonObject result = new JsonObject();
594
+ result.addProperty("address", canonicalAddress(start));
595
+ result.addProperty("requested_bytes", length);
596
+ result.addProperty("returned_bytes", bytes.size());
597
+ result.addProperty("bytes_hex", bytesHex(bytes.toByteArray()));
598
+ result.addProperty("complete", bytes.size() == length);
599
+ return result;
600
+ }
601
+
602
+ private JsonObject addressToFileOffset(JsonObject params) {
603
+ requireKeys(params, Set.of("document", "address"));
604
+ requireDocument(params);
605
+ Address address = requireAddress(params, "address");
606
+ MemoryBlock block = currentProgram.getMemory().getBlock(address);
607
+ if (block == null || !block.isInitialized())
608
+ throw new RequestFailure("invalid_request", "Address has no initialized file-backed memory: " + canonicalAddress(address));
609
+ Long fileOffset = null;
610
+ int mappings = 0;
611
+ for (MemoryBlockSourceInfo source : block.getSourceInfos()) {
612
+ if (!source.contains(address) || source.getFileBytes().isEmpty()) continue;
613
+ long offset = source.getFileBytesOffset(address);
614
+ if (offset < 0) continue;
615
+ fileOffset = offset;
616
+ mappings++;
617
+ }
618
+ if (mappings != 1)
619
+ throw new RequestFailure("invalid_request", "Address has " + mappings + " authoritative source mappings: " + canonicalAddress(address));
620
+ JsonObject result = new JsonObject();
621
+ result.addProperty("address", canonicalAddress(address));
622
+ result.addProperty("file_offset", fileOffset);
371
623
  return result;
372
624
  }
373
625
 
@@ -579,6 +831,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
579
831
  result.addProperty("total_fields", totalFields);
580
832
  result.addProperty("truncated", totalFields > 20_000);
581
833
  result.add("limitations", GSON.toJsonTree(List.of("Layouts are Ghidra data-type database observations; original debug/source authority and flexible-tail semantics are not inferred. Nested and recursive types retain category-path identities for separate inspection.", "At most 20000 fields or enum members are serialized per type to bound provider output. total_fields and truncated report omissions. Enum values preserve Ghidra's signed long representation.")));
834
+ if (type != null) {
835
+ JsonObject metadata = analysisExtensions.inspectDataType(currentProgram, type, address, monitor);
836
+ if (metadata != null) result.add("metadata_recovery", metadata);
837
+ }
582
838
  return result;
583
839
  }
584
840
 
@@ -725,6 +981,90 @@ public final class ReaGhidraBridge extends HeadlessScript {
725
981
  return result;
726
982
  }
727
983
 
984
+ private void invalidateAnalysisCaches() {
985
+ nameInventory = null;
986
+ procedureInventory = null;
987
+ stringInventory = null;
988
+ if (decompiler != null) decompiler.flushCache();
989
+ }
990
+
991
+ private JsonObject annotationReadback(Function function) {
992
+ Address entry = function.getEntryPoint();
993
+ JsonObject value = new JsonObject();
994
+ value.addProperty("address", canonicalAddress(entry));
995
+ value.addProperty("name", procedureName(function));
996
+ value.addProperty("comment", currentProgram.getListing().getComment(CommentType.PRE, entry));
997
+ value.addProperty("inline_comment", currentProgram.getListing().getComment(CommentType.EOL, entry));
998
+ return value;
999
+ }
1000
+
1001
+ private JsonObject annotateNativeFunction(JsonObject params) throws Exception {
1002
+ if (!Set.of("procedure", "name", "comment", "inline_comment").containsAll(params.keySet()))
1003
+ throw new RequestFailure("invalid_request", "Unknown function annotation field");
1004
+ if (!params.has("name") && !params.has("comment") && !params.has("inline_comment"))
1005
+ throw new RequestFailure("invalid_request", "Supply at least one annotation change");
1006
+ Function function = resolveProcedure(requireString(params, "procedure"));
1007
+ Address entry = function.getEntryPoint();
1008
+ if (function.isExternal() || !currentProgram.getMemory().contains(entry))
1009
+ throw new RequestFailure("invalid_request", "Annotations require a local function entry: " + canonicalAddress(entry));
1010
+ int transaction = currentProgram.startTransaction("REA function annotations");
1011
+ boolean commit = false;
1012
+ try {
1013
+ // Validate edits through Ghidra's own setters, including name rules.
1014
+ // A later invalid name must roll back earlier comment writes.
1015
+ for (String field : List.of("comment", "inline_comment")) {
1016
+ if (params.has(field)) {
1017
+ String text = requireText(params, field);
1018
+ CommentType type = field.equals("comment") ? CommentType.PRE : CommentType.EOL;
1019
+ currentProgram.getListing().setComment(entry, type, text.isEmpty() ? null : text);
1020
+ }
1021
+ }
1022
+ if (params.has("name"))
1023
+ function.setName(requireString(params, "name"), SourceType.USER_DEFINED);
1024
+ monitor.checkCancelled();
1025
+ invalidateAnalysisCaches();
1026
+ JsonObject readback = annotationReadback(function);
1027
+ for (String field : List.of("name", "comment", "inline_comment")) {
1028
+ if (!params.has(field)) continue;
1029
+ String requested = requireText(params, field);
1030
+ JsonElement measured = readback.get(field);
1031
+ String expected = !field.equals("name") && requested.isEmpty() ? null : requested;
1032
+ String observed = field.equals("name") ? function.getName() :
1033
+ (measured.isJsonNull() ? null : measured.getAsString());
1034
+ if (!java.util.Objects.equals(expected, observed))
1035
+ throw new RequestFailure("annotation_readback_mismatch", "Annotation readback differs for " + field + " at " + canonicalAddress(entry));
1036
+ }
1037
+ JsonObject query = new JsonObject();
1038
+ query.addProperty("procedure", canonicalAddress(entry));
1039
+ JsonObject result = new JsonObject();
1040
+ result.add("annotations", readback);
1041
+ result.add("dossier", analyzeFunction(query));
1042
+ JsonObject effects = new JsonObject();
1043
+ effects.addProperty("scope", "session-analysis-database");
1044
+ effects.addProperty("source_bytes_modified", false);
1045
+ effects.addProperty("persists_after_close", false);
1046
+ result.add("effects", effects);
1047
+ monitor.checkCancelled();
1048
+ commit = true;
1049
+ return result;
1050
+ }
1051
+ catch (ghidra.util.exception.InvalidInputException | ghidra.util.exception.DuplicateNameException exception) {
1052
+ throw new RequestFailure("invalid_function_name", "Invalid function name at " + canonicalAddress(entry) + ": " + safeMessage(exception));
1053
+ }
1054
+ finally {
1055
+ currentProgram.endTransaction(transaction, commit);
1056
+ // Rollback also invalidates inventory and decompiler views.
1057
+ invalidateAnalysisCaches();
1058
+ }
1059
+ }
1060
+
1061
+ private static String requireText(JsonObject params, String field) {
1062
+ JsonElement value = params.get(field);
1063
+ if (value == null || !value.isJsonPrimitive() || !value.getAsJsonPrimitive().isString())
1064
+ throw new RequestFailure("invalid_request", "Annotation " + field + " must be text");
1065
+ return value.getAsString();
1066
+ }
1067
+
728
1068
  private JsonObject analyzeFunction(JsonObject params) throws Exception {
729
1069
  requireKeys(params, Set.of("procedure"));
730
1070
  Function function = resolveProcedure(requireString(params, "procedure"));
@@ -2724,10 +3064,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
2724
3064
  if (!Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS)) {
2725
3065
  throw new IllegalArgumentException("REA session descriptor is invalid");
2726
3066
  }
2727
- JsonObject object = requireObject(
2728
- JsonParser.parseString(Files.readString(path, StandardCharsets.UTF_8)),
2729
- DESCRIPTOR_KEYS
2730
- );
3067
+ JsonElement parsed = JsonParser.parseString(Files.readString(path, StandardCharsets.UTF_8));
3068
+ Set<String> keys = new HashSet<>(DESCRIPTOR_KEYS);
3069
+ if (parsed.isJsonObject() && parsed.getAsJsonObject().has("analysis_extensions"))
3070
+ keys.add("analysis_extensions");
3071
+ JsonObject object = requireObject(parsed, keys);
2731
3072
  return new SessionDescriptor(
2732
3073
  requireString(object, "transport"),
2733
3074
  requireString(object, "endpoint_path"),
@@ -2735,7 +3076,8 @@ public final class ReaGhidraBridge extends HeadlessScript {
2735
3076
  requireString(object, "run_id"),
2736
3077
  requireSha256(object, "target_sha256"),
2737
3078
  requireString(object, "provider_version"),
2738
- requireString(object, "profile_digest")
3079
+ requireString(object, "profile_digest"),
3080
+ object.has("analysis_extensions") ? object.getAsJsonArray("analysis_extensions") : new JsonArray()
2739
3081
  );
2740
3082
  }
2741
3083
 
@@ -2919,7 +3261,8 @@ public final class ReaGhidraBridge extends HeadlessScript {
2919
3261
  String runId,
2920
3262
  String targetSha256,
2921
3263
  String providerVersion,
2922
- String profileDigest
3264
+ String profileDigest,
3265
+ JsonArray analysisExtensions
2923
3266
  ) {}
2924
3267
  private record Request(int id, String method, JsonObject params) {}
2925
3268
 
@@ -0,0 +1,113 @@
1
+ import com.google.gson.JsonArray;
2
+ import com.google.gson.JsonNull;
3
+ import com.google.gson.JsonObject;
4
+ import ghidra.program.model.address.Address;
5
+ import ghidra.program.model.data.DataType;
6
+ import ghidra.program.model.listing.Program;
7
+ import ghidra.util.exception.CancelledException;
8
+ import ghidra.util.task.TaskMonitor;
9
+ import java.lang.reflect.InvocationTargetException;
10
+ import java.net.URLClassLoader;
11
+ import java.nio.file.Files;
12
+ import java.nio.file.LinkOption;
13
+ import java.nio.file.Path;
14
+ import java.security.MessageDigest;
15
+ import java.util.ArrayList;
16
+ import java.util.List;
17
+
18
+ /** Session-owned extension loading; analyzer algorithms stay behind each adapter ABI. */
19
+ final class ReaGhidraExtensions implements AutoCloseable {
20
+ private record Loaded(URLClassLoader loader, Object instance, String sha256) {}
21
+ private final List<Loaded> loaded = new ArrayList<>();
22
+ private final JsonArray reports = new JsonArray();
23
+
24
+ void analyze(JsonArray descriptors, Program program, TaskMonitor monitor) throws Exception {
25
+ for (var item : descriptors) {
26
+ monitor.checkCancelled();
27
+ JsonObject descriptor = item.getAsJsonObject();
28
+ String id = descriptor.get("id").getAsString();
29
+ String entry = descriptor.get("entry_class").getAsString();
30
+ String digest = descriptor.get("sha256").getAsString();
31
+ JsonObject report = new JsonObject();
32
+ report.addProperty("id", id);
33
+ report.addProperty("sha256", digest);
34
+ URLClassLoader loader = null;
35
+ try {
36
+ if (!id.equals("nativeaot") || !entry.equals("rea.extensions.nativeaot.NativeAotExtension") ||
37
+ descriptor.get("integration_api").getAsInt() != 1)
38
+ throw new IllegalArgumentException("Unregistered Ghidra extension ABI: " + id);
39
+ Path path = Path.of(descriptor.get("path").getAsString());
40
+ if (!path.isAbsolute() || !Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS) || Files.size(path) > 8 * 1024 * 1024)
41
+ throw new IllegalArgumentException("Invalid private extension artifact: " + path);
42
+ String measured = java.util.HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(Files.readAllBytes(path)));
43
+ if (!measured.equals(digest)) throw new IllegalArgumentException("Private extension digest mismatch: " + id);
44
+ loader = new URLClassLoader(new java.net.URL[] { path.toUri().toURL() }, getClass().getClassLoader());
45
+ Class<?> type = Class.forName(entry, true, loader);
46
+ Object instance = type.getConstructor().newInstance();
47
+ Object response = type.getMethod("analyze", Program.class, TaskMonitor.class).invoke(instance, program, monitor);
48
+ if (!(response instanceof JsonObject result)) throw new IllegalArgumentException("Invalid Ghidra extension result: " + id);
49
+ report.addProperty("status", result.get("status").getAsString());
50
+ report.add("reason", result.get("reason").deepCopy());
51
+ report.add("result", result);
52
+ loaded.add(new Loaded(loader, instance, digest));
53
+ loader = null;
54
+ } catch (InvocationTargetException ex) {
55
+ if (ex.getCause() instanceof CancelledException cancelled) throw cancelled;
56
+ failure(report, ex.getCause());
57
+ } catch (Exception | LinkageError ex) {
58
+ failure(report, ex);
59
+ } finally {
60
+ if (loader != null) loader.close();
61
+ }
62
+ reports.add(report);
63
+ }
64
+ }
65
+
66
+ JsonArray reports() { return reports.deepCopy(); }
67
+
68
+ JsonArray inspectImage() throws Exception {
69
+ JsonArray summaries = new JsonArray();
70
+ for (Loaded extension : loaded) {
71
+ Object response = extension.instance.getClass().getMethod("inspectImage").invoke(extension.instance);
72
+ if (!(response instanceof JsonObject summary)) throw new IllegalArgumentException("Invalid extension image summary");
73
+ summary.addProperty("analysis_artifact_sha256", extension.sha256);
74
+ summaries.add(summary);
75
+ }
76
+ return summaries;
77
+ }
78
+
79
+ JsonObject inspectDataType(Program program, DataType type, Address address, TaskMonitor monitor) throws Exception {
80
+ for (Loaded extension : loaded) {
81
+ try {
82
+ Object response = extension.instance.getClass().getMethod("inspectDataType", Program.class, DataType.class, Address.class, TaskMonitor.class)
83
+ .invoke(extension.instance, program, type, address, monitor);
84
+ if (response instanceof JsonObject result) return result;
85
+ if (response != null) throw new IllegalArgumentException("Invalid extension type metadata result");
86
+ } catch (InvocationTargetException ex) {
87
+ if (ex.getCause() instanceof CancelledException cancelled) throw cancelled;
88
+ throw new IllegalStateException("Ghidra extension type inspection failed: " + ex.getCause(), ex.getCause());
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+
94
+ private static void failure(JsonObject report, Throwable ex) {
95
+ String reason = "Extension loading/analysis failed: " + ex;
96
+ if (ex.getCause() != null) reason += "; caused by " + ex.getCause();
97
+ report.addProperty("status", "failed");
98
+ report.addProperty("reason", reason);
99
+ JsonObject result = new JsonObject();
100
+ result.addProperty("loader_failure", reason);
101
+ report.add("result", result);
102
+ }
103
+
104
+ @Override public void close() throws Exception {
105
+ Exception failure = null;
106
+ for (Loaded extension : loaded) {
107
+ try { extension.loader.close(); }
108
+ catch (Exception ex) { if (failure == null) failure = ex; else failure.addSuppressed(ex); }
109
+ }
110
+ loaded.clear();
111
+ if (failure != null) throw failure;
112
+ }
113
+ }
@@ -0,0 +1,32 @@
1
+ import ghidra.app.script.GhidraScript;
2
+ import ghidra.program.model.address.Address;
3
+ import ghidra.program.model.listing.Program;
4
+ import java.math.BigInteger;
5
+
6
+ /** Seed the declared DOS COM analysis context before default auto-analysis. */
7
+ public final class ReaGhidraPrepareCom extends GhidraScript {
8
+ @Override
9
+ public void run() throws Exception {
10
+ if (!currentProgram.getLanguageID().getIdAsString().equals("x86:LE:16:Real Mode") ||
11
+ !currentProgram.getExecutableFormat().equals("Raw Binary")) {
12
+ throw new IllegalArgumentException("DOS COM preparation requires raw x86 real-mode import");
13
+ }
14
+ Address entry = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress("1000:0100");
15
+ Address start = currentProgram.getMinAddress();
16
+ Address end = currentProgram.getMaxAddress();
17
+ if (!entry.equals(start) || end.subtract(start) + 1 > 0xff00) {
18
+ throw new IllegalArgumentException("DOS COM import must map 1..65280 bytes at 1000:0100");
19
+ }
20
+ for (String name : new String[] { "CS", "DS", "ES", "SS" }) {
21
+ monitor.checkCancelled();
22
+ currentProgram.getProgramContext().setValue(
23
+ currentProgram.getRegister(name), start, end, BigInteger.valueOf(0x1000)
24
+ );
25
+ }
26
+ addEntryPoint(entry);
27
+ if (!disassemble(entry) || createFunction(entry, "entry") == null) {
28
+ throw new IllegalStateException("DOS COM entry cannot be decoded as a function");
29
+ }
30
+ currentProgram.getOptions(Program.PROGRAM_INFO).setBoolean("REA DOS COM prepared", true);
31
+ }
32
+ }