@jshookmcp/jshook 0.2.9 → 0.3.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 (187) hide show
  1. package/README.md +2 -2
  2. package/README.zh.md +2 -2
  3. package/dist/{AntiCheatDetector-BNk-EoBt.mjs → AntiCheatDetector-CqGDXmfc.mjs} +159 -53
  4. package/dist/{CodeInjector-Cq8q01kp.mjs → CodeInjector-BdjRfNx7.mjs} +5 -5
  5. package/dist/{ConsoleMonitor-CPVQW1Y-.mjs → ConsoleMonitor-DykL3IAw.mjs} +85 -17
  6. package/dist/{DetailedDataManager-BQQcxh64.mjs → DetailedDataManager-HT49OrvF.mjs} +1 -1
  7. package/dist/{ExtensionManager-CWYgw0YW.mjs → ExtensionManager-BDMsY2Dz.mjs} +15 -8
  8. package/dist/{HardwareBreakpoint-B9gZCdFP.mjs → HardwareBreakpoint-Cc2AFq1Y.mjs} +3 -3
  9. package/dist/{HeapAnalyzer-BLDH0dCv.mjs → HeapAnalyzer-DruMgsgj.mjs} +20 -20
  10. package/dist/{HookGeneratorBuilders.core.generators.storage-CtcdK78Q.mjs → HookGeneratorBuilders.core.generators.storage-CTbB4Lcx.mjs} +1 -74
  11. package/dist/{InstrumentationSession-CvPC7Jwy.mjs → InstrumentationSession-DLH0vd-z.mjs} +2 -2
  12. package/dist/{MemoryController-CbVdCIJF.mjs → MemoryController-CMtviNW_.mjs} +3 -3
  13. package/dist/{MemoryScanSession-BsDZbLYm.mjs → MemoryScanSession-ITgb_NMi.mjs} +2 -2
  14. package/dist/{MemoryScanner-Bcpml6II.mjs → MemoryScanner-CiL7Z3ey.mjs} +12 -9
  15. package/dist/{NativeMemoryManager.impl-dZtA1ZGn.mjs → NativeMemoryManager.impl-D9Lkovvn.mjs} +13 -10
  16. package/dist/{NativeMemoryManager.utils-B-FjA2mJ.mjs → NativeMemoryManager.utils-BBlAixF5.mjs} +1 -1
  17. package/dist/{PEAnalyzer-D1lzJ_VG.mjs → PEAnalyzer-DMQ44gen.mjs} +15 -15
  18. package/dist/{PageController-Bqm2kZ_X.mjs → PageController-BPJNqqBN.mjs} +18 -4
  19. package/dist/{PointerChainEngine-BOhyVsjx.mjs → PointerChainEngine-K7wN8Z-w.mjs} +10 -7
  20. package/dist/ProcessRegistry-zGg12QbE.mjs +74 -0
  21. package/dist/{ResponseBuilder-D3iFYx2N.mjs → ResponseBuilder-CJXWmWNw.mjs} +10 -10
  22. package/dist/{ScriptManager-aHHq0X7U.mjs → ScriptManager-ZuWD-0Jg.mjs} +195 -192
  23. package/dist/{Speedhack-CqdIFlQl.mjs → Speedhack-D-z0umeT.mjs} +2 -2
  24. package/dist/{StructureAnalyzer-DhFaPvRO.mjs → StructureAnalyzer-Cav5AVSL.mjs} +9 -6
  25. package/dist/{ToolCatalog-C0JGZoOm.mjs → ToolCatalog-5OJdMiF0.mjs} +81 -81
  26. package/dist/{ToolProbe-oC7aPrkv.mjs → ToolProbe-DbCFGyrg.mjs} +1 -1
  27. package/dist/{ToolRegistry-BjaF4oNz.mjs → ToolRegistry-B9krbTtI.mjs} +51 -2
  28. package/dist/{ToolRouter.policy-BWV67ZK-.mjs → ToolRouter.policy-BGDAGyeH.mjs} +60 -20
  29. package/dist/TraceRecorder-B41Z5XBj.mjs +1286 -0
  30. package/dist/{Win32API-CePkipZY.mjs → Win32API-C2kjj0ze.mjs} +18 -12
  31. package/dist/{Win32Debug-BvKs-gxc.mjs → Win32Debug-CKrGOTpo.mjs} +2 -2
  32. package/dist/{WorkflowEngine-CuvkZtWu.mjs → WorkflowEngine-DJ6M4opp.mjs} +226 -255
  33. package/dist/analysis-BHeJW2Nb.mjs +1234 -0
  34. package/dist/{antidebug-CqDTB_uk.mjs → antidebug-BRKeyt27.mjs} +3 -3
  35. package/dist/{artifactRetention-CFEprwPw.mjs → artifactRetention-CPXkUJXp.mjs} +13 -6
  36. package/dist/{artifacts-Bk2-_uPq.mjs → artifacts-DkfosXH3.mjs} +1 -1
  37. package/dist/authorization-schema-DRqyJMSk.mjs +31 -0
  38. package/dist/{binary-instrument-CXfpx6fT.mjs → binary-instrument--V3MAhJ4.mjs} +19 -27
  39. package/dist/bind-helpers-ClV34xdn.mjs +42 -0
  40. package/dist/{boringssl-inspector-BH2D3VKc.mjs → boringssl-inspector-Bo_LOLaS.mjs} +1 -1
  41. package/dist/{browser-BpOr5PEx.mjs → browser-Dx3_S2cG.mjs} +324 -37
  42. package/dist/capabilities-CcHlvWgK.mjs +33 -0
  43. package/dist/{constants-B0OANIBL.mjs → constants-CDZLOoVv.mjs} +18 -3
  44. package/dist/{coordination-qUbyF8KU.mjs → coordination-DgItD9DL.mjs} +2 -2
  45. package/dist/{debugger-gnKxRSN0.mjs → debugger-RS3RSAqs.mjs} +30 -13
  46. package/dist/definitions-BEoYofW5.mjs +47 -0
  47. package/dist/{definitions-bAhHQJq9.mjs → definitions-BRaefg3u.mjs} +11 -5
  48. package/dist/{definitions-DVGfrn7y.mjs → definitions-BbkvZkiv.mjs} +2 -2
  49. package/dist/definitions-BtWSHJ3o.mjs +17 -0
  50. package/dist/{definitions-BMfYXoNC.mjs → definitions-C1gCHO0i.mjs} +1 -1
  51. package/dist/{definitions-C1UvM5Iy.mjs → definitions-CDOg_b-l.mjs} +14 -2
  52. package/dist/definitions-CVPD9hzZ.mjs +54 -0
  53. package/dist/{definitions-Cke7zEb8.mjs → definitions-Cea8Lgl7.mjs} +1 -1
  54. package/dist/definitions-DAgIyjxM.mjs +10 -0
  55. package/dist/{definitions-B4rAvHNZ.mjs → definitions-DJA27nsL.mjs} +12 -9
  56. package/dist/{definitions-ClJLzsJQ.mjs → definitions-DKPFU3LW.mjs} +1 -1
  57. package/dist/{definitions-D3VsGcvz.mjs → definitions-DPRpZQ96.mjs} +7 -7
  58. package/dist/{definitions-B18eyf0B.mjs → definitions-DUE5gmdn.mjs} +1 -1
  59. package/dist/definitions-DYVjOtxa.mjs +26 -0
  60. package/dist/{definitions-BB_4jnmy.mjs → definitions-DcYLVLCo.mjs} +1 -1
  61. package/dist/{definitions-Beid2EB3.mjs → definitions-Pp5LI2H4.mjs} +1 -1
  62. package/dist/definitions-j9KdHVNR.mjs +14 -0
  63. package/dist/definitions-uzkjBwa7.mjs +258 -0
  64. package/dist/{definitions-Cq-zroAU.mjs → definitions-va-AnLuQ.mjs} +4 -4
  65. package/dist/{encoding-Bvz5jLRv.mjs → encoding-DJeqHmpd.mjs} +18 -4
  66. package/dist/{evidence-graph-bridge-C_fv9PuC.mjs → evidence-graph-bridge-DcYizFk2.mjs} +1 -0
  67. package/dist/{factory-DxlGh9Xf.mjs → factory-C90tBff6.mjs} +6 -6
  68. package/dist/flat-target-session-Dgax2Cy3.mjs +29 -0
  69. package/dist/{graphql-DYWzJ29s.mjs → graphql-CoHrhweh.mjs} +205 -34
  70. package/dist/{handlers-C67ktuRN.mjs → handlers-4jmR0nMs.mjs} +220 -32
  71. package/dist/{handlers-DlCJN4Td.mjs → handlers-BAHPxcch.mjs} +122 -90
  72. package/dist/{handlers-9sAbfIg-.mjs → handlers-BOs9b907.mjs} +849 -801
  73. package/dist/{handlers-DxGIq15_2.mjs → handlers-BWXEy6ef.mjs} +16 -16
  74. package/dist/{handlers-tB9Mp9ZK.mjs → handlers-Bndn6QvE.mjs} +31 -4
  75. package/dist/{handlers-CTsDAO6p.mjs → handlers-BqC4bD4s.mjs} +1 -1
  76. package/dist/{handlers-C87g8oCe.mjs → handlers-BtYq60bM2.mjs} +1 -1
  77. package/dist/{handlers-DeLOCd5m.mjs → handlers-BzgcB4iv.mjs} +17 -17
  78. package/dist/{handlers-Cgyg6c0U.mjs → handlers-CRyRWj2b.mjs} +237 -23
  79. package/dist/{handlers-U6L4xhuF.mjs → handlers-CVv2H1uq.mjs} +24 -17
  80. package/dist/{handlers-tiy7EIBp.mjs → handlers-Dl5a7JS4.mjs} +3 -3
  81. package/dist/{handlers-D6j6yka7.mjs → handlers-Dx2d7jt7.mjs} +1893 -1480
  82. package/dist/{handlers-Bl8zkwz1.mjs → handlers-Dz9PYsCa.mjs} +95 -6
  83. package/dist/handlers-HujRKC3b.mjs +661 -0
  84. package/dist/{handlers.impl-DS0d9fUw.mjs → handlers.impl-XWXkQfyi.mjs} +70 -24
  85. package/dist/{hooks-CzCWByww.mjs → hooks-B1B8NRHL.mjs} +3 -3
  86. package/dist/index.mjs +154 -144
  87. package/dist/{maintenance-P7ePRXQC.mjs → maintenance-PRMkLVRW.mjs} +35 -30
  88. package/dist/manifest-67Bok-Si.mjs +58 -0
  89. package/dist/{manifest-B3QVVeBS.mjs → manifest-6lNTMZAB2.mjs} +33 -28
  90. package/dist/manifest-B2duEHiH.mjs +90 -0
  91. package/dist/manifest-B6EY9Vm8.mjs +57 -0
  92. package/dist/{manifest-gZ4s_UtG.mjs → manifest-B6nKSbyY.mjs} +32 -33
  93. package/dist/{manifest-2ToTpjv8.mjs → manifest-BL8AQNPF.mjs} +31 -31
  94. package/dist/{manifest-DzwvxPJX.mjs → manifest-BSZvJJmV.mjs} +23 -14
  95. package/dist/{manifest-Sc_0JQ13.mjs → manifest-BU7qzUyX.mjs} +23 -23
  96. package/dist/{manifest-CT7zZBV1.mjs → manifest-Bl62e8WK.mjs} +24 -23
  97. package/dist/manifest-Bo5cXjdt.mjs +82 -0
  98. package/dist/manifest-BpS4gtUK.mjs +1347 -0
  99. package/dist/manifest-Bv65_e2W.mjs +101 -0
  100. package/dist/manifest-BytNIF4Z.mjs +117 -0
  101. package/dist/{manifest-BqrQ4Tpj.mjs → manifest-C-xtsjS3.mjs} +23 -23
  102. package/dist/{manifest-NXctwWQq.mjs → manifest-CDYl7OhA.mjs} +36 -38
  103. package/dist/manifest-CRZ3xmkD.mjs +61 -0
  104. package/dist/manifest-CoW6u4Tp.mjs +132 -0
  105. package/dist/manifest-Cq5zN_8A.mjs +50 -0
  106. package/dist/{manifest-CAhOuvSl.mjs → manifest-D7YZM_2e.mjs} +75 -85
  107. package/dist/{manifest-DCyjf4n2.mjs → manifest-DE_VrAeQ.mjs} +27 -7
  108. package/dist/manifest-DGsXSCpT.mjs +39 -0
  109. package/dist/{manifest-BB2J8IMJ.mjs → manifest-DJ2vfEuW.mjs} +48 -41
  110. package/dist/{manifest-3g71z6Bg.mjs → manifest-DPXDYhEu.mjs} +26 -25
  111. package/dist/manifest-Dd4fQb0a.mjs +322 -0
  112. package/dist/{manifest-CXsRWjjI.mjs → manifest-Deq6opGg.mjs} +95 -96
  113. package/dist/{manifest-C9RT5nk32.mjs → manifest-DfJTafJK.mjs} +14 -11
  114. package/dist/manifest-DgOdgN_j.mjs +50 -0
  115. package/dist/{manifest-BmtZzQiQ2.mjs → manifest-DlbMW4v4.mjs} +17 -15
  116. package/dist/{manifest-DrbmZcFl2.mjs → manifest-DmVfbH0w.mjs} +212 -91
  117. package/dist/manifest-Dog6Ddjr.mjs +109 -0
  118. package/dist/manifest-DvgU5FWb.mjs +58 -0
  119. package/dist/manifest-HsfDBs7j.mjs +50 -0
  120. package/dist/manifest-I8oQHvCG.mjs +186 -0
  121. package/dist/manifest-NvH_a-av.mjs +786 -0
  122. package/dist/{manifest-Dh8WBmEW.mjs → manifest-cEJU1v0Z.mjs} +24 -24
  123. package/dist/manifest-wOl5XLB12.mjs +112 -0
  124. package/dist/{modules-C184v-S9.mjs → modules-tZozf0LQ.mjs} +130 -860
  125. package/dist/{mojo-ipc-B_H61Afw.mjs → mojo-ipc-DXNEXEqb.mjs} +141 -26
  126. package/dist/{network-671Cw6hV.mjs → network-CPVvwvFg.mjs} +1329 -823
  127. package/dist/{outputPaths-B1uGmrWZ.mjs → outputPaths-um7lCRY3.mjs} +4 -8
  128. package/dist/{platform-WmNn8Sxb.mjs → platform-CYeFoTWp.mjs} +101 -10
  129. package/dist/{process-QcbIy5Zq.mjs → process-BTbgcVc6.mjs} +251 -346
  130. package/dist/{proxy-DqNs0bAd.mjs → proxy-r8YN6nP1.mjs} +30 -8
  131. package/dist/{registry-D-6e18lB.mjs → registry-Bl8ZQW61.mjs} +3 -3
  132. package/dist/{response-BQVP-xUn.mjs → response-CWhh2aLo.mjs} +7 -1
  133. package/dist/{shared-state-board-DV-dpHFJ.mjs → shared-state-board-BoZnSoj-.mjs} +2 -2
  134. package/dist/{sourcemap-Dq8ez8vS.mjs → sourcemap-BIDHUVXy.mjs} +350 -66
  135. package/dist/{streaming-BUQ0VJsg.mjs → streaming-Dal6utPp.mjs} +13 -13
  136. package/dist/{tool-builder-DCbIC5Eo.mjs → tool-builder-BHJp32mV.mjs} +1 -1
  137. package/dist/{transform-CiYJfNX0.mjs → transform-DRVgGG90.mjs} +18 -14
  138. package/dist/wasm-BYx5UOeG.mjs +1044 -0
  139. package/dist/webcrack-Be0_FccV.mjs +747 -0
  140. package/dist/{workflow-f3xJOcjx.mjs → workflow-BpuKEtvn.mjs} +8 -8
  141. package/package.json +76 -43
  142. package/dist/TraceRecorder-DgxyVbdQ.mjs +0 -519
  143. package/dist/analysis-CL9uACt9.mjs +0 -463
  144. package/dist/bind-helpers-xFfRF-qm.mjs +0 -22
  145. package/dist/definitions-6M-eejaT.mjs +0 -53
  146. package/dist/definitions-B3QdlrHv.mjs +0 -34
  147. package/dist/definitions-CXEI7QC72.mjs +0 -216
  148. package/dist/definitions-C_4r7Fo-2.mjs +0 -14
  149. package/dist/definitions-CkFDALoa.mjs +0 -26
  150. package/dist/definitions-Cy3Sl6gV.mjs +0 -34
  151. package/dist/definitions-LKpC3-nL.mjs +0 -9
  152. package/dist/handlers-DdFzXLvF.mjs +0 -446
  153. package/dist/manifest-82baTv4U.mjs +0 -45
  154. package/dist/manifest-BKbgbSiY.mjs +0 -60
  155. package/dist/manifest-Bcf-TJzH.mjs +0 -848
  156. package/dist/manifest-Bnd7kqEY.mjs +0 -55
  157. package/dist/manifest-BqQX6OQC2.mjs +0 -65
  158. package/dist/manifest-Br4RPFt5.mjs +0 -370
  159. package/dist/manifest-C5qDjysN.mjs +0 -107
  160. package/dist/manifest-CBYWCUBJ.mjs +0 -51
  161. package/dist/manifest-CFADCRa1.mjs +0 -37
  162. package/dist/manifest-CQVhavRF.mjs +0 -114
  163. package/dist/manifest-CV12bcrF.mjs +0 -121
  164. package/dist/manifest-CZLUCfG02.mjs +0 -95
  165. package/dist/manifest-D6phHKFd.mjs +0 -131
  166. package/dist/manifest-DHsnKgP6.mjs +0 -60
  167. package/dist/manifest-Df_dliIe.mjs +0 -55
  168. package/dist/manifest-DhKRAT8_.mjs +0 -92
  169. package/dist/manifest-DlpTj4ic2.mjs +0 -193
  170. package/dist/manifest-DuwHjUa5.mjs +0 -70
  171. package/dist/manifest-qSleDqdO.mjs +0 -1023
  172. package/dist/wasm-DQTnHDs4.mjs +0 -531
  173. /package/dist/{CacheAdapters-CDe5WPSV.mjs → CacheAdapters-jJFy20G-.mjs} +0 -0
  174. /package/dist/{DarwinAPI-BNPxu0RH.mjs → DarwinAPI-ETyy0xyo.mjs} +0 -0
  175. /package/dist/{EventBus-DgPmwpeu.mjs → EventBus-DFKvADm3.mjs} +0 -0
  176. /package/dist/{EvidenceGraphBridge-SFesNera.mjs → EvidenceGraphBridge-318Oi0Lf.mjs} +0 -0
  177. /package/dist/{FingerprintManager-gzWtkKuf.mjs → FingerprintManager-BN4UQWnX.mjs} +0 -0
  178. /package/dist/{PrerequisiteError-Dl33Svkz.mjs → PrerequisiteError-TuyZIs6n.mjs} +0 -0
  179. /package/dist/{ReverseEvidenceGraph-Dlsk94LC.mjs → ReverseEvidenceGraph-C02-gXOh.mjs} +0 -0
  180. /package/dist/{StealthVerifier-Bo4T3bz8.mjs → StealthVerifier-BWmPgQsv.mjs} +0 -0
  181. /package/dist/{VersionDetector-CwVLVdDM.mjs → VersionDetector-K3V4vGsw.mjs} +0 -0
  182. /package/dist/{betterSqlite3-0pqusHHH.mjs → betterSqlite3-DLSBZodi.mjs} +0 -0
  183. /package/dist/{concurrency-Bt0yv1kJ.mjs → concurrency-Drev_Vz9.mjs} +0 -0
  184. /package/dist/{formatAddress-DVkj9kpI.mjs → formatAddress-nnMvEohD.mjs} +0 -0
  185. /package/dist/{parse-args-BlRjqlkL.mjs → parse-args-B4cY5Vx5.mjs} +0 -0
  186. /package/dist/{ssrf-policy-ZaUfvhq7.mjs → ssrf-policy-Dsqd-DTX.mjs} +0 -0
  187. /package/dist/{types-CPhOReNX.mjs → types-DDBWs9UP.mjs} +0 -0
@@ -1,9 +1,11 @@
1
+ import { fr as SYSCALL_TRACE_DURATION_DEFAULT_SEC, mr as SYSCALL_TRACE_DURATION_MIN_SEC, pr as SYSCALL_TRACE_DURATION_MAX_SEC } from "./constants-CDZLOoVv.mjs";
1
2
  //#region src/modules/syscall-hook/SyscallMonitor.ts
2
3
  const SUPPORTED_BACKENDS = [
3
4
  "etw",
4
5
  "strace",
5
6
  "dtrace"
6
7
  ];
8
+ const TRACE_SPAWN_TIMEOUT_MS = 3e3;
7
9
  const SYNTHETIC_EVENT_SEEDS = {
8
10
  etw: [
9
11
  {
@@ -106,6 +108,31 @@ function cloneEvent(event) {
106
108
  duration: event.duration
107
109
  };
108
110
  }
111
+ function createSpawnReadyGuard(label, resolve, reject, terminate) {
112
+ let settled = false;
113
+ const timer = setTimeout(() => {
114
+ if (settled) return;
115
+ settled = true;
116
+ try {
117
+ terminate?.();
118
+ } catch {}
119
+ reject(/* @__PURE__ */ new Error(`${label} did not signal readiness within ${TRACE_SPAWN_TIMEOUT_MS}ms`));
120
+ }, TRACE_SPAWN_TIMEOUT_MS);
121
+ return {
122
+ resolveReady(process) {
123
+ if (settled) return;
124
+ settled = true;
125
+ clearTimeout(timer);
126
+ resolve(process);
127
+ },
128
+ rejectReady(error) {
129
+ if (settled) return;
130
+ settled = true;
131
+ clearTimeout(timer);
132
+ reject(error);
133
+ }
134
+ };
135
+ }
109
136
  function matchesFilter(event, filter) {
110
137
  if (!filter) return true;
111
138
  if (filter.pid !== void 0 && event.pid !== filter.pid) return false;
@@ -118,7 +145,7 @@ function matchesFilter(event, filter) {
118
145
  * Example strace line:
119
146
  * 12345 14:30:00.123456 openat(AT_FDCWD, "/tmp/foo", O_RDONLY) = 3 <0.000123>
120
147
  */
121
- function parseStraceLine(line, targetPid) {
148
+ function parseStraceLine(line, targetPid, startedAt) {
122
149
  const match = /^(\d+)\s+([\d:.]+)\s+(\w+)\(([^)]*)\)\s*=\s*(-?\d+)(?:\s+<([\d.]+)>)?$/u.exec(line.trim());
123
150
  if (!match) return null;
124
151
  const syscall = match[3] ?? "unknown";
@@ -127,7 +154,7 @@ function parseStraceLine(line, targetPid) {
127
154
  const duration = match[6] ? Number(match[6]) : void 0;
128
155
  const args = rawArgs.split(",").map((a) => a.trim()).filter((a) => a.length > 0);
129
156
  return {
130
- timestamp: Date.now(),
157
+ timestamp: Date.now() - startedAt,
131
158
  pid: targetPid,
132
159
  syscall,
133
160
  args,
@@ -141,7 +168,7 @@ function parseStraceLine(line, targetPid) {
141
168
  * Example ETW line:
142
169
  * [2024-01-15 14:30:00.123] PID=1234 NtCreateFile Handle=0x90 Status=0x00000000
143
170
  */
144
- function parseETWLine(line, targetPid) {
171
+ function parseETWLine(line, targetPid, startedAt) {
145
172
  const match = /^\[([^\]]+)\]\s+PID=(\d+)\s+(\w+)\s+(.*)$/u.exec(line.trim());
146
173
  if (!match) return null;
147
174
  const syscall = match[3] ?? "unknown";
@@ -149,7 +176,7 @@ function parseETWLine(line, targetPid) {
149
176
  const pid = Number(match[2]);
150
177
  const args = rawArgs.split(/\s+/u).filter((a) => a.length > 0);
151
178
  return {
152
- timestamp: Date.now(),
179
+ timestamp: Date.now() - startedAt,
153
180
  pid: Number.isFinite(pid) ? pid : targetPid,
154
181
  syscall,
155
182
  args
@@ -161,7 +188,7 @@ function parseETWLine(line, targetPid) {
161
188
  * Example dtrace line:
162
189
  * 1234 0 12345 open_nocancel:entry /private/tmp/foo O_RDONLY
163
190
  */
164
- function parseDTraceLine(line, targetPid) {
191
+ function parseDTraceLine(line, targetPid, startedAt) {
165
192
  const match = /^\s*(\d+)\s+\d+\s+(\d+)\s+(\w+):\w+\s+(.*)$/u.exec(line.trim());
166
193
  if (!match) return null;
167
194
  const syscall = match[3] ?? "unknown";
@@ -169,7 +196,7 @@ function parseDTraceLine(line, targetPid) {
169
196
  const pid = Number(match[2]);
170
197
  const args = rawArgs.split(/\s+/u).filter((a) => a.length > 0);
171
198
  return {
172
- timestamp: Date.now(),
199
+ timestamp: Date.now() - startedAt,
173
200
  pid: Number.isFinite(pid) ? pid : targetPid,
174
201
  syscall,
175
202
  args
@@ -182,12 +209,13 @@ var SyscallMonitor = class {
182
209
  subprocessError;
183
210
  async start(options) {
184
211
  const requestedBackend = options?.backend ?? chooseDefaultBackend();
212
+ const startedAt = Date.now();
185
213
  if (!isBackendSupportedOnCurrentPlatform(requestedBackend)) throw new Error(`Backend "${requestedBackend}" is not available on platform "${process.platform}"`);
186
214
  if (options?.simulate ?? process.env["JSHOOK_SIMULATE"] === "1") {
187
215
  this.activeState = {
188
216
  backend: requestedBackend,
189
217
  pid: options?.pid,
190
- startedAt: Date.now(),
218
+ startedAt,
191
219
  generatedEvents: 0
192
220
  };
193
221
  this.lastBackend = requestedBackend;
@@ -198,15 +226,15 @@ var SyscallMonitor = class {
198
226
  const pid = options?.pid ?? process.pid;
199
227
  let subprocess;
200
228
  try {
201
- if (requestedBackend === "strace") subprocess = await this.captureWithStrace(pid);
202
- else if (requestedBackend === "etw") subprocess = await this.captureWithETW(pid);
203
- else if (requestedBackend === "dtrace") subprocess = await this.captureWithDTrace(pid);
229
+ if (requestedBackend === "strace") subprocess = await this.captureWithStrace(pid, startedAt);
230
+ else if (requestedBackend === "etw") subprocess = await this.captureWithETW(pid, startedAt);
231
+ else if (requestedBackend === "dtrace") subprocess = await this.captureWithDTrace(pid, startedAt);
204
232
  } catch (error) {
205
233
  this.subprocessError = error instanceof Error ? error.message : String(error);
206
234
  this.activeState = {
207
235
  backend: requestedBackend,
208
236
  pid: options?.pid,
209
- startedAt: Date.now(),
237
+ startedAt,
210
238
  generatedEvents: 0
211
239
  };
212
240
  this.lastBackend = requestedBackend;
@@ -217,7 +245,7 @@ var SyscallMonitor = class {
217
245
  this.activeState = {
218
246
  backend: requestedBackend,
219
247
  pid: options?.pid,
220
- startedAt: Date.now(),
248
+ startedAt,
221
249
  generatedEvents: 0,
222
250
  subprocess
223
251
  };
@@ -257,7 +285,7 @@ var SyscallMonitor = class {
257
285
  * Spawn strace for syscall tracing on Linux.
258
286
  * Parses stdout into SyscallEvent objects.
259
287
  */
260
- async captureWithStrace(pid) {
288
+ async captureWithStrace(pid, startedAt = this.activeState?.startedAt ?? Date.now()) {
261
289
  const { spawn } = await import("node:child_process");
262
290
  return new Promise((resolve, reject) => {
263
291
  const subprocess = spawn("strace", [
@@ -272,6 +300,7 @@ var SyscallMonitor = class {
272
300
  "pipe",
273
301
  "pipe"
274
302
  ] });
303
+ const ready = createSpawnReadyGuard("strace process", resolve, reject, () => subprocess.kill("SIGTERM"));
275
304
  let stderrBuffer = "";
276
305
  let lineAccumulator = "";
277
306
  subprocess.stdout?.on("data", (chunk) => {
@@ -283,15 +312,15 @@ var SyscallMonitor = class {
283
312
  const lines = stderrBuffer.split(/\r?\n/u);
284
313
  stderrBuffer = lines.pop() ?? "";
285
314
  for (const line of lines) if (line.length > 0) {
286
- const event = parseStraceLine(line, pid);
315
+ const event = parseStraceLine(line, pid, startedAt);
287
316
  if (event) this.capturedEvents.push(event);
288
317
  }
289
318
  });
290
319
  subprocess.on("error", (error) => {
291
- reject(/* @__PURE__ */ new Error(`strace process error: ${error.message}. Is strace installed?`));
320
+ ready.rejectReady(/* @__PURE__ */ new Error(`strace process error: ${error.message}. Is strace installed?`));
292
321
  });
293
322
  subprocess.on("spawn", () => {
294
- resolve(subprocess);
323
+ ready.resolveReady(subprocess);
295
324
  });
296
325
  });
297
326
  }
@@ -299,7 +328,7 @@ var SyscallMonitor = class {
299
328
  * Spawn ETW tracing on Windows using logman.
300
329
  * Parses ETW trace output into SyscallEvent objects.
301
330
  */
302
- async captureWithETW(pid) {
331
+ async captureWithETW(pid, startedAt = this.activeState?.startedAt ?? Date.now()) {
303
332
  const { spawn } = await import("node:child_process");
304
333
  return new Promise((resolve, reject) => {
305
334
  const logman = spawn("logman", [
@@ -320,13 +349,14 @@ var SyscallMonitor = class {
320
349
  ],
321
350
  windowsHide: true
322
351
  });
352
+ const ready = createSpawnReadyGuard("ETW trace session", resolve, reject, () => logman.kill("SIGTERM"));
323
353
  let outputBuffer = "";
324
354
  logman.stdout?.on("data", (chunk) => {
325
355
  outputBuffer += chunk.toString();
326
356
  const lines = outputBuffer.split(/\r?\n/u);
327
357
  outputBuffer = lines.pop() ?? "";
328
358
  for (const line of lines) {
329
- const event = parseETWLine(line, pid);
359
+ const event = parseETWLine(line, pid, startedAt);
330
360
  if (event) this.capturedEvents.push(event);
331
361
  }
332
362
  });
@@ -335,13 +365,13 @@ var SyscallMonitor = class {
335
365
  if (msg.length > 0 && !msg.startsWith("The command completed successfully")) {}
336
366
  });
337
367
  logman.on("error", (error) => {
338
- reject(/* @__PURE__ */ new Error(`ETW trace error: ${error.message}. Run as Administrator.`));
368
+ ready.rejectReady(/* @__PURE__ */ new Error(`ETW trace error: ${error.message}. Run as Administrator.`));
339
369
  });
340
370
  logman.on("exit", (code) => {
341
- if (code !== 0 && code !== void 0) reject(/* @__PURE__ */ new Error(`ETW trace session ended (code ${code}). Check permissions.`));
371
+ if (code !== 0 && code !== void 0) ready.rejectReady(/* @__PURE__ */ new Error(`ETW trace session ended (code ${code}). Check permissions.`));
342
372
  });
343
373
  logman.on("spawn", () => {
344
- resolve(logman);
374
+ ready.resolveReady(logman);
345
375
  });
346
376
  });
347
377
  }
@@ -349,7 +379,7 @@ var SyscallMonitor = class {
349
379
  * Spawn dtrace for syscall tracing on macOS.
350
380
  * Parses dtrace output into SyscallEvent objects.
351
381
  */
352
- async captureWithDTrace(pid) {
382
+ async captureWithDTrace(pid, startedAt = this.activeState?.startedAt ?? Date.now()) {
353
383
  const { spawn } = await import("node:child_process");
354
384
  return new Promise((resolve, reject) => {
355
385
  const dtrace = spawn("dtrace", ["-n", `
@@ -363,22 +393,23 @@ var SyscallMonitor = class {
363
393
  "pipe",
364
394
  "pipe"
365
395
  ] });
396
+ const ready = createSpawnReadyGuard("dtrace process", resolve, reject, () => dtrace.kill("SIGTERM"));
366
397
  let outputBuffer = "";
367
398
  dtrace.stdout?.on("data", (chunk) => {
368
399
  outputBuffer += chunk.toString();
369
400
  const lines = outputBuffer.split(/\r?\n/u);
370
401
  outputBuffer = lines.pop() ?? "";
371
402
  for (const line of lines) {
372
- const event = parseDTraceLine(line, pid);
403
+ const event = parseDTraceLine(line, pid, startedAt);
373
404
  if (event) this.capturedEvents.push(event);
374
405
  }
375
406
  });
376
407
  dtrace.stderr?.on("data", () => {});
377
408
  dtrace.on("error", (error) => {
378
- reject(/* @__PURE__ */ new Error(`dtrace error: ${error.message}. Run with sudo.`));
409
+ ready.rejectReady(/* @__PURE__ */ new Error(`dtrace error: ${error.message}. Run with sudo.`));
379
410
  });
380
411
  dtrace.on("spawn", () => {
381
- resolve(dtrace);
412
+ ready.resolveReady(dtrace);
382
413
  });
383
414
  });
384
415
  }
@@ -392,7 +423,7 @@ var SyscallMonitor = class {
392
423
  while (this.activeState.generatedEvents < targetEventCount) {
393
424
  const seed = seeds[this.activeState.generatedEvents % seeds.length];
394
425
  if (!seed) break;
395
- const timestamp = this.activeState.startedAt + this.activeState.generatedEvents * 75;
426
+ const timestamp = this.activeState.generatedEvents * 75;
396
427
  this.capturedEvents.push({
397
428
  timestamp,
398
429
  pid,
@@ -531,6 +562,9 @@ function isRecord(value) {
531
562
  function readNumber(value) {
532
563
  if (typeof value === "number" && Number.isFinite(value)) return value;
533
564
  }
565
+ function readBoolean(value) {
566
+ if (typeof value === "boolean") return value;
567
+ }
534
568
  function readString(value) {
535
569
  if (typeof value === "string") return value;
536
570
  }
@@ -543,6 +577,10 @@ function readStringArray(value) {
543
577
  }
544
578
  return strings;
545
579
  }
580
+ const SYSCALL_NAME_RE = /^[a-z][a-z0-9_]*$/;
581
+ function isValidSyscallName(name) {
582
+ return SYSCALL_NAME_RE.test(name) && name.length <= 64;
583
+ }
546
584
  function readBackend(value) {
547
585
  if (value === "etw" || value === "strace" || value === "dtrace") return value;
548
586
  }
@@ -593,20 +631,26 @@ var SyscallHookHandlers = class {
593
631
  ok: false,
594
632
  error: "backend must be one of: etw, strace, dtrace"
595
633
  };
596
- const pid = readNumber(args["pid"]);
597
- if (args["pid"] !== void 0 && pid === void 0) return {
598
- ok: false,
599
- error: "pid must be a finite number when provided"
600
- };
634
+ const rawMonitorPid = readNumber(args["pid"]);
635
+ const simulate = readBoolean(args["simulate"]) ?? false;
636
+ if (args["pid"] !== void 0 && args["pid"] !== null) {
637
+ if (rawMonitorPid === void 0 || !Number.isInteger(rawMonitorPid) || rawMonitorPid < 0) return {
638
+ ok: false,
639
+ error: "pid must be a non-negative integer when provided"
640
+ };
641
+ }
642
+ const pid = rawMonitorPid;
601
643
  const monitor = this.ensureMonitor();
602
644
  try {
603
645
  await monitor.start({
604
646
  backend,
605
- pid
647
+ pid,
648
+ simulate
606
649
  });
607
650
  this.eventBus?.emit("syscall:trace_started", {
608
651
  backend,
609
652
  pid,
653
+ simulate,
610
654
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
611
655
  });
612
656
  return {
@@ -614,6 +658,7 @@ var SyscallHookHandlers = class {
614
658
  started: true,
615
659
  backend,
616
660
  pid,
661
+ simulate,
617
662
  stats: monitor.getStats()
618
663
  };
619
664
  } catch (error) {
@@ -697,6 +742,149 @@ var SyscallHookHandlers = class {
697
742
  supportedBackends: monitor.getSupportedBackends()
698
743
  };
699
744
  }
745
+ async handleSyscallEbpfTrace(args) {
746
+ const rawPid = readNumber(args["pid"]);
747
+ const syscalls = readStringArray(args["syscalls"]);
748
+ const durationSec = readNumber(args["durationSec"]) ?? SYSCALL_TRACE_DURATION_DEFAULT_SEC;
749
+ const simulate = readBoolean(args["simulate"]) ?? false;
750
+ if (args["pid"] !== void 0 && args["pid"] !== null) {
751
+ if (rawPid === void 0 || !Number.isInteger(rawPid) || rawPid < 0) return {
752
+ ok: false,
753
+ error: "pid must be a non-negative integer (0 for all processes)"
754
+ };
755
+ }
756
+ const pid = rawPid ?? 0;
757
+ if (durationSec < SYSCALL_TRACE_DURATION_MIN_SEC || durationSec > SYSCALL_TRACE_DURATION_MAX_SEC) return {
758
+ ok: false,
759
+ error: `durationSec must be between ${SYSCALL_TRACE_DURATION_MIN_SEC} and ${SYSCALL_TRACE_DURATION_MAX_SEC}`
760
+ };
761
+ if (syscalls?.length) {
762
+ const invalid = syscalls.filter((s) => !isValidSyscallName(s));
763
+ if (invalid.length > 0) return {
764
+ ok: false,
765
+ error: `Invalid syscall names (must be lowercase alphanumeric with underscores): ${invalid.join(", ")}`
766
+ };
767
+ }
768
+ if (simulate) {
769
+ const simulatedEvents = [];
770
+ const syscallPool = syscalls?.length ? syscalls : [
771
+ "read",
772
+ "write",
773
+ "openat",
774
+ "close",
775
+ "fstat",
776
+ "mmap",
777
+ "mprotect",
778
+ "munmap",
779
+ "brk",
780
+ "ioctl"
781
+ ];
782
+ const simulatedTimestampStepMs = durationSec * 50;
783
+ for (let i = 0; i < 20; i++) simulatedEvents.push({
784
+ timestamp: i * simulatedTimestampStepMs,
785
+ pid: pid || 1234,
786
+ syscall: syscallPool[i % syscallPool.length] ?? "read",
787
+ args: [`fd=${i % 5 + 3}`, `count=${(i + 1) * 64}`],
788
+ returnValue: i % 3 === 0 ? -1 : (i + 1) * 64,
789
+ duration: Math.random() * 2
790
+ });
791
+ return {
792
+ ok: true,
793
+ backend: "ebpf",
794
+ simulated: true,
795
+ pid,
796
+ durationSec,
797
+ events: simulatedEvents,
798
+ count: simulatedEvents.length,
799
+ syscallsTraced: syscallPool
800
+ };
801
+ }
802
+ const targetSyscalls = syscalls?.length ? syscalls : [
803
+ "read",
804
+ "write",
805
+ "openat",
806
+ "close",
807
+ "fstat",
808
+ "mmap",
809
+ "mprotect",
810
+ "munmap",
811
+ "brk",
812
+ "ioctl",
813
+ "connect",
814
+ "sendto",
815
+ "recvfrom",
816
+ "clone",
817
+ "execve"
818
+ ];
819
+ const pidFilter = pid > 0 ? `/pid == ${pid}/` : "";
820
+ const tracepoints = targetSyscalls.map((sc) => `tracepoint:syscalls:sys_enter_${sc}`).join(", ");
821
+ const exitTracepoints = targetSyscalls.map((sc) => `tracepoint:syscalls:sys_exit_${sc}`).join(", ");
822
+ const script = `#!/usr/bin/env bpftrace
823
+ // Generated by jshookmcp syscall_ebpf_trace
824
+ // Target PID: ${pid || "all"} | Duration: ${durationSec}s | Syscalls: ${targetSyscalls.join(", ")}
825
+
826
+ BEGIN {
827
+ printf("=== eBPF syscall trace started (pid=${pid || "all"}, duration=${durationSec}s) ===\\n");
828
+ }
829
+
830
+ ${tracepoints} ${pidFilter}
831
+ {
832
+ @enter_ts[tid] = nsecs;
833
+ printf("{\\"timestamp\\": %llu, \\"pid\\": %d, \\"tid\\": %d, \\"syscall\\": \\"%s\\", \\"phase\\": \\"enter\\", \\"args\\": {",
834
+ elapsed / 1000000, pid, tid, probe);
835
+ // Log key arguments based on syscall
836
+ if (probe == "tracepoint:syscalls:sys_enter_openat" || probe == "tracepoint:syscalls:sys_enter_open") {
837
+ printf("\\"pathname\\": \\"%s\\", \\"flags\\": %d, \\"mode\\": %d", args->pathname, args->flags, args->mode);
838
+ } else if (probe == "tracepoint:syscalls:sys_enter_read" || probe == "tracepoint:syscalls:sys_enter_write") {
839
+ printf("\\"fd\\": %d, \\"count\\": %d", args->fd, args->count);
840
+ } else if (probe == "tracepoint:syscalls:sys_enter_connect") {
841
+ printf("\\"fd\\": %d", args->fd);
842
+ } else if (probe == "tracepoint:syscalls:sys_enter_mmap") {
843
+ printf("\\"addr\\": %llu, \\"length\\": %llu, \\"prot\\": %d, \\"flags\\": %d, \\"fd\\": %d", args->addr, args->length, args->prot, args->flags, args->fd);
844
+ } else if (probe == "tracepoint:syscalls:sys_enter_execve") {
845
+ printf("\\"filename\\": \\"%s\\"", args->filename);
846
+ } else {
847
+ printf("\\"raw_args\\": \\"(see bpftrace -v output)\\"");
848
+ }
849
+ printf("}}\\n");
850
+ }
851
+
852
+ ${exitTracepoints} ${pidFilter}
853
+ {
854
+ $elapsed_ns = nsecs - @enter_ts[tid];
855
+ printf("{\\"timestamp\\": %llu, \\"pid\\": %d, \\"tid\\": %d, \\"syscall\\": \\"%s\\", \\"phase\\": \\"exit\\", \\"ret\\": %d, \\"duration_us\\": %llu}\\n",
856
+ elapsed / 1000000, pid, tid, probe, args->ret, $elapsed_ns / 1000);
857
+ delete(@enter_ts[tid]);
858
+ }
859
+
860
+ interval:s:${durationSec} {
861
+ printf("=== Trace duration (${durationSec}s) elapsed, exiting ===\\n");
862
+ exit();
863
+ }
864
+
865
+ END {
866
+ printf("=== eBPF syscall trace complete ===\\n");
867
+ clear(@enter_ts);
868
+ }
869
+ `;
870
+ return {
871
+ ok: true,
872
+ backend: "ebpf",
873
+ mode: "script",
874
+ pid,
875
+ durationSec,
876
+ syscallCount: targetSyscalls.length,
877
+ syscallsTraced: targetSyscalls,
878
+ script,
879
+ usage: `bpftrace -e '${script.replace(/'/g, "'\\''")}'`,
880
+ note: "Run the generated bpftrace script on a Linux system with bpftrace installed and CAP_BPF/root privileges.",
881
+ requiredCapabilities: [
882
+ "CAP_BPF",
883
+ "root",
884
+ "bpftrace"
885
+ ]
886
+ };
887
+ }
700
888
  ensureMonitor() {
701
889
  if (!this.monitor) this.monitor = new SyscallMonitor();
702
890
  return this.monitor;