@jshookmcp/jshook 0.1.5 → 0.1.6

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 (81) hide show
  1. package/LICENSE +661 -661
  2. package/README.md +72 -40
  3. package/README.zh.md +77 -40
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.js +13 -1
  6. package/dist/modules/analyzer/IntelligentAnalyzer.js +19 -11
  7. package/dist/modules/browser/BrowserModeManager.d.ts +5 -0
  8. package/dist/modules/browser/BrowserModeManager.js +96 -10
  9. package/dist/modules/browser/CamoufoxBrowserManager.d.ts +4 -0
  10. package/dist/modules/browser/CamoufoxBrowserManager.js +64 -3
  11. package/dist/modules/browser/TabRegistry.js +3 -2
  12. package/dist/modules/browser/UnifiedBrowserManager.d.ts +5 -0
  13. package/dist/modules/browser/UnifiedBrowserManager.js +62 -9
  14. package/dist/modules/captcha/AICaptchaDetector.js +185 -185
  15. package/dist/modules/debugger/DebuggerSessionManager.d.ts +4 -0
  16. package/dist/modules/debugger/DebuggerSessionManager.js +29 -19
  17. package/dist/modules/debugger/ScriptManager.impl.class.d.ts +4 -0
  18. package/dist/modules/debugger/ScriptManager.impl.class.js +46 -21
  19. package/dist/modules/emulator/EnvironmentEmulator.js +2 -2
  20. package/dist/modules/monitor/NetworkMonitor.impl.d.ts +1 -0
  21. package/dist/modules/monitor/NetworkMonitor.impl.js +22 -15
  22. package/dist/modules/monitor/PerformanceMonitor.js +64 -32
  23. package/dist/modules/process/LinuxProcessManager.d.ts +3 -1
  24. package/dist/modules/process/LinuxProcessManager.js +7 -3
  25. package/dist/modules/process/MacProcessManager.d.ts +3 -1
  26. package/dist/modules/process/MacProcessManager.js +32 -28
  27. package/dist/modules/process/ProcessManager.impl.d.ts +5 -1
  28. package/dist/modules/process/ProcessManager.impl.js +54 -13
  29. package/dist/modules/process/index.d.ts +3 -1
  30. package/dist/modules/process/index.js +2 -2
  31. package/dist/modules/process/memory/AuditTrail.d.ts +25 -0
  32. package/dist/modules/process/memory/AuditTrail.js +44 -0
  33. package/dist/modules/process/memory/availability.js +49 -49
  34. package/dist/modules/process/memory/injector.js +185 -185
  35. package/dist/modules/process/memory/linux/mapsParser.d.ts +16 -0
  36. package/dist/modules/process/memory/linux/mapsParser.js +28 -0
  37. package/dist/modules/process/memory/reader.js +50 -50
  38. package/dist/modules/process/memory/regions.enumerate.js +45 -1
  39. package/dist/modules/process/memory/regions.protection.js +48 -2
  40. package/dist/modules/process/memory/scanner.d.ts +4 -1
  41. package/dist/modules/process/memory/scanner.js +383 -182
  42. package/dist/modules/process/memory/writer.js +54 -54
  43. package/dist/native/NativeMemoryManager.impl.d.ts +4 -0
  44. package/dist/native/NativeMemoryManager.impl.js +72 -24
  45. package/dist/native/NativeMemoryManager.utils.d.ts +1 -0
  46. package/dist/native/NativeMemoryManager.utils.js +44 -1
  47. package/dist/native/scripts/linux/enum-windows.sh +12 -12
  48. package/dist/native/scripts/macos/enum-windows.applescript +22 -22
  49. package/dist/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
  50. package/dist/native/scripts/windows/enum-windows.ps1 +44 -44
  51. package/dist/native/scripts/windows/inject-dll.ps1 +21 -21
  52. package/dist/server/MCPServer.search.d.ts +3 -0
  53. package/dist/server/MCPServer.search.js +21 -2
  54. package/dist/server/ToolCallContextGuard.d.ts +2 -0
  55. package/dist/server/ToolCallContextGuard.js +29 -14
  56. package/dist/server/ToolSearch.js +11 -5
  57. package/dist/server/domains/browser/definitions.tools.page-core.js +53 -53
  58. package/dist/server/domains/browser/definitions.tools.runtime.js +40 -40
  59. package/dist/server/domains/browser/definitions.tools.security.js +76 -76
  60. package/dist/server/domains/browser/handlers/tab-workflow.js +6 -4
  61. package/dist/server/domains/maintenance/handlers.extensions.js +46 -26
  62. package/dist/server/domains/process/definitions.js +20 -7
  63. package/dist/server/domains/process/handlers.impl.core.runtime.base.d.ts +35 -0
  64. package/dist/server/domains/process/handlers.impl.core.runtime.base.js +107 -1
  65. package/dist/server/domains/process/handlers.impl.core.runtime.inject.js +111 -2
  66. package/dist/server/domains/process/handlers.impl.core.runtime.memory.d.ts +9 -0
  67. package/dist/server/domains/process/handlers.impl.core.runtime.memory.js +282 -31
  68. package/dist/server/domains/process/manifest.js +1 -0
  69. package/dist/server/domains/transform/handlers.impl.transform-base.js +102 -102
  70. package/dist/server/domains/workflow/handlers.impl.workflow-api.js +14 -4
  71. package/dist/server/domains/workflow/handlers.impl.workflow-base.js +51 -51
  72. package/dist/server/registry/discovery.js +17 -12
  73. package/dist/server/registry/index.js +10 -2
  74. package/dist/utils/TokenBudgetManager.d.ts +1 -0
  75. package/dist/utils/TokenBudgetManager.js +22 -0
  76. package/package.json +5 -1
  77. package/src/native/scripts/linux/enum-windows.sh +12 -12
  78. package/src/native/scripts/macos/enum-windows.applescript +22 -22
  79. package/src/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
  80. package/src/native/scripts/windows/enum-windows.ps1 +44 -44
  81. package/src/native/scripts/windows/inject-dll.ps1 +21 -21
@@ -233,28 +233,38 @@ async function rewriteLocalExtensionSdkDependency(installDir) {
233
233
  }
234
234
  }
235
235
  async function findRegistryEntryBySlug(registryBase, slug) {
236
- let workflowFetchError;
237
- try {
238
- const workflowIndex = await fetchJson(`${registryBase}/workflows.index.json`, { cacheKey: 'workflows' });
239
- const workflowEntry = workflowIndex.data.workflows.find((item) => item.slug === slug);
236
+ const [workflowResult, pluginResult] = await Promise.allSettled([
237
+ fetchJson(`${registryBase}/workflows.index.json`, { cacheKey: 'workflows' }),
238
+ fetchJson(`${registryBase}/plugins.index.json`, { cacheKey: 'plugins' }),
239
+ ]);
240
+ if (workflowResult.status === 'fulfilled') {
241
+ const workflows = Array.isArray(workflowResult.value.data.workflows)
242
+ ? workflowResult.value.data.workflows
243
+ : [];
244
+ const workflowEntry = workflows.find((item) => item.slug === slug);
240
245
  if (workflowEntry) {
241
246
  return { entry: workflowEntry, kind: 'workflow' };
242
247
  }
243
248
  }
244
- catch (error) {
245
- workflowFetchError = error instanceof Error ? error : new Error(String(error));
246
- }
247
- let pluginFetchError;
248
- try {
249
- const pluginIndex = await fetchJson(`${registryBase}/plugins.index.json`, { cacheKey: 'plugins' });
250
- const pluginEntry = pluginIndex.data.plugins.find((item) => item.slug === slug);
249
+ if (pluginResult.status === 'fulfilled') {
250
+ const plugins = Array.isArray(pluginResult.value.data.plugins)
251
+ ? pluginResult.value.data.plugins
252
+ : [];
253
+ const pluginEntry = plugins.find((item) => item.slug === slug);
251
254
  if (pluginEntry) {
252
255
  return { entry: pluginEntry, kind: 'plugin' };
253
256
  }
254
257
  }
255
- catch (error) {
256
- pluginFetchError = error instanceof Error ? error : new Error(String(error));
257
- }
258
+ const workflowFetchError = workflowResult.status === 'rejected'
259
+ ? workflowResult.reason instanceof Error
260
+ ? workflowResult.reason
261
+ : new Error(String(workflowResult.reason))
262
+ : undefined;
263
+ const pluginFetchError = pluginResult.status === 'rejected'
264
+ ? pluginResult.reason instanceof Error
265
+ ? pluginResult.reason
266
+ : new Error(String(pluginResult.reason))
267
+ : undefined;
258
268
  if (workflowFetchError && pluginFetchError) {
259
269
  throw new Error(`Failed to resolve extension slug "${slug}": workflow registry error: ${workflowFetchError.message}; plugin registry error: ${pluginFetchError.message}`);
260
270
  }
@@ -298,9 +308,19 @@ export class ExtensionManagementHandlers {
298
308
  const showWorkflows = kind === 'all' || kind === 'workflow';
299
309
  const result = { success: true };
300
310
  let stale = false;
301
- if (showPlugins) {
302
- const index = await fetchJson(`${registryBase}/plugins.index.json`, { cacheKey: 'plugins' });
303
- result.plugins = index.data.plugins.map((p) => ({
311
+ const pluginPromise = showPlugins
312
+ ? fetchJson(`${registryBase}/plugins.index.json`, { cacheKey: 'plugins' })
313
+ : undefined;
314
+ const workflowPromise = showWorkflows
315
+ ? fetchJson(`${registryBase}/workflows.index.json`, { cacheKey: 'workflows' })
316
+ : undefined;
317
+ const [pluginIndex, workflowIndex] = await Promise.all([
318
+ pluginPromise ?? Promise.resolve(undefined),
319
+ workflowPromise ?? Promise.resolve(undefined),
320
+ ]);
321
+ if (pluginIndex) {
322
+ const plugins = Array.isArray(pluginIndex.data.plugins) ? pluginIndex.data.plugins : [];
323
+ result.plugins = plugins.map((p) => ({
304
324
  slug: p.slug,
305
325
  id: p.id,
306
326
  name: p.meta.name,
@@ -310,13 +330,13 @@ export class ExtensionManagementHandlers {
310
330
  commit: p.source.commit,
311
331
  entry: p.source.entry,
312
332
  }));
313
- result.pluginCount = index.data.plugins.length;
314
- result.pluginSource = index.source;
315
- stale = stale || index.stale;
333
+ result.pluginCount = plugins.length;
334
+ result.pluginSource = pluginIndex.source;
335
+ stale = stale || pluginIndex.stale;
316
336
  }
317
- if (showWorkflows) {
318
- const index = await fetchJson(`${registryBase}/workflows.index.json`, { cacheKey: 'workflows' });
319
- result.workflows = index.data.workflows.map((w) => ({
337
+ if (workflowIndex) {
338
+ const workflows = Array.isArray(workflowIndex.data.workflows) ? workflowIndex.data.workflows : [];
339
+ result.workflows = workflows.map((w) => ({
320
340
  slug: w.slug,
321
341
  id: w.id,
322
342
  name: w.meta.name,
@@ -326,9 +346,9 @@ export class ExtensionManagementHandlers {
326
346
  commit: w.source.commit,
327
347
  entry: w.source.entry,
328
348
  }));
329
- result.workflowCount = index.data.workflows.length;
330
- result.workflowSource = index.source;
331
- stale = stale || index.stale;
349
+ result.workflowCount = workflows.length;
350
+ result.workflowSource = workflowIndex.source;
351
+ stale = stale || workflowIndex.stale;
332
352
  }
333
353
  if (stale) {
334
354
  result.stale = true;
@@ -121,7 +121,7 @@ export const processToolDefinitions = [
121
121
  },
122
122
  {
123
123
  name: 'memory_read',
124
- description: 'Read memory from a process at a specific address. Requires process to be attached.',
124
+ description: 'Read memory from a process at a specific address. Failures include structured diagnostics for permissions, region checks, and ASLR guidance.',
125
125
  inputSchema: {
126
126
  type: 'object',
127
127
  properties: {
@@ -143,7 +143,7 @@ export const processToolDefinitions = [
143
143
  },
144
144
  {
145
145
  name: 'memory_write',
146
- description: 'Write data to process memory at a specific address. Requires process to be attached.',
146
+ description: 'Write data to process memory at a specific address. Failures include structured diagnostics for permissions, region checks, and ASLR guidance.',
147
147
  inputSchema: {
148
148
  type: 'object',
149
149
  properties: {
@@ -171,7 +171,7 @@ export const processToolDefinitions = [
171
171
  },
172
172
  {
173
173
  name: 'memory_scan',
174
- description: 'Scan process memory for a pattern or value. Useful for finding game values.',
174
+ description: 'Scan process memory for a pattern or value. Failures include structured diagnostics for permissions, region checks, and ASLR guidance.',
175
175
  inputSchema: {
176
176
  type: 'object',
177
177
  properties: {
@@ -325,9 +325,22 @@ export const processToolDefinitions = [
325
325
  required: ['pid'],
326
326
  },
327
327
  },
328
+ {
329
+ name: 'memory_audit_export',
330
+ description: 'Export the in-memory audit trail for memory operations as JSON. Supports clear=true to flush the buffer after export.',
331
+ inputSchema: {
332
+ type: 'object',
333
+ properties: {
334
+ clear: {
335
+ type: 'boolean',
336
+ description: 'Clear audit trail after export',
337
+ },
338
+ },
339
+ },
340
+ },
328
341
  {
329
342
  name: 'inject_dll',
330
- description: 'Inject a DLL into a target process using CreateRemoteThread + LoadLibraryA. Requires administrator privileges.',
343
+ description: 'Inject a DLL into a target process using CreateRemoteThread + LoadLibraryA. Disabled by default; set ENABLE_INJECTION_TOOLS=true to enable. Requires administrator privileges.',
331
344
  inputSchema: {
332
345
  type: 'object',
333
346
  properties: {
@@ -345,7 +358,7 @@ export const processToolDefinitions = [
345
358
  },
346
359
  {
347
360
  name: 'module_inject_dll',
348
- description: 'Alias of inject_dll. Inject a DLL into a target process.',
361
+ description: 'Alias of inject_dll. Disabled by default; set ENABLE_INJECTION_TOOLS=true to enable.',
349
362
  inputSchema: {
350
363
  type: 'object',
351
364
  properties: {
@@ -363,7 +376,7 @@ export const processToolDefinitions = [
363
376
  },
364
377
  {
365
378
  name: 'inject_shellcode',
366
- description: 'Inject and execute shellcode in a target process. Uses VirtualAllocEx + WriteProcessMemory + CreateRemoteThread.',
379
+ description: 'Inject and execute shellcode in a target process. Accepts hex or base64. Disabled by default; set ENABLE_INJECTION_TOOLS=true to enable.',
367
380
  inputSchema: {
368
381
  type: 'object',
369
382
  properties: {
@@ -387,7 +400,7 @@ export const processToolDefinitions = [
387
400
  },
388
401
  {
389
402
  name: 'module_inject_shellcode',
390
- description: 'Alias of inject_shellcode. Inject and execute shellcode in a target process.',
403
+ description: 'Alias of inject_shellcode. Disabled by default; set ENABLE_INJECTION_TOOLS=true to enable.',
391
404
  inputSchema: {
392
405
  type: 'object',
393
406
  properties: {
@@ -1,4 +1,36 @@
1
1
  import { UnifiedProcessManager, MemoryManager } from '../../domains/shared/modules.js';
2
+ import { MemoryAuditTrail } from '../../../modules/process/memory/AuditTrail.js';
3
+ interface MemoryDiagnosticsInput {
4
+ pid?: number;
5
+ address?: string;
6
+ size?: number;
7
+ operation: string;
8
+ error?: string;
9
+ }
10
+ interface MemoryDiagnostics {
11
+ permission: {
12
+ available: boolean;
13
+ reason?: string;
14
+ platform: string;
15
+ };
16
+ process: {
17
+ exists: boolean | null;
18
+ pid: number | null;
19
+ name: string | null;
20
+ };
21
+ address: {
22
+ queried: boolean;
23
+ valid: boolean | null;
24
+ protection: string | null;
25
+ regionStart: string | null;
26
+ regionSize: number | null;
27
+ };
28
+ aslr: {
29
+ heuristic: true;
30
+ note: string;
31
+ };
32
+ recommendedActions: string[];
33
+ }
2
34
  export declare function validatePid(value: unknown): number;
3
35
  export declare function requireString(value: unknown, name: string): string;
4
36
  export declare function requirePositiveNumber(value: unknown, name: string): number;
@@ -6,7 +38,9 @@ export declare class ProcessToolHandlersBase {
6
38
  protected processManager: UnifiedProcessManager;
7
39
  protected memoryManager: MemoryManager;
8
40
  protected platform: string;
41
+ protected auditTrail: MemoryAuditTrail;
9
42
  constructor();
43
+ protected buildMemoryDiagnostics(input: MemoryDiagnosticsInput): Promise<MemoryDiagnostics>;
10
44
  handleProcessFind(args: Record<string, unknown>): Promise<{
11
45
  content: {
12
46
  type: string;
@@ -50,3 +84,4 @@ export declare class ProcessToolHandlersBase {
50
84
  }[];
51
85
  }>;
52
86
  }
87
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { UnifiedProcessManager, MemoryManager } from '../../domains/shared/modules.js';
2
+ import { MemoryAuditTrail } from '../../../modules/process/memory/AuditTrail.js';
2
3
  import { logger } from '../../../utils/logger.js';
3
4
  export function validatePid(value) {
4
5
  const n = Number(value);
@@ -22,12 +23,115 @@ export class ProcessToolHandlersBase {
22
23
  processManager;
23
24
  memoryManager;
24
25
  platform;
26
+ auditTrail = new MemoryAuditTrail();
25
27
  constructor() {
26
28
  this.processManager = new UnifiedProcessManager();
27
29
  this.memoryManager = new MemoryManager();
28
30
  this.platform = this.processManager.getPlatform();
29
31
  logger.info(`ProcessToolHandlers initialized for platform: ${this.platform}`);
30
32
  }
33
+ async buildMemoryDiagnostics(input) {
34
+ const recommendedActions = new Set();
35
+ const permission = await this.memoryManager.checkAvailability();
36
+ if (!permission.available) {
37
+ recommendedActions.add('Run as administrator');
38
+ }
39
+ let processInfo = null;
40
+ if (input.pid != null) {
41
+ try {
42
+ const resolvedProcess = await this.processManager.getProcessByPid(input.pid);
43
+ processInfo = resolvedProcess
44
+ ? {
45
+ pid: resolvedProcess.pid,
46
+ name: resolvedProcess.name,
47
+ executablePath: resolvedProcess.executablePath,
48
+ windowTitle: resolvedProcess.windowTitle,
49
+ windowHandle: resolvedProcess.windowHandle,
50
+ memoryUsage: resolvedProcess.memoryUsage,
51
+ }
52
+ : null;
53
+ }
54
+ catch {
55
+ processInfo = null;
56
+ }
57
+ if (!processInfo) {
58
+ recommendedActions.add('Check if process is still running');
59
+ }
60
+ }
61
+ let protectionInfo = null;
62
+ let protectionQueryFailed = false;
63
+ if (input.pid != null && input.address) {
64
+ try {
65
+ protectionInfo = await this.memoryManager.checkMemoryProtection(input.pid, input.address);
66
+ }
67
+ catch {
68
+ protectionQueryFailed = true;
69
+ }
70
+ if (protectionQueryFailed || protectionInfo?.success === false) {
71
+ recommendedActions.add('Verify address is within valid memory region');
72
+ }
73
+ }
74
+ if (input.size != null && protectionInfo?.regionSize != null && input.size > protectionInfo.regionSize) {
75
+ recommendedActions.add('Reduce the requested size to fit the target memory region');
76
+ }
77
+ if (input.operation === 'memory_read' && protectionInfo?.success && protectionInfo.isReadable === false) {
78
+ recommendedActions.add('Ensure target memory region is readable');
79
+ }
80
+ if (input.operation === 'memory_write' && protectionInfo?.success && protectionInfo.isWritable === false) {
81
+ recommendedActions.add('Ensure target memory region is writable');
82
+ }
83
+ let modulesEnumerated = false;
84
+ let moduleCount = null;
85
+ if (input.pid != null) {
86
+ try {
87
+ const modulesResult = await this.memoryManager.enumerateModules(input.pid);
88
+ modulesEnumerated = modulesResult.success;
89
+ moduleCount = modulesResult.modules?.length ?? null;
90
+ }
91
+ catch {
92
+ modulesEnumerated = false;
93
+ }
94
+ }
95
+ if (input.pid != null && input.address) {
96
+ recommendedActions.add('Re-resolve the address after the process restarts because ASLR can shift module addresses');
97
+ }
98
+ const normalizedError = input.error?.toLowerCase() ?? '';
99
+ if (normalizedError.includes('access denied') ||
100
+ normalizedError.includes('permission') ||
101
+ normalizedError.includes('privilege') ||
102
+ normalizedError.includes('administrator')) {
103
+ recommendedActions.add('Run as administrator');
104
+ }
105
+ const aslrNote = modulesEnumerated
106
+ ? moduleCount && moduleCount > 0
107
+ ? `Enumerated ${moduleCount} module(s). Treat absolute addresses as session-specific because ASLR can shift module bases between launches.`
108
+ : 'Module enumeration succeeded but returned no modules. Absolute addresses may still change across process launches because of ASLR.'
109
+ : 'Module enumeration was unavailable. Assume ASLR may shift absolute addresses between launches and re-resolve addresses after restarts.';
110
+ return {
111
+ permission: {
112
+ available: permission.available,
113
+ reason: permission.reason,
114
+ platform: this.platform,
115
+ },
116
+ process: {
117
+ exists: input.pid != null ? Boolean(processInfo) : null,
118
+ pid: input.pid ?? null,
119
+ name: processInfo?.name ?? null,
120
+ },
121
+ address: {
122
+ queried: input.pid != null && Boolean(input.address),
123
+ valid: input.pid != null && input.address ? protectionInfo?.success ?? null : null,
124
+ protection: protectionInfo?.protection ?? null,
125
+ regionStart: protectionInfo?.regionStart ?? null,
126
+ regionSize: protectionInfo?.regionSize ?? null,
127
+ },
128
+ aslr: {
129
+ heuristic: true,
130
+ note: aslrNote,
131
+ },
132
+ recommendedActions: Array.from(recommendedActions),
133
+ };
134
+ }
31
135
  async handleProcessFind(args) {
32
136
  try {
33
137
  const pattern = requireString(args.pattern, 'pattern');
@@ -86,7 +190,9 @@ export class ProcessToolHandlersBase {
86
190
  };
87
191
  }
88
192
  const cmdLine = await this.processManager.getProcessCommandLine(pid);
89
- const debugPort = await this.processManager.checkDebugPort(pid);
193
+ const debugPort = await this.processManager.checkDebugPort(pid, {
194
+ commandLine: cmdLine.commandLine,
195
+ });
90
196
  return {
91
197
  content: [
92
198
  {
@@ -1,12 +1,67 @@
1
1
  import { logger } from '../../../utils/logger.js';
2
+ import { ENABLE_INJECTION_TOOLS } from '../../../constants.js';
2
3
  import { ProcessToolHandlersMemory } from '../../domains/process/handlers.impl.core.runtime.memory.js';
3
4
  import { requireString, validatePid } from '../../domains/process/handlers.impl.core.runtime.base.js';
5
+ const INJECTION_TOOLS_DISABLED_ERROR = 'Injection tools are disabled by default for safety. Set ENABLE_INJECTION_TOOLS=true before starting the server to enable DLL and shellcode injection.';
6
+ const INJECTION_TOOLS_ENABLE_GUIDANCE = 'Set ENABLE_INJECTION_TOOLS=true before starting the server.';
7
+ const INJECTION_TOOLS_SECURITY_NOTICE = 'Only enable injection tools in an authorized debugging, lab, or CTF environment.';
8
+ function buildInjectionDisabledPayload() {
9
+ return {
10
+ success: false,
11
+ error: INJECTION_TOOLS_DISABLED_ERROR,
12
+ howToEnable: INJECTION_TOOLS_ENABLE_GUIDANCE,
13
+ securityNotice: INJECTION_TOOLS_SECURITY_NOTICE,
14
+ };
15
+ }
16
+ function getOptionalPid(value) {
17
+ const pid = Number(value);
18
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
19
+ }
20
+ function getOptionalString(value) {
21
+ return typeof value === 'string' && value.length > 0 ? value : null;
22
+ }
23
+ function getShellcodeSize(shellcode, encoding) {
24
+ if (encoding === 'hex') {
25
+ const normalized = shellcode.replace(/\s+/g, '');
26
+ return Math.ceil(normalized.length / 2);
27
+ }
28
+ return Buffer.from(shellcode, 'base64').length;
29
+ }
4
30
  export class ProcessToolHandlersRuntime extends ProcessToolHandlersMemory {
5
31
  async handleInjectDll(args) {
32
+ const startedAt = Date.now();
33
+ if (!ENABLE_INJECTION_TOOLS) {
34
+ this.recordMemoryAudit({
35
+ operation: 'inject_dll',
36
+ pid: getOptionalPid(args.pid),
37
+ address: getOptionalString(args.dllPath),
38
+ size: null,
39
+ result: 'failure',
40
+ error: INJECTION_TOOLS_DISABLED_ERROR,
41
+ durationMs: Date.now() - startedAt,
42
+ });
43
+ return {
44
+ content: [
45
+ {
46
+ type: 'text',
47
+ text: JSON.stringify(buildInjectionDisabledPayload(), null, 2),
48
+ },
49
+ ],
50
+ };
51
+ }
6
52
  try {
7
53
  const pid = validatePid(args.pid);
8
54
  const dllPath = requireString(args.dllPath, 'dllPath');
9
55
  const result = await this.memoryManager.injectDll(pid, dllPath);
56
+ this.recordMemoryAudit({
57
+ operation: 'inject_dll',
58
+ pid,
59
+ address: dllPath,
60
+ size: null,
61
+ result: result.success ? 'success' : 'failure',
62
+ error: result.error,
63
+ durationMs: Date.now() - startedAt,
64
+ });
10
65
  return {
11
66
  content: [
12
67
  {
@@ -18,22 +73,64 @@ export class ProcessToolHandlersRuntime extends ProcessToolHandlersMemory {
18
73
  }
19
74
  catch (error) {
20
75
  logger.error('DLL injection failed:', error);
76
+ const errorMessage = error instanceof Error ? error.message : String(error);
77
+ this.recordMemoryAudit({
78
+ operation: 'inject_dll',
79
+ pid: getOptionalPid(args.pid),
80
+ address: getOptionalString(args.dllPath),
81
+ size: null,
82
+ result: 'failure',
83
+ error: errorMessage,
84
+ durationMs: Date.now() - startedAt,
85
+ });
21
86
  return {
22
87
  content: [
23
88
  {
24
89
  type: 'text',
25
- text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2),
90
+ text: JSON.stringify({ success: false, error: errorMessage }, null, 2),
26
91
  },
27
92
  ],
28
93
  };
29
94
  }
30
95
  }
31
96
  async handleInjectShellcode(args) {
97
+ const startedAt = Date.now();
98
+ if (!ENABLE_INJECTION_TOOLS) {
99
+ const shellcode = getOptionalString(args.shellcode);
100
+ const encoding = args.encoding || 'hex';
101
+ this.recordMemoryAudit({
102
+ operation: 'inject_shellcode',
103
+ pid: getOptionalPid(args.pid),
104
+ address: null,
105
+ size: shellcode ? getShellcodeSize(shellcode, encoding) : null,
106
+ result: 'failure',
107
+ error: INJECTION_TOOLS_DISABLED_ERROR,
108
+ durationMs: Date.now() - startedAt,
109
+ });
110
+ return {
111
+ content: [
112
+ {
113
+ type: 'text',
114
+ text: JSON.stringify(buildInjectionDisabledPayload(), null, 2),
115
+ },
116
+ ],
117
+ };
118
+ }
32
119
  try {
33
120
  const pid = validatePid(args.pid);
34
121
  const shellcode = requireString(args.shellcode, 'shellcode');
35
122
  const encoding = args.encoding || 'hex';
123
+ const size = getShellcodeSize(shellcode, encoding);
36
124
  const result = await this.memoryManager.injectShellcode(pid, shellcode, encoding);
125
+ this.recordMemoryAudit({
126
+ operation: 'inject_shellcode',
127
+ pid,
128
+ address: null,
129
+ size,
130
+ result: result.success ? 'success' : 'failure',
131
+ error: result.error,
132
+ durationMs: Date.now() - startedAt,
133
+ });
37
134
  return {
38
135
  content: [
39
136
  {
@@ -45,11 +142,23 @@ export class ProcessToolHandlersRuntime extends ProcessToolHandlersMemory {
45
142
  }
46
143
  catch (error) {
47
144
  logger.error('Shellcode injection failed:', error);
145
+ const errorMessage = error instanceof Error ? error.message : String(error);
146
+ const shellcode = getOptionalString(args.shellcode);
147
+ const encoding = args.encoding || 'hex';
148
+ this.recordMemoryAudit({
149
+ operation: 'inject_shellcode',
150
+ pid: getOptionalPid(args.pid),
151
+ address: null,
152
+ size: shellcode ? getShellcodeSize(shellcode, encoding) : null,
153
+ result: 'failure',
154
+ error: errorMessage,
155
+ durationMs: Date.now() - startedAt,
156
+ });
48
157
  return {
49
158
  content: [
50
159
  {
51
160
  type: 'text',
52
- text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2),
161
+ text: JSON.stringify({ success: false, error: errorMessage }, null, 2),
53
162
  },
54
163
  ],
55
164
  };
@@ -1,5 +1,8 @@
1
+ import type { AuditEntry } from '../../../modules/process/memory/AuditTrail.js';
1
2
  import { ProcessToolHandlersBase } from '../../domains/process/handlers.impl.core.runtime.base.js';
2
3
  export declare class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
4
+ private safeBuildMemoryDiagnostics;
5
+ protected recordMemoryAudit(entry: Omit<AuditEntry, 'timestamp' | 'user'>): void;
3
6
  handleMemoryRead(args: Record<string, unknown>): Promise<{
4
7
  content: {
5
8
  type: string;
@@ -18,6 +21,12 @@ export declare class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
18
21
  text: string;
19
22
  }[];
20
23
  }>;
24
+ handleMemoryAuditExport(args: Record<string, unknown>): Promise<{
25
+ content: {
26
+ type: string;
27
+ text: string;
28
+ }[];
29
+ }>;
21
30
  handleMemoryCheckProtection(args: Record<string, unknown>): Promise<{
22
31
  content: {
23
32
  type: string;