rea-agents 5.0.0 → 6.0.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 (275) hide show
  1. package/README.md +157 -650
  2. package/bridge/mitmproxy/capture.py +210 -0
  3. package/bridge/native/rea_lldb_tracer.py +303 -0
  4. package/bridge/process/ProcessRunTokenReader.swift +263 -0
  5. package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
  6. package/bridge/pwndbg/core_context.py +101 -0
  7. package/bridge/pwndbg/launch.py +39 -0
  8. package/bridge/pwndbg/launch_impl.py +34 -0
  9. package/bridge/pwntools/decoder_runtime.py +59 -0
  10. package/bridge/pwntools/layout.py +39 -0
  11. package/bridge/pwntools/layout_impl.py +309 -0
  12. package/bridge/pwntools/recorded_crash.py +39 -0
  13. package/bridge/pwntools/recorded_crash_impl.py +143 -0
  14. package/dist/android/JadxProvider.js +1 -0
  15. package/dist/application/CapabilityInventory.js +21 -0
  16. package/dist/application/DirectAnalysis.js +97 -23
  17. package/dist/application/EvidenceBundleFiles.js +1 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +5 -1
  19. package/dist/application/WebNetworkCapturePort.js +1 -0
  20. package/dist/application/WebNetworkCaptureService.js +132 -0
  21. package/dist/application/WindowsCapabilities.js +1 -1
  22. package/dist/application/binary/AnalysisSnapshotCache.js +49 -6
  23. package/dist/application/binary/BinarySession.js +38 -10
  24. package/dist/application/binary/BinarySessionOpen.js +16 -3
  25. package/dist/application/binary/BinarySessionRecords.js +20 -0
  26. package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
  27. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +57 -0
  28. package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
  29. package/dist/application/binaryDiagnostics/RecordedCrashService.js +60 -0
  30. package/dist/application/evm/EvmInterfacePort.js +1 -0
  31. package/dist/application/evm/EvmInterfaceService.js +62 -0
  32. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -2
  33. package/dist/application/javascript/JavaScriptApplicationService.js +15 -2
  34. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +42 -23
  35. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
  36. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +74 -24
  37. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +23 -10
  38. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
  39. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +145 -70
  40. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
  41. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
  42. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
  43. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
  44. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
  45. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
  46. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
  47. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +5 -5
  48. package/dist/application/{ProcessCli.js → process/ProcessCli.js} +10 -10
  49. package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +4 -4
  50. package/dist/artifacts/ArtifactProvider.js +30 -3
  51. package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
  52. package/dist/artifacts/ZipArtifactReader.js +3 -0
  53. package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
  54. package/dist/artifacts/apple/MachoLoadCommandReader.js +294 -0
  55. package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
  56. package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +3 -3
  57. package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
  58. package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
  59. package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
  60. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +3 -3
  61. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
  62. package/dist/artifacts/readStableArtifact.js +20 -4
  63. package/dist/browser/CdpCaptureEventHandlers.js +90 -2
  64. package/dist/browser/CdpCaptureEvents.js +9 -0
  65. package/dist/browser/PlaywrightElectronActiveProvider.js +12 -3
  66. package/dist/browser/history/CaptureFailures.js +101 -0
  67. package/dist/browser/history/CaptureFormatError.js +10 -0
  68. package/dist/browser/history/CaptureRedaction.js +65 -0
  69. package/dist/browser/history/CaptureRelease.js +12 -0
  70. package/dist/browser/history/HarCapture.js +165 -0
  71. package/dist/browser/history/HarCaptureAdapter.js +20 -0
  72. package/dist/browser/history/HarCaptureProcess.js +57 -0
  73. package/dist/browser/history/HarJson.js +91 -0
  74. package/dist/browser/history/HarSchema.js +72 -0
  75. package/dist/browser/history/HistoricalCaptureDecoder.js +186 -0
  76. package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
  77. package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
  78. package/dist/cli/artifactCommands.js +26 -1
  79. package/dist/cli/binaryDiagnosticsCommands.js +39 -0
  80. package/dist/cli/coreAnalysisCommands.js +2 -2
  81. package/dist/cli/coreBinaryCommands.js +8 -8
  82. package/dist/cli/electronCommands.js +16 -9
  83. package/dist/cli/evmCommands.js +24 -0
  84. package/dist/cli/firmwareCommands.js +6 -3
  85. package/dist/cli/javascriptApplicationAnalysis.js +16 -3
  86. package/dist/cli/jsonOutput.js +133 -0
  87. package/dist/cli/nativeCallCommands.js +35 -0
  88. package/dist/cli/processCommands.js +1 -1
  89. package/dist/cli/streamedJsonOutput.js +56 -0
  90. package/dist/cli/utilityCommands.js +2 -0
  91. package/dist/cli/webNetworkCaptureCommands.js +40 -0
  92. package/dist/cli.js +9 -3
  93. package/dist/cliBrowserScenarioCommands.js +2 -2
  94. package/dist/cliCommandNames.js +6 -0
  95. package/dist/cliJsonInput.js +30 -1
  96. package/dist/cliOutput.js +21 -6
  97. package/dist/composition/binaryDiagnostics.js +8 -0
  98. package/dist/composition/evm.js +4 -0
  99. package/dist/composition/webNetworkCaptures.js +6 -0
  100. package/dist/contracts/artifactToolContracts.js +6 -0
  101. package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
  102. package/dist/contracts/browserToolContracts.js +4 -3
  103. package/dist/contracts/errorSchemas.js +8 -1
  104. package/dist/contracts/evm/evmToolContracts.js +20 -0
  105. package/dist/contracts/investigationExamples.js +2 -2
  106. package/dist/contracts/managed/managedToolContracts.js +7 -3
  107. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
  108. package/dist/contracts/native/nativeToolContracts.js +17 -1
  109. package/dist/contracts/officialToolContracts.js +12 -9
  110. package/dist/contracts/process/processCaptureExample.js +2 -0
  111. package/dist/contracts/sessionLifecycleInputs.js +22 -5
  112. package/dist/contracts/sessionStatusContract.js +10 -2
  113. package/dist/contracts/sessionToolContracts.js +8 -1
  114. package/dist/contracts/sessionToolSchemas.js +10 -3
  115. package/dist/contracts/toolContractExamples.js +1 -1
  116. package/dist/contracts/toolContracts.js +6 -0
  117. package/dist/contracts/toolEffects.js +30 -0
  118. package/dist/contracts/toolOutputSchemaGroups.js +5 -1
  119. package/dist/contracts/toolOutputSchemaPrimitives.js +1 -1
  120. package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
  121. package/dist/domain/analysisErrorBase.js +15 -0
  122. package/dist/domain/analysisErrorCore.js +59 -5
  123. package/dist/domain/analysisErrorPresentation.js +29 -1
  124. package/dist/domain/analysisErrorProjection.js +52 -2
  125. package/dist/domain/analysisSnapshot.js +166 -2
  126. package/dist/domain/apple/dyldPaths.js +81 -0
  127. package/dist/domain/apple/dylibResolution.js +367 -0
  128. package/dist/domain/apple/dylibResolutionFindings.js +75 -0
  129. package/dist/domain/artifactPathSyntax.js +1 -1
  130. package/dist/domain/browserObservation.js +1 -1
  131. package/dist/domain/browserObservationSchemas.js +13 -0
  132. package/dist/domain/browserScenarioValues.js +9 -2
  133. package/dist/domain/callPathSchemas.js +1 -1
  134. package/dist/domain/canonicalDigest.js +13 -1
  135. package/dist/domain/changedBehavior.js +3 -3
  136. package/dist/domain/comparisonStatus.js +2 -30
  137. package/dist/domain/conformanceTrustGate.js +0 -16
  138. package/dist/domain/evidence.js +17 -5
  139. package/dist/domain/evm/evmInterface.js +63 -0
  140. package/dist/domain/explicitSensitiveFailure.js +92 -0
  141. package/dist/domain/explicitSensitiveValues.js +10 -0
  142. package/dist/domain/firmware/firmwareAnalysis.js +8 -1
  143. package/dist/domain/javascript/electronActiveObservation.js +9 -4
  144. package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
  145. package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
  146. package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
  147. package/dist/domain/javascript/javascriptSemanticGraph.js +21 -5
  148. package/dist/domain/jsonValue.js +4 -0
  149. package/dist/domain/localPath.js +2 -0
  150. package/dist/domain/native/binaryLayout.js +357 -0
  151. package/dist/domain/native/nativeCallObservation.js +164 -0
  152. package/dist/domain/native/objcSwiftMetadata.js +0 -39
  153. package/dist/domain/native/recordedCrash.js +266 -0
  154. package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
  155. package/dist/domain/{processCapture.js → process/processCapture.js} +139 -2
  156. package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
  157. package/dist/domain/process/processCaptureParsing.js +54 -0
  158. package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
  159. package/dist/domain/{processComparison.js → process/processComparison.js} +1 -1
  160. package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
  161. package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
  162. package/dist/domain/providerSelectionError.js +4 -2
  163. package/dist/domain/reconstructionVerification.js +3 -3
  164. package/dist/domain/reconstructionVerificationSchemas.js +1 -1
  165. package/dist/domain/residualUnknown.js +3 -2
  166. package/dist/domain/staticRuntimeCorrelation.js +3 -3
  167. package/dist/domain/webCaptureDiff.js +1 -0
  168. package/dist/domain/webNetworkCapture.js +118 -0
  169. package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
  170. package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
  171. package/dist/dotnet/ManagedMemberInspector.js +4 -2
  172. package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
  173. package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
  174. package/dist/dotnet/ManagedMemberRows.js +14 -3
  175. package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
  176. package/dist/dotnet/ManagedMetadataInventory.js +38 -28
  177. package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
  178. package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
  179. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
  180. package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
  181. package/dist/dotnet/ManagedPeReader.js +11 -0
  182. package/dist/evm/EvmBytecodeCarrier.js +21 -0
  183. package/dist/evm/EvmWorkerLimits.js +40 -0
  184. package/dist/evm/EvmoleFailures.js +126 -0
  185. package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
  186. package/dist/evm/EvmoleInterfaceProvider.js +273 -0
  187. package/dist/evm/EvmoleInterfaceWorker.js +87 -0
  188. package/dist/evm/EvmoleRelease.js +16 -0
  189. package/dist/firmware/FirmwareCommand.js +1 -0
  190. package/dist/generatedPackageMetadata.js +2 -2
  191. package/dist/ghidra/GhidraLauncher.js +1 -0
  192. package/dist/ghidra/GhidraProvider.js +2 -2
  193. package/dist/ghidra/GhidraProviderCapabilities.js +1 -1
  194. package/dist/hopper/BridgeLauncher.js +2 -0
  195. package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
  196. package/dist/javascript/recovery/WakaruCommand.js +3 -0
  197. package/dist/javascript/sourceMaps/SourceMapCommand.js +1 -0
  198. package/dist/native/CommandRunner.js +2 -1
  199. package/dist/native/LldbCallTracer.js +278 -0
  200. package/dist/native/NativeCallObservation.js +135 -0
  201. package/dist/native/NativeMacOSProvider.js +19 -3
  202. package/dist/native/NativeMacOSProviderMetadata.js +8 -3
  203. package/dist/native/pwndbg/PwndbgCoreContext.js +160 -0
  204. package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
  205. package/dist/native/pwntools/PwntoolsFailures.js +180 -0
  206. package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
  207. package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
  208. package/dist/native/pwntools/PwntoolsRelease.js +19 -0
  209. package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
  210. package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
  211. package/dist/native/pwntools/RecordedCrashStructureBindings.js +101 -0
  212. package/dist/process/DarwinProcessRunTokenReader.js +294 -0
  213. package/dist/process/OwnedCommand.js +113 -0
  214. package/dist/process/ProcessOwnership.js +263 -33
  215. package/dist/process/ProcessOwnershipObservation.js +161 -24
  216. package/dist/process/ProviderProcess.js +30 -3
  217. package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
  218. package/dist/{application → process/capture}/ProcessCaptureError.js +17 -1
  219. package/dist/process/capture/ProcessCaptureLifecycle.js +615 -0
  220. package/dist/{application → process/capture}/ProcessHarness.js +195 -29
  221. package/dist/{application → process/capture}/ProcessSampling.js +2 -2
  222. package/dist/server/createServer.js +22 -0
  223. package/dist/server/promptCompletion.js +10 -3
  224. package/dist/server/registerBinaryDiagnosticsTools.js +17 -0
  225. package/dist/server/registerEvidenceTools.js +1 -1
  226. package/dist/server/registerEvmTools.js +17 -0
  227. package/dist/server/registerProcessComparisonTool.js +1 -1
  228. package/dist/server/registerRecordedCrashTools.js +17 -0
  229. package/dist/server/registerSessionTools.js +2 -2
  230. package/dist/server/registerWebNetworkCaptureTool.js +28 -0
  231. package/dist/server/sessionAvailabilityPolicy.js +3 -0
  232. package/dist/server/sessionToolPolicies.js +1 -1
  233. package/dist/server/toolResult.js +1 -1
  234. package/native/windows/build/manifest.json +2 -2
  235. package/native/windows/build/rea-windows-x64.node +0 -0
  236. package/package.json +37 -9
  237. package/scripts/rea.mjs +11 -3
  238. package/skills/reverse-engineer-anything/SKILL.md +23 -3
  239. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
  240. package/third_party/README.md +60 -0
  241. package/third_party/evmole/LICENSE +21 -0
  242. package/third_party/evmole/README.md +22 -0
  243. package/third_party/pwndbg/LICENSE.md +21 -0
  244. package/third_party/pwndbg/README.md +23 -0
  245. package/third_party/pwntools/README.md +40 -0
  246. package/dist/application/AuthorizedArtifactInventory.js +0 -7
  247. package/dist/application/ProcessCaptureLifecycle.js +0 -299
  248. package/dist/application/StoreFileLock.js +0 -124
  249. package/dist/contracts/processCaptureExample.js +0 -2
  250. package/dist/domain/bytecodeProvider.js +0 -178
  251. package/dist/domain/customProtocolCapture.js +0 -137
  252. package/dist/domain/eventProcessTree.js +0 -225
  253. package/dist/domain/mobileApplicationInvestigation.js +0 -159
  254. package/dist/domain/packageAnalysis.js +0 -123
  255. package/dist/domain/peInspection.js +0 -197
  256. package/dist/domain/processCaptureParsing.js +0 -21
  257. package/dist/domain/protocolCapture.js +0 -217
  258. package/dist/domain/runtimeIdentification.js +0 -212
  259. package/dist/generatedMcpToolCatalog.js +0 -37
  260. /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
  261. /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
  262. /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
  263. /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
  264. /package/dist/domain/{processScenario.js → process/processScenario.js} +0 -0
  265. /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
  266. /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
  267. /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
  268. /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
  269. /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
  270. /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
  271. /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
  272. /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
  273. /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
  274. /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
  275. /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
@@ -0,0 +1,309 @@
1
+ """Offline adapter to unchanged pwntools 4.15.0; never use libs/maps/libc.
2
+
3
+ Owned request/snapshot/reply paths are supplied by REA. No host target-process launch,
4
+ user configuration initialization, debugger startup, or dependency installation.
5
+ """
6
+ import base64
7
+ import importlib.metadata
8
+ import io
9
+ import json
10
+ import os
11
+ from pathlib import Path
12
+ import resource
13
+ import sys
14
+
15
+ PROFILE = "pwntools@4.15.0;pyelftools@0.33;unicorn@2.1.2"
16
+ PACKAGES = {"pwntools": "4.15.0", "pyelftools": "0.33", "unicorn": "2.1.2"}
17
+ OUTPUT_BYTES = 64 * 1024 * 1024
18
+
19
+
20
+ class LayoutFailure(Exception):
21
+ def __init__(self, reason, message):
22
+ super().__init__(message)
23
+ self.reason = reason
24
+
25
+
26
+ def address(value):
27
+ return hex(int(value))
28
+
29
+
30
+ def file_range(offset, size, length):
31
+ return 0 <= offset <= length and 0 <= size <= length - offset
32
+
33
+
34
+ def location(offset, size, length):
35
+ if not file_range(offset, size, length):
36
+ raise LayoutFailure("format", "ELF contains a file-backed range outside the selected snapshot.")
37
+ return {"offset": address(offset), "bytes": address(size)}
38
+
39
+
40
+ def name_reference(display, section, offset, content):
41
+ header = getattr(section, "header", None)
42
+ if header is None or header.sh_type != "SHT_STRTAB":
43
+ return {"display": display, "bytes_base64": None, "location": None,
44
+ "unknown_reason": "Referenced string table could not be resolved."}
45
+ return name_in_table(display, header.sh_offset, header.sh_size, offset, content)
46
+
47
+
48
+ def name_in_table(display, table_start, table_size, offset, content):
49
+ location(table_start, table_size, len(content))
50
+ if not 0 <= offset < table_size:
51
+ raise LayoutFailure("format", f"ELF name offset {offset} lies outside its declared string table of {table_size} bytes at file offset {table_start}.")
52
+ start = table_start + offset
53
+ limit = table_start + table_size
54
+ end = content.find(b"\0", start, limit)
55
+ if end < 0:
56
+ raise LayoutFailure("format", "ELF name lacks a terminator within its reported string table.")
57
+ raw = content[start:end]
58
+ return {"display": raw.decode("utf-8", "replace") if display is None else display, "bytes_base64": base64.b64encode(raw).decode("ascii"),
59
+ "location": location(start, len(raw) + 1, len(content)), "unknown_reason": None}
60
+
61
+
62
+ def dynamic_name_reference(tags, offset, image, content):
63
+ starts = [tag.d_val for tag in tags if tag.d_tag == "DT_STRTAB"]
64
+ sizes = [tag.d_val for tag in tags if tag.d_tag == "DT_STRSZ"]
65
+ if not starts or not sizes:
66
+ raise LayoutFailure("format", "ELF dependency requires DT_STRTAB and DT_STRSZ.")
67
+ if len(starts) != 1 or len(sizes) != 1:
68
+ raise LayoutFailure("unsupported-target", "ELF dependency string-table tags are ambiguous: " + repr({"DT_STRTAB": starts, "DT_STRSZ": sizes}))
69
+ if not 0 <= offset < sizes[0]:
70
+ raise LayoutFailure("format", f"ELF dependency name offset {offset} lies outside declared DT_STRSZ {sizes[0]}.")
71
+ offsets = set()
72
+ if len(starts) == 1 and len(sizes) == 1:
73
+ for segment in image.iter_segments_by_type("PT_LOAD"):
74
+ h = segment.header
75
+ if starts[0] >= h.p_vaddr and starts[0] + sizes[0] <= h.p_vaddr + h.p_filesz:
76
+ offsets.add(h.p_offset + starts[0] - h.p_vaddr)
77
+ if len(offsets) != 1:
78
+ raise LayoutFailure("unsupported-target", "Dynamic string table lacks a unique file-backed mapping: " + repr({"DT_STRTAB": starts, "DT_STRSZ": sizes, "candidate_file_offsets": sorted(offsets)}))
79
+ return name_in_table(None, offsets.pop(), sizes[0], offset, content)
80
+
81
+
82
+ def symbol_value_meaning(raw, image_type, sections):
83
+ index = raw.st_shndx
84
+ if raw.st_info.type == "STT_FILE": return "no-address"
85
+ if index == "SHN_UNDEF": return "undefined"
86
+ if index == "SHN_COMMON": return "alignment"
87
+ if index == "SHN_ABS": return "absolute-value"
88
+ if not isinstance(index, int) or not 0 < index < len(sections) or index >= 0xff00:
89
+ return "unknown-section-index"
90
+ if sections[index].header.sh_type == "SHT_NULL":
91
+ return "unknown-section-index"
92
+ if image_type == "ET_REL": return "section-offset"
93
+ if raw.st_info.type == "STT_TLS": return "tls-offset"
94
+ return "linked-virtual-address"
95
+
96
+
97
+ def relocation_target(image_type, section_index, offset, sections):
98
+ if image_type != "ET_REL":
99
+ return {"kind": "linked-virtual-address", "address": address(offset)}
100
+ if section_index == 0 or sections[section_index].header.sh_type == "SHT_NULL":
101
+ return {"kind": "unknown-section", "reported_section_index": section_index,
102
+ "offset": address(offset), "unknown_reason": "undefined-section-reference" if section_index == 0 else "inactive-section-header"}
103
+ return {"kind": "section-offset", "section_index": section_index, "offset": address(offset)}
104
+
105
+
106
+ def inspect_elf(path, cache):
107
+ for package, expected in PACKAGES.items():
108
+ try:
109
+ version = importlib.metadata.version(package)
110
+ except importlib.metadata.PackageNotFoundError as error:
111
+ raise LayoutFailure("unavailable", "Selected Python lacks " + package + " " + expected + ".") from error
112
+ if version != expected:
113
+ raise LayoutFailure("unsupported", "Expected " + package + " " + expected + "; selected Python reports " + version + ".")
114
+ content = path.read_bytes()
115
+ if len(content) < 4 or content[:4] != b"\x7fELF":
116
+ raise LayoutFailure("format", "Selected object does not contain an ELF header.")
117
+ if len(content) < 16:
118
+ raise LayoutFailure("format", "Selected ELF identification is truncated.")
119
+ if content[4] != 2 or content[5] != 1:
120
+ raise LayoutFailure("unsupported-target", "Initial layout profile requires ELF64 little-endian objects.")
121
+ if len(content) < 64:
122
+ raise LayoutFailure("format", "Selected ELF64 header is truncated.")
123
+ if int.from_bytes(content[18:20], "little") != 62:
124
+ raise LayoutFailure("unsupported-target", "Initial layout profile requires x86-64 ELF objects.")
125
+ if int.from_bytes(content[16:18], "little") not in (1, 2, 3):
126
+ raise LayoutFailure("unsupported-target", "Selected ELF type is outside the EXEC/DYN/REL layout profile; recorded core analysis is separate.")
127
+ from pwnlib.context import context
128
+ with context.local(cache_dir=str(cache), log_level="warning"):
129
+ from elftools.common.exceptions import ELFError
130
+ from elftools.elf.elffile import ELFFile
131
+ from pwnlib.elf import ELF
132
+ try:
133
+ headers = ELFFile(io.BytesIO(content))
134
+ section_count = headers.num_sections()
135
+ if headers.header.e_shstrndx == 0xffff and section_count == 0:
136
+ raise LayoutFailure("format", "ELF extended section-name index requires a declared section-zero header.")
137
+ raw_name_index = headers.header.e_shstrndx
138
+ if 0xff00 <= raw_name_index < 0xffff:
139
+ raise LayoutFailure("format", f"ELF section-name index {raw_name_index} is reserved and cannot directly reference a section.")
140
+ section_name_index = headers.get_shstrndx()
141
+ if raw_name_index == 0xffff and section_name_index < 0xff00:
142
+ raise LayoutFailure("format", f"ELF SHN_XINDEX resolves to ordinary index {section_name_index}; the escape requires an index at least SHN_LORESERVE (0xff00).")
143
+ if section_name_index != 0:
144
+ if section_name_index >= section_count:
145
+ raise LayoutFailure("format", f"ELF section-name table index {section_name_index} lies outside the declared section count {section_count}.")
146
+ names_header = headers._get_section_header(section_name_index)
147
+ if names_header.sh_type != "SHT_STRTAB":
148
+ raise LayoutFailure("format", f"ELF section-name table {section_name_index} is not SHT_STRTAB.")
149
+ location(names_header.sh_offset, names_header.sh_size, len(content))
150
+ except ELFError as error:
151
+ raise LayoutFailure("format", str(error)) from error
152
+ class LayoutELF(ELF):
153
+ def _get_section_name(self, header):
154
+ # SHN_UNDEF declares no names; upstream would otherwise read
155
+ # strings at the inactive section-zero offset.
156
+ return "" if section_name_index == 0 else super()._get_section_name(header)
157
+
158
+ # pyelftools 0.33 calls these documented filters internally;
159
+ # pwntools 4.15.0's cached overrides do not accept the argument.
160
+ # Forward the filter on this adapter instance, without modifying
161
+ # either upstream package or process-global methods.
162
+ def iter_segments(self, type=None):
163
+ return (segment for segment in super().iter_segments()
164
+ if type is None or segment.header.p_type == type)
165
+
166
+ def iter_sections(self, type=None):
167
+ return (section for section in super().iter_sections()
168
+ if type is None or section.header.sh_type == type)
169
+ try:
170
+ image = LayoutELF(str(path), checksec=False)
171
+ if image.arch != "amd64" or image.bits != 64 or image.endian != "little":
172
+ raise LayoutFailure("unsupported-target", "Initial layout profile requires x86-64 ELF64 little-endian objects.")
173
+ if image.header.e_type not in ("ET_EXEC", "ET_DYN", "ET_REL"):
174
+ raise LayoutFailure("unsupported-target", "Selected ELF type is outside the EXEC/DYN/REL layout profile; recorded core analysis is separate.")
175
+ length = len(content)
176
+ all_sections = list(image.iter_sections())
177
+ shstrings = image.get_section(section_name_index) if all_sections and section_name_index != 0 else None
178
+ sections, segments, symbols, relocations, packed_relatives = [], [], [], [], []
179
+ needed, interpreters = [], []
180
+ for index, section in enumerate(all_sections):
181
+ h = section.header
182
+ backing = h.sh_type not in ("SHT_NOBITS", "SHT_NULL")
183
+ if backing: location(h.sh_offset, h.sh_size, length)
184
+ sections.append({
185
+ "index": index, "name": name_reference(section.name, shstrings, h.sh_name, content) if shstrings is not None else {"display": "", "bytes_base64": None, "location": None, "unknown_reason": "ELF declares no section-name table (SHN_UNDEF index 0)."}, "name_offset": address(h.sh_name), "type": h.sh_type,
186
+ "header_location": location(image.header.e_shoff + index * image.header.e_shentsize, image.header.e_shentsize, length),
187
+ "address": address(h.sh_addr), "offset": address(h.sh_offset),
188
+ "size": address(h.sh_size), "alignment": address(h.sh_addralign),
189
+ "flags": address(h.sh_flags), "link": h.sh_link, "info": h.sh_info,
190
+ "entry_size": address(h.sh_entsize), "file_backing": "file" if backing else "none",
191
+ })
192
+ if h.sh_type in ("SHT_SYMTAB", "SHT_DYNSYM"):
193
+ if h.sh_entsize < image.structs.Elf_Sym.sizeof():
194
+ raise LayoutFailure("format", "ELF symbol entry is smaller than the decoded Elf64_Sym structure.")
195
+ if h.sh_link >= len(all_sections) or all_sections[h.sh_link].header.sh_type != "SHT_STRTAB":
196
+ raise LayoutFailure("format", f"ELF symbol table {index} links to invalid string table {h.sh_link}.")
197
+ strings = all_sections[h.sh_link]
198
+ for entry, symbol in enumerate(section.iter_symbols()):
199
+ raw = symbol.entry
200
+ symbols.append({
201
+ "table_index": index, "entry_index": entry,
202
+ "name": name_reference(symbol.name, strings, raw.st_name, content), "name_offset": address(raw.st_name),
203
+ "location": location(h.sh_offset + entry * h.sh_entsize, h.sh_entsize, length),
204
+ "value": address(raw.st_value), "value_meaning": symbol_value_meaning(raw, image.header.e_type, all_sections),
205
+ "size": address(raw.st_size), "binding": raw.st_info.bind, "type": raw.st_info.type,
206
+ "visibility": raw.st_other.visibility, "section_index": raw.st_shndx,
207
+ })
208
+ if h.sh_type in ("SHT_REL", "SHT_RELA"):
209
+ if image.header.e_type == "ET_REL" and h.sh_info >= len(all_sections):
210
+ raise LayoutFailure("format", f"ELF relocation section {index} references missing target section {h.sh_info}.")
211
+ symbol_table = None
212
+ if h.sh_link != 0:
213
+ if h.sh_link >= len(all_sections) or all_sections[h.sh_link].header.sh_type not in ("SHT_SYMTAB", "SHT_DYNSYM"):
214
+ raise LayoutFailure("format", f"ELF relocation section {index} links to invalid symbol table {h.sh_link}.")
215
+ symbol_table = all_sections[h.sh_link]
216
+ for entry, relocation in enumerate(section.iter_relocations()):
217
+ raw = relocation.entry
218
+ if raw.r_info_sym != 0 and (symbol_table is None or raw.r_info_sym >= symbol_table.num_symbols()):
219
+ raise LayoutFailure("format", f"ELF relocation section {index} entry {entry} references missing symbol {raw.r_info_sym} in table {h.sh_link}.")
220
+ relocations.append({
221
+ "section_index": index, "entry_index": entry, "reported_offset": address(raw.r_offset),
222
+ "target": relocation_target(image.header.e_type, h.sh_info, raw.r_offset, all_sections),
223
+ "location": location(h.sh_offset + entry * h.sh_entsize, h.sh_entsize, length),
224
+ "type": raw.r_info_type, "symbol_table_index": h.sh_link, "symbol_index": raw.r_info_sym,
225
+ "symbol_reference_meaning": "zero-symbol-value" if raw.r_info_sym == 0 else "symbol-table-entry",
226
+ "addend": None if "r_addend" not in raw else str(raw.r_addend),
227
+ })
228
+ if h.sh_type == "SHT_RELR":
229
+ packed_relatives.append({
230
+ "section_index": index,
231
+ "location": location(h.sh_offset, h.sh_size, length),
232
+ "encoded_bytes_base64": base64.b64encode(content[h.sh_offset:h.sh_offset + h.sh_size]).decode("ascii"),
233
+ "entries": [{"decoded_index": decoded, "reported_offset": address(relocation.entry.r_offset)} for decoded, relocation in enumerate(section.iter_relocations())],
234
+ "offset_meaning": "unknown" if image.header.e_type == "ET_REL" else "linked-virtual-address",
235
+ "evidence_kind": "derived", "entry_source_locations": None, "addends": None,
236
+ })
237
+ for index, segment in enumerate(image.iter_segments()):
238
+ h = segment.header
239
+ backing = h.p_type != "PT_NULL" and h.p_filesz != 0
240
+ if backing: location(h.p_offset, h.p_filesz, length)
241
+ if h.p_type == "PT_LOAD" and h.p_memsz < h.p_filesz:
242
+ raise LayoutFailure("format", "ELF load segment memory size is smaller than its file size.")
243
+ segments.append({
244
+ "index": index, "type": h.p_type, "offset": address(h.p_offset),
245
+ "header_location": location(image.header.e_phoff + index * image.header.e_phentsize, image.header.e_phentsize, length),
246
+ "file_size": address(h.p_filesz), "memory_size": address(h.p_memsz),
247
+ "virtual_address": address(h.p_vaddr), "physical_address": address(h.p_paddr),
248
+ "alignment": address(h.p_align), "flags": address(h.p_flags),
249
+ "file_backing": "file" if backing else "none",
250
+ "permissions": None if h.p_type == "PT_NULL" else {"read": bool(h.p_flags & 4), "write": bool(h.p_flags & 2), "execute": bool(h.p_flags & 1)},
251
+ })
252
+ if h.p_type == "PT_DYNAMIC":
253
+ tag_size = image.structs.Elf_Dyn.sizeof()
254
+ tags = []
255
+ for tag_index in range(h.p_filesz // tag_size):
256
+ tag = segment._get_tag(tag_index)
257
+ tags.append(tag)
258
+ if tag.d_tag == "DT_NULL":
259
+ break
260
+ else:
261
+ raise LayoutFailure("format", f"ELF dynamic segment {index} has no complete DT_NULL terminator within its reported file range.")
262
+ for tag in tags:
263
+ if tag.d_tag == "DT_NEEDED":
264
+ needed.append(dynamic_name_reference(tags, tag.d_val, image, content))
265
+ if h.p_type == "PT_INTERP":
266
+ raw = content[h.p_offset:h.p_offset + h.p_filesz]
267
+ end = raw.find(b"\0")
268
+ if end < 0:
269
+ raise LayoutFailure("format", "ELF interpreter lacks a reported terminator.")
270
+ interpreters.append({"display": raw[:end].decode("utf-8", "replace"), "bytes_base64": base64.b64encode(raw[:end]).decode("ascii"), "location": location(h.p_offset, end + 1, length), "unknown_reason": None})
271
+ return {
272
+ "format": "elf", "architecture": {"machine": image.header.e_machine, "bits": image.bits, "byte_order": image.endian},
273
+ "image_type": image.header.e_type,
274
+ "entry_point": {"reported_value": address(image.header.e_entry), "meaning": "not-applicable" if image.header.e_type == "ET_REL" else "absent" if image.header.e_entry == 0 else "linked-virtual-address", "execution_status": "unknown"},
275
+ "runtime_load_base": None, "sections": sections, "segments": segments, "symbols": symbols, "relocations": relocations,
276
+ "packed_relative_relocations": packed_relatives, "relocation_inventory_completeness": "unknown",
277
+ "linkage": {"needed_libraries": needed, "interpreters": interpreters,
278
+ "got": [{"display_name": name, "address": address(value)} for name, value in image.got.items()],
279
+ "plt": [{"display_name": name, "address": address(value)} for name, value in image.plt.items()],
280
+ "convenience_maps_completeness": "unknown", "runtime_library_paths": None},
281
+ "mitigations": {"evidence_kind": "inferred", "position_independent": image.pie, "nx_indicator": image.nx, "executable_stack_indicator": image.execstack, "stack_canary_indicator": image.canary, "relro": image.relro},
282
+ "limitations": [
283
+ "PT_NULL payload fields are unused and retain their reported numbers without file-byte or permission claims. Zero-file-size segments provide no file bytes.",
284
+ "SHN_XINDEX symbol values remain unresolved in this upstream representation; an external index table does not establish a resolved index in this report.",
285
+ "Reported values preserve linked addresses, section offsets, TLS offsets, alignment and absolute values separately. Runtime load base and library paths are unknown.",
286
+ "Names are display strings plus raw bytes and file ranges where resolvable; section/table/entry indices preserve identity and duplicates. Name ranges include their terminating NUL; raw name bytes exclude it.",
287
+ "Ordinary relocation rows cover REL/RELA. RELR tables retain complete encoded bytes and upstream-decoded offsets as derived evidence; per-offset packed-word locations and implicit addends remain unknown. Relocation inventory completeness is unknown, including other encodings and missing section tables.",
288
+ "Relocation symbol index zero uses a zero symbol value without a table lookup. Positive indices reference validated original symbol-table entries; raw table and symbol indices remain reported.",
289
+ "Relocatable relocation targets with SHN_UNDEF or inactive SHT_NULL headers retain their reported section index/offset as unknown; they do not establish an associated target section.",
290
+ "GOT/PLT are derived upstream convenience maps; PLT inference can emulate selected instructions in Unicorn. They do not establish target runtime behavior; aliases may collapse and warnings may indicate incomplete coverage. Their completeness is unknown.",
291
+ "Mitigations are upstream static heuristics, not runtime protection. ET_DYN does not prove an executable; absent canary symbols do not prove every function unprotected.",
292
+ "This profile inspects ELF EXEC/DYN/REL layout only. It does not analyze recorded cores, resolve loaded libraries, launch the target as a host process or start a debugger.",
293
+ "Symbol/relocation inventories reflect original section tables. A sectionless image can still report dynamic dependency names; missing tables do not prove absence of dynamic symbols or relocations.",
294
+ *(["Absent section-name table: section-dependent RELRO/canary heuristics may be incomplete; protection coverage is unknown."] if all_sections and section_name_index == 0 else []),
295
+ *(["Sectionless images lack the .dynamic section and symbol tables used by upstream heuristics. RELRO/canary indicators may be incomplete; their values remain reported static candidates, with protection coverage unknown."] if not all_sections else []),
296
+ ],
297
+ }
298
+ except LayoutFailure:
299
+ raise
300
+ except (ELFError, ValueError, AssertionError, IndexError) as error:
301
+ raise LayoutFailure("format", "Selected ELF failed unchanged upstream structural parsing: " + str(error)) from error
302
+
303
+
304
+
305
+ if __name__ == "__main__":
306
+ runtime_path = Path(__file__).with_name("decoder_runtime.py")
307
+ runtime = {"__file__": str(runtime_path), "__name__": "rea_decoder_runtime"}
308
+ exec(compile(runtime_path.read_bytes(), str(runtime_path), "exec"), runtime)
309
+ runtime["main"](sys.argv[-1], inspect_elf, LayoutFailure, PROFILE)
@@ -0,0 +1,39 @@
1
+ """Catch typed resource failures while loading or running the owned recorded-core adapter.
2
+
3
+ Only this package's fixed sibling is executed; caller input stays in request.json.
4
+ Interpreter startup failures before this boundary remain unclassified.
5
+ """
6
+ import os
7
+ import sys
8
+
9
+
10
+ def resource_exit(status, marker):
11
+ try:
12
+ if len(sys.argv) > 2:
13
+ descriptor = os.open(sys.argv[1], os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
14
+ os.write(descriptor, marker)
15
+ os.close(descriptor)
16
+ except (OSError, MemoryError):
17
+ # Without a complete marker the parent keeps this failure unclassified.
18
+ pass
19
+ os._exit(status)
20
+
21
+ try:
22
+ implementation = os.path.join(os.path.dirname(__file__), "recorded_crash_impl.py")
23
+ with open(implementation, "rb") as handle:
24
+ source = handle.read()
25
+ exec(compile(source, implementation, "exec"), {
26
+ "__file__": implementation,
27
+ "__name__": "__main__",
28
+ })
29
+ except MemoryError:
30
+ # Reserved status: an observed allocation failure, including imports/compile.
31
+ resource_exit(75, b"M")
32
+ except OSError as error:
33
+ # Linux ENOMEM is an observed allocation failure, independent of error text.
34
+ if error.errno == 12:
35
+ resource_exit(75, b"M")
36
+ # Linux EFBIG is observed directly, including a partial limits/reply write.
37
+ if error.errno == 27:
38
+ resource_exit(76, b"F")
39
+ raise
@@ -0,0 +1,143 @@
1
+ """Bounded Linux core evidence via unchanged ELFFile/structs and pwntools ctypes.
2
+
3
+ No Corefile-selected thread, executable guessing, process lookup or target launch.
4
+ """
5
+ import base64
6
+ import ctypes
7
+ import importlib.metadata
8
+ import io
9
+ from pathlib import Path
10
+ import sys
11
+
12
+ PROFILE = "pwntools@4.15.0;pyelftools@0.33;unicorn@2.1.2"
13
+
14
+
15
+ class CoreFailure(Exception):
16
+ def __init__(self, reason, message):
17
+ super().__init__(message)
18
+ self.reason = reason
19
+
20
+
21
+ def encoded(value):
22
+ return base64.b64encode(value).decode("ascii")
23
+
24
+
25
+ def location(offset, size, limit):
26
+ if not 0 <= offset <= limit or not 0 <= size <= limit - offset:
27
+ raise CoreFailure("format", "Recorded source range exceeds its declared container.")
28
+ return {"offset": hex(offset), "bytes": hex(size)}
29
+
30
+
31
+ def inspect_core(path, cache):
32
+ for package, required in {"pwntools": "4.15.0", "pyelftools": "0.33", "unicorn": "2.1.2"}.items():
33
+ try:
34
+ actual = importlib.metadata.version(package)
35
+ except importlib.metadata.PackageNotFoundError as error:
36
+ raise CoreFailure("unavailable", "Selected Python lacks " + package + " " + required + ".") from error
37
+ if actual != required:
38
+ raise CoreFailure("unsupported", "Expected " + package + " " + required + "; selected Python reports " + actual + ".")
39
+ content = path.read_bytes()
40
+ if len(content) < 16 or content[:4] != b"\x7fELF":
41
+ raise CoreFailure("format", "Selected recording lacks a complete ELF identification.")
42
+ if content[4:6] != b"\x02\x01":
43
+ raise CoreFailure("unsupported-target", "Initial recorded-core profile requires ELF64 little-endian.")
44
+ if len(content) < 64:
45
+ raise CoreFailure("format", "Selected ELF64 core header is truncated.")
46
+ # Linux commonly emits ELFOSABI_NONE (0), also accepted as GNU/Linux (3).
47
+ # Other declared OSABIs must never select Linux note ctypes.
48
+ if content[7] not in (0, 3) or content[8] != 0:
49
+ raise CoreFailure("unsupported-target", "Initial recorded-core profile requires System V or GNU/Linux OSABI with ABI version zero; selected OSABI=" + str(content[7]) + ", ABI version=" + str(content[8]) + ".")
50
+ if int.from_bytes(content[16:18], "little") != 4 or int.from_bytes(content[18:20], "little") != 62:
51
+ raise CoreFailure("unsupported-target", "Initial recorded-core profile requires x86-64 ET_CORE.")
52
+ from elftools.common.exceptions import ELFError
53
+ from elftools.common.utils import struct_parse
54
+ from elftools.elf.elffile import ELFFile
55
+ from pwnlib.elf.datatypes import elf_prstatus_amd64, elf_siginfo_64, user_regs_struct_amd64
56
+ try:
57
+ image = ELFFile(io.BytesIO(content))
58
+ header = image.header
59
+ count = image.num_segments()
60
+ if count and header.e_phentsize < image.structs.Elf_Phdr.sizeof():
61
+ raise CoreFailure("format", "Program-header entry is shorter than the required ELF64 structure.")
62
+ location(header.e_phoff, count * header.e_phentsize, len(content))
63
+ segments, notes, padding, threads, signals = [], [], [], [], []
64
+ for segment_index, segment in enumerate(image.iter_segments()):
65
+ h = segment.header
66
+ backing = h.p_type != "PT_NULL" and h.p_filesz > 0
67
+ if backing:
68
+ location(h.p_offset, h.p_filesz, len(content))
69
+ if h.p_type == "PT_LOAD" and h.p_filesz > h.p_memsz:
70
+ raise CoreFailure("format", "Recorded PT_LOAD file bytes exceed memory size.")
71
+ segments.append({"index": segment_index, "type": h.p_type,
72
+ "header_location": location(header.e_phoff + segment_index * header.e_phentsize, header.e_phentsize, len(content)),
73
+ "offset": hex(h.p_offset), "file_size": hex(h.p_filesz), "memory_size": hex(h.p_memsz),
74
+ "virtual_address": hex(h.p_vaddr), "physical_address": hex(h.p_paddr), "alignment": hex(h.p_align), "flags": hex(h.p_flags), "file_backing": "file" if backing else "none"})
75
+ if h.p_type != "PT_NOTE" or h.p_filesz == 0:
76
+ continue
77
+ position, end = h.p_offset, h.p_offset + h.p_filesz
78
+ header_size = image.structs.Elf_Nhdr.sizeof()
79
+ while position < end:
80
+ if end - position < header_size:
81
+ raw = content[position:end]
82
+ if any(raw):
83
+ raise CoreFailure("format", "Nonzero trailing note bytes lack a complete note header.")
84
+ padding.append({"segment_index": segment_index, "location": location(position, len(raw), end), "bytes_base64": encoded(raw)})
85
+ break
86
+ note = struct_parse(image.structs.Elf_Nhdr, image.stream, stream_pos=position)
87
+ owner_start = position + header_size
88
+ descriptor_start = owner_start + ((note.n_namesz + 3) // 4) * 4
89
+ note_end = descriptor_start + ((note.n_descsz + 3) // 4) * 4
90
+ location(position, note_end - position, end)
91
+ owner = content[owner_start:owner_start + note.n_namesz]
92
+ if owner and b"\0" not in owner:
93
+ raise CoreFailure("format", "Declared note owner has no NUL terminator.")
94
+ display = owner.split(b"\0", 1)[0].decode("utf-8", "replace") if owner else None
95
+ descriptor = content[descriptor_start:descriptor_start + note.n_descsz]
96
+ note_index = len(notes)
97
+ notes.append({"index": note_index, "segment_index": segment_index, "type": note.n_type,
98
+ "location": location(position, note_end - position, end),
99
+ "owner_location": location(owner_start, len(owner), end), "owner_bytes_base64": encoded(owner), "owner_display": display,
100
+ "descriptor_location": location(descriptor_start, len(descriptor), end), "descriptor_bytes_base64": encoded(descriptor)})
101
+ position = note_end
102
+ # Only the initial Linux CORE ABI is interpreted. Other owners retain exact bytes.
103
+ if owner != b"CORE\0":
104
+ continue
105
+ if note.n_type == "NT_PRSTATUS":
106
+ if len(descriptor) < ctypes.sizeof(elf_prstatus_amd64):
107
+ raise CoreFailure("format", "Linux amd64 NT_PRSTATUS descriptor is truncated.")
108
+ status = elf_prstatus_amd64.from_buffer_copy(descriptor)
109
+ registers = []
110
+ for name, kind in user_regs_struct_amd64._fields_:
111
+ relative = elf_prstatus_amd64.pr_reg.offset + getattr(user_regs_struct_amd64, name).offset
112
+ registers.append({"name": name, "value": hex(getattr(status.pr_reg, name)), "location": location(descriptor_start + relative, ctypes.sizeof(kind), end)})
113
+ threads.append({"note_index": note_index, "historical_pid": ctypes.c_int32(status.pr_pid).value, "recorded_current_signal": status.pr_cursig, "registers": registers})
114
+ elif note.n_type == "NT_SIGINFO":
115
+ if len(descriptor) < ctypes.sizeof(elf_siginfo_64):
116
+ raise CoreFailure("format", "Linux amd64 NT_SIGINFO descriptor is truncated.")
117
+ signal = elf_siginfo_64.from_buffer_copy(descriptor)
118
+ number = ctypes.c_int32(signal.si_signo).value
119
+ code = ctypes.c_int32(signal.si_code).value
120
+ known = number == 11 and code in (1, 2)
121
+ signals.append({"note_index": note_index, "number": number, "code": code, "errno": ctypes.c_int32(signal.si_errno).value,
122
+ "fault_address": hex(signal.sigfault_addr) if known else None,
123
+ "fault_address_meaning": "recorded-sigsegv-address" if known else "unknown", "thread_association": "unknown"})
124
+ return {"format": "elf-core", "architecture": "x86_64-little-endian", "target_execution": "not-performed", "live_process_identity": "unknown",
125
+ "segments": segments, "notes": notes, "note_padding": padding, "threads": threads, "signals": signals,
126
+ "note_interpretation_completeness": "unknown",
127
+ "limitations": ["The initial Linux note profile accepts System V/unspecified or GNU/Linux OSABI with ABI version zero; an unspecified OSABI alone does not prove operating-system origin.",
128
+ "Historical PID and signal values are recorded metadata, not current process identity or attach authority.",
129
+ "Only exact Linux CORE NT_PRSTATUS/NT_SIGINFO owners are interpreted; every descriptor and owner retains original bytes. Other note semantics remain unknown.",
130
+ "NT_SIGINFO thread association is unknown. Only SIGSEGV SEGV_MAPERR/SEGV_ACCERR initially establish a fault-address union meaning.",
131
+ "PT_LOAD file bytes are recorded bytes. Undumped memory and current executable/library identity remain unknown; no current host file is resolved from a recorded pathname.",
132
+ "Missing notes/registers/signals do not establish their absence at the original crash. Full unwinding, executable pairing and live control are not provided."]}
133
+ except CoreFailure:
134
+ raise
135
+ except (ELFError, ValueError, AssertionError, IndexError) as error:
136
+ raise CoreFailure("format", "Recorded core failed unchanged upstream structural parsing: " + str(error)) from error
137
+
138
+
139
+ if __name__ == "__main__":
140
+ runtime_path = Path(__file__).with_name("decoder_runtime.py")
141
+ runtime = {"__file__": str(runtime_path), "__name__": "rea_decoder_runtime"}
142
+ exec(compile(runtime_path.read_bytes(), str(runtime_path), "exec"), runtime)
143
+ runtime["main"](sys.argv[-1], inspect_core, CoreFailure, PROFILE)
@@ -216,6 +216,7 @@ export class JadxProvider {
216
216
  ],
217
217
  cwd: root.path,
218
218
  hostEnvironment: this.environment,
219
+ signal,
219
220
  }, this.launcher);
220
221
  retained = {
221
222
  key,
@@ -186,6 +186,27 @@ const workflowAvailabilityFor = ({ name, kind, policy, }) => {
186
186
  reason: "provider_missing",
187
187
  remediation: "On Linux x64, provide an absolute REA_WAKARU_COMMAND for Wakaru 1.13.0 and util-linux prlimit. No binary target is required.",
188
188
  };
189
+ if (name === "inspect_binary_layout")
190
+ return policy.binaryLayoutEnabled === true
191
+ ? { reason: "available", remediation: null }
192
+ : {
193
+ reason: "provider_missing",
194
+ remediation: "On Linux x64, set absolute REA_PWNTOOLS_PYTHON to caller-supplied Python with pwntools 4.15.0. No active binary target is required.",
195
+ };
196
+ if (name === "inspect_evm_interface")
197
+ return policy.evmInterfaceEnabled === true
198
+ ? { reason: "available", remediation: null }
199
+ : {
200
+ reason: "provider_missing",
201
+ remediation: "The bundled offline EVM interface profile is currently real-verified on Linux x64. No active binary target or chain endpoint is required.",
202
+ };
203
+ if (name === "inspect_recorded_crash")
204
+ return policy.recordedCrashEnabled === true
205
+ ? { reason: "available", remediation: null }
206
+ : {
207
+ reason: "provider_missing",
208
+ remediation: "On Linux x64, set absolute REA_PWNTOOLS_PYTHON to caller-supplied Python with pwntools 4.15.0. No active binary target is required.",
209
+ };
189
210
  if (kind === "firmware-provider") {
190
211
  const enabled = name === "inspect_firmware_regions"
191
212
  ? policy.firmwareInspectionEnabled