@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.
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/dist/{AntiCheatDetector-BNk-EoBt.mjs → AntiCheatDetector-CqGDXmfc.mjs} +159 -53
- package/dist/{CodeInjector-Cq8q01kp.mjs → CodeInjector-BdjRfNx7.mjs} +5 -5
- package/dist/{ConsoleMonitor-CPVQW1Y-.mjs → ConsoleMonitor-DykL3IAw.mjs} +85 -17
- package/dist/{DetailedDataManager-BQQcxh64.mjs → DetailedDataManager-HT49OrvF.mjs} +1 -1
- package/dist/{ExtensionManager-CWYgw0YW.mjs → ExtensionManager-BDMsY2Dz.mjs} +15 -8
- package/dist/{HardwareBreakpoint-B9gZCdFP.mjs → HardwareBreakpoint-Cc2AFq1Y.mjs} +3 -3
- package/dist/{HeapAnalyzer-BLDH0dCv.mjs → HeapAnalyzer-DruMgsgj.mjs} +20 -20
- package/dist/{HookGeneratorBuilders.core.generators.storage-CtcdK78Q.mjs → HookGeneratorBuilders.core.generators.storage-CTbB4Lcx.mjs} +1 -74
- package/dist/{InstrumentationSession-CvPC7Jwy.mjs → InstrumentationSession-DLH0vd-z.mjs} +2 -2
- package/dist/{MemoryController-CbVdCIJF.mjs → MemoryController-CMtviNW_.mjs} +3 -3
- package/dist/{MemoryScanSession-BsDZbLYm.mjs → MemoryScanSession-ITgb_NMi.mjs} +2 -2
- package/dist/{MemoryScanner-Bcpml6II.mjs → MemoryScanner-CiL7Z3ey.mjs} +12 -9
- package/dist/{NativeMemoryManager.impl-dZtA1ZGn.mjs → NativeMemoryManager.impl-D9Lkovvn.mjs} +13 -10
- package/dist/{NativeMemoryManager.utils-B-FjA2mJ.mjs → NativeMemoryManager.utils-BBlAixF5.mjs} +1 -1
- package/dist/{PEAnalyzer-D1lzJ_VG.mjs → PEAnalyzer-DMQ44gen.mjs} +15 -15
- package/dist/{PageController-Bqm2kZ_X.mjs → PageController-BPJNqqBN.mjs} +18 -4
- package/dist/{PointerChainEngine-BOhyVsjx.mjs → PointerChainEngine-K7wN8Z-w.mjs} +10 -7
- package/dist/ProcessRegistry-zGg12QbE.mjs +74 -0
- package/dist/{ResponseBuilder-D3iFYx2N.mjs → ResponseBuilder-CJXWmWNw.mjs} +10 -10
- package/dist/{ScriptManager-aHHq0X7U.mjs → ScriptManager-ZuWD-0Jg.mjs} +195 -192
- package/dist/{Speedhack-CqdIFlQl.mjs → Speedhack-D-z0umeT.mjs} +2 -2
- package/dist/{StructureAnalyzer-DhFaPvRO.mjs → StructureAnalyzer-Cav5AVSL.mjs} +9 -6
- package/dist/{ToolCatalog-C0JGZoOm.mjs → ToolCatalog-5OJdMiF0.mjs} +81 -81
- package/dist/{ToolProbe-oC7aPrkv.mjs → ToolProbe-DbCFGyrg.mjs} +1 -1
- package/dist/{ToolRegistry-BjaF4oNz.mjs → ToolRegistry-B9krbTtI.mjs} +51 -2
- package/dist/{ToolRouter.policy-BWV67ZK-.mjs → ToolRouter.policy-BGDAGyeH.mjs} +60 -20
- package/dist/TraceRecorder-B41Z5XBj.mjs +1286 -0
- package/dist/{Win32API-CePkipZY.mjs → Win32API-C2kjj0ze.mjs} +18 -12
- package/dist/{Win32Debug-BvKs-gxc.mjs → Win32Debug-CKrGOTpo.mjs} +2 -2
- package/dist/{WorkflowEngine-CuvkZtWu.mjs → WorkflowEngine-DJ6M4opp.mjs} +226 -255
- package/dist/analysis-BHeJW2Nb.mjs +1234 -0
- package/dist/{antidebug-CqDTB_uk.mjs → antidebug-BRKeyt27.mjs} +3 -3
- package/dist/{artifactRetention-CFEprwPw.mjs → artifactRetention-CPXkUJXp.mjs} +13 -6
- package/dist/{artifacts-Bk2-_uPq.mjs → artifacts-DkfosXH3.mjs} +1 -1
- package/dist/authorization-schema-DRqyJMSk.mjs +31 -0
- package/dist/{binary-instrument-CXfpx6fT.mjs → binary-instrument--V3MAhJ4.mjs} +19 -27
- package/dist/bind-helpers-ClV34xdn.mjs +42 -0
- package/dist/{boringssl-inspector-BH2D3VKc.mjs → boringssl-inspector-Bo_LOLaS.mjs} +1 -1
- package/dist/{browser-BpOr5PEx.mjs → browser-Dx3_S2cG.mjs} +324 -37
- package/dist/capabilities-CcHlvWgK.mjs +33 -0
- package/dist/{constants-B0OANIBL.mjs → constants-CDZLOoVv.mjs} +18 -3
- package/dist/{coordination-qUbyF8KU.mjs → coordination-DgItD9DL.mjs} +2 -2
- package/dist/{debugger-gnKxRSN0.mjs → debugger-RS3RSAqs.mjs} +30 -13
- package/dist/definitions-BEoYofW5.mjs +47 -0
- package/dist/{definitions-bAhHQJq9.mjs → definitions-BRaefg3u.mjs} +11 -5
- package/dist/{definitions-DVGfrn7y.mjs → definitions-BbkvZkiv.mjs} +2 -2
- package/dist/definitions-BtWSHJ3o.mjs +17 -0
- package/dist/{definitions-BMfYXoNC.mjs → definitions-C1gCHO0i.mjs} +1 -1
- package/dist/{definitions-C1UvM5Iy.mjs → definitions-CDOg_b-l.mjs} +14 -2
- package/dist/definitions-CVPD9hzZ.mjs +54 -0
- package/dist/{definitions-Cke7zEb8.mjs → definitions-Cea8Lgl7.mjs} +1 -1
- package/dist/definitions-DAgIyjxM.mjs +10 -0
- package/dist/{definitions-B4rAvHNZ.mjs → definitions-DJA27nsL.mjs} +12 -9
- package/dist/{definitions-ClJLzsJQ.mjs → definitions-DKPFU3LW.mjs} +1 -1
- package/dist/{definitions-D3VsGcvz.mjs → definitions-DPRpZQ96.mjs} +7 -7
- package/dist/{definitions-B18eyf0B.mjs → definitions-DUE5gmdn.mjs} +1 -1
- package/dist/definitions-DYVjOtxa.mjs +26 -0
- package/dist/{definitions-BB_4jnmy.mjs → definitions-DcYLVLCo.mjs} +1 -1
- package/dist/{definitions-Beid2EB3.mjs → definitions-Pp5LI2H4.mjs} +1 -1
- package/dist/definitions-j9KdHVNR.mjs +14 -0
- package/dist/definitions-uzkjBwa7.mjs +258 -0
- package/dist/{definitions-Cq-zroAU.mjs → definitions-va-AnLuQ.mjs} +4 -4
- package/dist/{encoding-Bvz5jLRv.mjs → encoding-DJeqHmpd.mjs} +18 -4
- package/dist/{evidence-graph-bridge-C_fv9PuC.mjs → evidence-graph-bridge-DcYizFk2.mjs} +1 -0
- package/dist/{factory-DxlGh9Xf.mjs → factory-C90tBff6.mjs} +6 -6
- package/dist/flat-target-session-Dgax2Cy3.mjs +29 -0
- package/dist/{graphql-DYWzJ29s.mjs → graphql-CoHrhweh.mjs} +205 -34
- package/dist/{handlers-C67ktuRN.mjs → handlers-4jmR0nMs.mjs} +220 -32
- package/dist/{handlers-DlCJN4Td.mjs → handlers-BAHPxcch.mjs} +122 -90
- package/dist/{handlers-9sAbfIg-.mjs → handlers-BOs9b907.mjs} +849 -801
- package/dist/{handlers-DxGIq15_2.mjs → handlers-BWXEy6ef.mjs} +16 -16
- package/dist/{handlers-tB9Mp9ZK.mjs → handlers-Bndn6QvE.mjs} +31 -4
- package/dist/{handlers-CTsDAO6p.mjs → handlers-BqC4bD4s.mjs} +1 -1
- package/dist/{handlers-C87g8oCe.mjs → handlers-BtYq60bM2.mjs} +1 -1
- package/dist/{handlers-DeLOCd5m.mjs → handlers-BzgcB4iv.mjs} +17 -17
- package/dist/{handlers-Cgyg6c0U.mjs → handlers-CRyRWj2b.mjs} +237 -23
- package/dist/{handlers-U6L4xhuF.mjs → handlers-CVv2H1uq.mjs} +24 -17
- package/dist/{handlers-tiy7EIBp.mjs → handlers-Dl5a7JS4.mjs} +3 -3
- package/dist/{handlers-D6j6yka7.mjs → handlers-Dx2d7jt7.mjs} +1893 -1480
- package/dist/{handlers-Bl8zkwz1.mjs → handlers-Dz9PYsCa.mjs} +95 -6
- package/dist/handlers-HujRKC3b.mjs +661 -0
- package/dist/{handlers.impl-DS0d9fUw.mjs → handlers.impl-XWXkQfyi.mjs} +70 -24
- package/dist/{hooks-CzCWByww.mjs → hooks-B1B8NRHL.mjs} +3 -3
- package/dist/index.mjs +154 -144
- package/dist/{maintenance-P7ePRXQC.mjs → maintenance-PRMkLVRW.mjs} +35 -30
- package/dist/manifest-67Bok-Si.mjs +58 -0
- package/dist/{manifest-B3QVVeBS.mjs → manifest-6lNTMZAB2.mjs} +33 -28
- package/dist/manifest-B2duEHiH.mjs +90 -0
- package/dist/manifest-B6EY9Vm8.mjs +57 -0
- package/dist/{manifest-gZ4s_UtG.mjs → manifest-B6nKSbyY.mjs} +32 -33
- package/dist/{manifest-2ToTpjv8.mjs → manifest-BL8AQNPF.mjs} +31 -31
- package/dist/{manifest-DzwvxPJX.mjs → manifest-BSZvJJmV.mjs} +23 -14
- package/dist/{manifest-Sc_0JQ13.mjs → manifest-BU7qzUyX.mjs} +23 -23
- package/dist/{manifest-CT7zZBV1.mjs → manifest-Bl62e8WK.mjs} +24 -23
- package/dist/manifest-Bo5cXjdt.mjs +82 -0
- package/dist/manifest-BpS4gtUK.mjs +1347 -0
- package/dist/manifest-Bv65_e2W.mjs +101 -0
- package/dist/manifest-BytNIF4Z.mjs +117 -0
- package/dist/{manifest-BqrQ4Tpj.mjs → manifest-C-xtsjS3.mjs} +23 -23
- package/dist/{manifest-NXctwWQq.mjs → manifest-CDYl7OhA.mjs} +36 -38
- package/dist/manifest-CRZ3xmkD.mjs +61 -0
- package/dist/manifest-CoW6u4Tp.mjs +132 -0
- package/dist/manifest-Cq5zN_8A.mjs +50 -0
- package/dist/{manifest-CAhOuvSl.mjs → manifest-D7YZM_2e.mjs} +75 -85
- package/dist/{manifest-DCyjf4n2.mjs → manifest-DE_VrAeQ.mjs} +27 -7
- package/dist/manifest-DGsXSCpT.mjs +39 -0
- package/dist/{manifest-BB2J8IMJ.mjs → manifest-DJ2vfEuW.mjs} +48 -41
- package/dist/{manifest-3g71z6Bg.mjs → manifest-DPXDYhEu.mjs} +26 -25
- package/dist/manifest-Dd4fQb0a.mjs +322 -0
- package/dist/{manifest-CXsRWjjI.mjs → manifest-Deq6opGg.mjs} +95 -96
- package/dist/{manifest-C9RT5nk32.mjs → manifest-DfJTafJK.mjs} +14 -11
- package/dist/manifest-DgOdgN_j.mjs +50 -0
- package/dist/{manifest-BmtZzQiQ2.mjs → manifest-DlbMW4v4.mjs} +17 -15
- package/dist/{manifest-DrbmZcFl2.mjs → manifest-DmVfbH0w.mjs} +212 -91
- package/dist/manifest-Dog6Ddjr.mjs +109 -0
- package/dist/manifest-DvgU5FWb.mjs +58 -0
- package/dist/manifest-HsfDBs7j.mjs +50 -0
- package/dist/manifest-I8oQHvCG.mjs +186 -0
- package/dist/manifest-NvH_a-av.mjs +786 -0
- package/dist/{manifest-Dh8WBmEW.mjs → manifest-cEJU1v0Z.mjs} +24 -24
- package/dist/manifest-wOl5XLB12.mjs +112 -0
- package/dist/{modules-C184v-S9.mjs → modules-tZozf0LQ.mjs} +130 -860
- package/dist/{mojo-ipc-B_H61Afw.mjs → mojo-ipc-DXNEXEqb.mjs} +141 -26
- package/dist/{network-671Cw6hV.mjs → network-CPVvwvFg.mjs} +1329 -823
- package/dist/{outputPaths-B1uGmrWZ.mjs → outputPaths-um7lCRY3.mjs} +4 -8
- package/dist/{platform-WmNn8Sxb.mjs → platform-CYeFoTWp.mjs} +101 -10
- package/dist/{process-QcbIy5Zq.mjs → process-BTbgcVc6.mjs} +251 -346
- package/dist/{proxy-DqNs0bAd.mjs → proxy-r8YN6nP1.mjs} +30 -8
- package/dist/{registry-D-6e18lB.mjs → registry-Bl8ZQW61.mjs} +3 -3
- package/dist/{response-BQVP-xUn.mjs → response-CWhh2aLo.mjs} +7 -1
- package/dist/{shared-state-board-DV-dpHFJ.mjs → shared-state-board-BoZnSoj-.mjs} +2 -2
- package/dist/{sourcemap-Dq8ez8vS.mjs → sourcemap-BIDHUVXy.mjs} +350 -66
- package/dist/{streaming-BUQ0VJsg.mjs → streaming-Dal6utPp.mjs} +13 -13
- package/dist/{tool-builder-DCbIC5Eo.mjs → tool-builder-BHJp32mV.mjs} +1 -1
- package/dist/{transform-CiYJfNX0.mjs → transform-DRVgGG90.mjs} +18 -14
- package/dist/wasm-BYx5UOeG.mjs +1044 -0
- package/dist/webcrack-Be0_FccV.mjs +747 -0
- package/dist/{workflow-f3xJOcjx.mjs → workflow-BpuKEtvn.mjs} +8 -8
- package/package.json +76 -43
- package/dist/TraceRecorder-DgxyVbdQ.mjs +0 -519
- package/dist/analysis-CL9uACt9.mjs +0 -463
- package/dist/bind-helpers-xFfRF-qm.mjs +0 -22
- package/dist/definitions-6M-eejaT.mjs +0 -53
- package/dist/definitions-B3QdlrHv.mjs +0 -34
- package/dist/definitions-CXEI7QC72.mjs +0 -216
- package/dist/definitions-C_4r7Fo-2.mjs +0 -14
- package/dist/definitions-CkFDALoa.mjs +0 -26
- package/dist/definitions-Cy3Sl6gV.mjs +0 -34
- package/dist/definitions-LKpC3-nL.mjs +0 -9
- package/dist/handlers-DdFzXLvF.mjs +0 -446
- package/dist/manifest-82baTv4U.mjs +0 -45
- package/dist/manifest-BKbgbSiY.mjs +0 -60
- package/dist/manifest-Bcf-TJzH.mjs +0 -848
- package/dist/manifest-Bnd7kqEY.mjs +0 -55
- package/dist/manifest-BqQX6OQC2.mjs +0 -65
- package/dist/manifest-Br4RPFt5.mjs +0 -370
- package/dist/manifest-C5qDjysN.mjs +0 -107
- package/dist/manifest-CBYWCUBJ.mjs +0 -51
- package/dist/manifest-CFADCRa1.mjs +0 -37
- package/dist/manifest-CQVhavRF.mjs +0 -114
- package/dist/manifest-CV12bcrF.mjs +0 -121
- package/dist/manifest-CZLUCfG02.mjs +0 -95
- package/dist/manifest-D6phHKFd.mjs +0 -131
- package/dist/manifest-DHsnKgP6.mjs +0 -60
- package/dist/manifest-Df_dliIe.mjs +0 -55
- package/dist/manifest-DhKRAT8_.mjs +0 -92
- package/dist/manifest-DlpTj4ic2.mjs +0 -193
- package/dist/manifest-DuwHjUa5.mjs +0 -70
- package/dist/manifest-qSleDqdO.mjs +0 -1023
- package/dist/wasm-DQTnHDs4.mjs +0 -531
- /package/dist/{CacheAdapters-CDe5WPSV.mjs → CacheAdapters-jJFy20G-.mjs} +0 -0
- /package/dist/{DarwinAPI-BNPxu0RH.mjs → DarwinAPI-ETyy0xyo.mjs} +0 -0
- /package/dist/{EventBus-DgPmwpeu.mjs → EventBus-DFKvADm3.mjs} +0 -0
- /package/dist/{EvidenceGraphBridge-SFesNera.mjs → EvidenceGraphBridge-318Oi0Lf.mjs} +0 -0
- /package/dist/{FingerprintManager-gzWtkKuf.mjs → FingerprintManager-BN4UQWnX.mjs} +0 -0
- /package/dist/{PrerequisiteError-Dl33Svkz.mjs → PrerequisiteError-TuyZIs6n.mjs} +0 -0
- /package/dist/{ReverseEvidenceGraph-Dlsk94LC.mjs → ReverseEvidenceGraph-C02-gXOh.mjs} +0 -0
- /package/dist/{StealthVerifier-Bo4T3bz8.mjs → StealthVerifier-BWmPgQsv.mjs} +0 -0
- /package/dist/{VersionDetector-CwVLVdDM.mjs → VersionDetector-K3V4vGsw.mjs} +0 -0
- /package/dist/{betterSqlite3-0pqusHHH.mjs → betterSqlite3-DLSBZodi.mjs} +0 -0
- /package/dist/{concurrency-Bt0yv1kJ.mjs → concurrency-Drev_Vz9.mjs} +0 -0
- /package/dist/{formatAddress-DVkj9kpI.mjs → formatAddress-nnMvEohD.mjs} +0 -0
- /package/dist/{parse-args-BlRjqlkL.mjs → parse-args-B4cY5Vx5.mjs} +0 -0
- /package/dist/{ssrf-policy-ZaUfvhq7.mjs → ssrf-policy-Dsqd-DTX.mjs} +0 -0
- /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
|
|
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
|
|
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
|
|
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
|
-
|
|
320
|
+
ready.rejectReady(/* @__PURE__ */ new Error(`strace process error: ${error.message}. Is strace installed?`));
|
|
292
321
|
});
|
|
293
322
|
subprocess.on("spawn", () => {
|
|
294
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
409
|
+
ready.rejectReady(/* @__PURE__ */ new Error(`dtrace error: ${error.message}. Run with sudo.`));
|
|
379
410
|
});
|
|
380
411
|
dtrace.on("spawn", () => {
|
|
381
|
-
|
|
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.
|
|
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
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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;
|