@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.
- package/LICENSE +661 -661
- package/README.md +72 -40
- package/README.zh.md +77 -40
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +13 -1
- package/dist/modules/analyzer/IntelligentAnalyzer.js +19 -11
- package/dist/modules/browser/BrowserModeManager.d.ts +5 -0
- package/dist/modules/browser/BrowserModeManager.js +96 -10
- package/dist/modules/browser/CamoufoxBrowserManager.d.ts +4 -0
- package/dist/modules/browser/CamoufoxBrowserManager.js +64 -3
- package/dist/modules/browser/TabRegistry.js +3 -2
- package/dist/modules/browser/UnifiedBrowserManager.d.ts +5 -0
- package/dist/modules/browser/UnifiedBrowserManager.js +62 -9
- package/dist/modules/captcha/AICaptchaDetector.js +185 -185
- package/dist/modules/debugger/DebuggerSessionManager.d.ts +4 -0
- package/dist/modules/debugger/DebuggerSessionManager.js +29 -19
- package/dist/modules/debugger/ScriptManager.impl.class.d.ts +4 -0
- package/dist/modules/debugger/ScriptManager.impl.class.js +46 -21
- package/dist/modules/emulator/EnvironmentEmulator.js +2 -2
- package/dist/modules/monitor/NetworkMonitor.impl.d.ts +1 -0
- package/dist/modules/monitor/NetworkMonitor.impl.js +22 -15
- package/dist/modules/monitor/PerformanceMonitor.js +64 -32
- package/dist/modules/process/LinuxProcessManager.d.ts +3 -1
- package/dist/modules/process/LinuxProcessManager.js +7 -3
- package/dist/modules/process/MacProcessManager.d.ts +3 -1
- package/dist/modules/process/MacProcessManager.js +32 -28
- package/dist/modules/process/ProcessManager.impl.d.ts +5 -1
- package/dist/modules/process/ProcessManager.impl.js +54 -13
- package/dist/modules/process/index.d.ts +3 -1
- package/dist/modules/process/index.js +2 -2
- package/dist/modules/process/memory/AuditTrail.d.ts +25 -0
- package/dist/modules/process/memory/AuditTrail.js +44 -0
- package/dist/modules/process/memory/availability.js +49 -49
- package/dist/modules/process/memory/injector.js +185 -185
- package/dist/modules/process/memory/linux/mapsParser.d.ts +16 -0
- package/dist/modules/process/memory/linux/mapsParser.js +28 -0
- package/dist/modules/process/memory/reader.js +50 -50
- package/dist/modules/process/memory/regions.enumerate.js +45 -1
- package/dist/modules/process/memory/regions.protection.js +48 -2
- package/dist/modules/process/memory/scanner.d.ts +4 -1
- package/dist/modules/process/memory/scanner.js +383 -182
- package/dist/modules/process/memory/writer.js +54 -54
- package/dist/native/NativeMemoryManager.impl.d.ts +4 -0
- package/dist/native/NativeMemoryManager.impl.js +72 -24
- package/dist/native/NativeMemoryManager.utils.d.ts +1 -0
- package/dist/native/NativeMemoryManager.utils.js +44 -1
- package/dist/native/scripts/linux/enum-windows.sh +12 -12
- package/dist/native/scripts/macos/enum-windows.applescript +22 -22
- package/dist/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
- package/dist/native/scripts/windows/enum-windows.ps1 +44 -44
- package/dist/native/scripts/windows/inject-dll.ps1 +21 -21
- package/dist/server/MCPServer.search.d.ts +3 -0
- package/dist/server/MCPServer.search.js +21 -2
- package/dist/server/ToolCallContextGuard.d.ts +2 -0
- package/dist/server/ToolCallContextGuard.js +29 -14
- package/dist/server/ToolSearch.js +11 -5
- package/dist/server/domains/browser/definitions.tools.page-core.js +53 -53
- package/dist/server/domains/browser/definitions.tools.runtime.js +40 -40
- package/dist/server/domains/browser/definitions.tools.security.js +76 -76
- package/dist/server/domains/browser/handlers/tab-workflow.js +6 -4
- package/dist/server/domains/maintenance/handlers.extensions.js +46 -26
- package/dist/server/domains/process/definitions.js +20 -7
- package/dist/server/domains/process/handlers.impl.core.runtime.base.d.ts +35 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.base.js +107 -1
- package/dist/server/domains/process/handlers.impl.core.runtime.inject.js +111 -2
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.d.ts +9 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.js +282 -31
- package/dist/server/domains/process/manifest.js +1 -0
- package/dist/server/domains/transform/handlers.impl.transform-base.js +102 -102
- package/dist/server/domains/workflow/handlers.impl.workflow-api.js +14 -4
- package/dist/server/domains/workflow/handlers.impl.workflow-base.js +51 -51
- package/dist/server/registry/discovery.js +17 -12
- package/dist/server/registry/index.js +10 -2
- package/dist/utils/TokenBudgetManager.d.ts +1 -0
- package/dist/utils/TokenBudgetManager.js +22 -0
- package/package.json +5 -1
- package/src/native/scripts/linux/enum-windows.sh +12 -12
- package/src/native/scripts/macos/enum-windows.applescript +22 -22
- package/src/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
- package/src/native/scripts/windows/enum-windows.ps1 +44 -44
- package/src/native/scripts/windows/inject-dll.ps1 +21 -21
|
@@ -119,8 +119,7 @@ export class WorkflowHandlersApi extends WorkflowHandlersBase {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
var results = {};
|
|
122
|
-
|
|
123
|
-
var path = paths[i];
|
|
122
|
+
async function probePath(path) {
|
|
124
123
|
try {
|
|
125
124
|
var opts = {method: method, headers: headers};
|
|
126
125
|
if (bodyTemplate && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
|
@@ -137,11 +136,22 @@ export class WorkflowHandlersApi extends WorkflowHandlersBase {
|
|
|
137
136
|
snippet = '[HTML/XML response suppressed]';
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
|
-
|
|
139
|
+
return [path, {status: resp.status, contentType: ct.split(';')[0].trim(), snippet: snippet}];
|
|
141
140
|
} catch(e) {
|
|
142
|
-
|
|
141
|
+
return [path, {status: -1, error: e instanceof Error ? e.message : String(e)}];
|
|
143
142
|
}
|
|
144
143
|
}
|
|
144
|
+
|
|
145
|
+
var nextIndex = 0;
|
|
146
|
+
var maxConcurrency = Math.min(paths.length, 6);
|
|
147
|
+
await Promise.all(Array.from({ length: maxConcurrency }, async function() {
|
|
148
|
+
while (nextIndex < paths.length) {
|
|
149
|
+
var currentIndex = nextIndex++;
|
|
150
|
+
var currentPath = paths[currentIndex];
|
|
151
|
+
var entry = await probePath(currentPath);
|
|
152
|
+
results[entry[0]] = entry[1];
|
|
153
|
+
}
|
|
154
|
+
}));
|
|
145
155
|
return {probed: paths.length, method: method, baseUrl: baseUrl, results: results};
|
|
146
156
|
})()`;
|
|
147
157
|
try {
|
|
@@ -164,69 +164,69 @@ export class WorkflowHandlersBase {
|
|
|
164
164
|
initBuiltinScripts() {
|
|
165
165
|
this.scriptRegistry.set('auth_extract', {
|
|
166
166
|
description: 'Extract auth tokens from localStorage and cookies',
|
|
167
|
-
code: `(function(){
|
|
168
|
-
var keys=['token','active_token','access_token','jwt','auth_token','userRole','id_token','refresh_token'];
|
|
169
|
-
var r={};
|
|
170
|
-
for(var i=0;i<keys.length;i++){var v=localStorage.getItem(keys[i]);if(v)r[keys[i]]=v;}
|
|
171
|
-
r._cookies=document.cookie;
|
|
172
|
-
return r;
|
|
167
|
+
code: `(function(){
|
|
168
|
+
var keys=['token','active_token','access_token','jwt','auth_token','userRole','id_token','refresh_token'];
|
|
169
|
+
var r={};
|
|
170
|
+
for(var i=0;i<keys.length;i++){var v=localStorage.getItem(keys[i]);if(v)r[keys[i]]=v;}
|
|
171
|
+
r._cookies=document.cookie;
|
|
172
|
+
return r;
|
|
173
173
|
})()`,
|
|
174
174
|
});
|
|
175
175
|
this.scriptRegistry.set('bundle_search', {
|
|
176
176
|
description: 'Fetch a remote JS bundle and search it with regex patterns. params: { url: string, patterns: string[] }',
|
|
177
|
-
code: `(async function(){
|
|
178
|
-
var p=typeof __params__!=='undefined'?__params__:{};
|
|
179
|
-
if(!p.url)return{error:'params.url required'};
|
|
180
|
-
var resp=await fetch(p.url);
|
|
181
|
-
var text=await resp.text();
|
|
182
|
-
var patterns=p.patterns||[];
|
|
183
|
-
var results={};
|
|
184
|
-
for(var i=0;i<patterns.length;i++){
|
|
185
|
-
var re=new RegExp(patterns[i],'g');
|
|
186
|
-
var matches=[];var m;
|
|
187
|
-
while((m=re.exec(text))!==null){
|
|
188
|
-
var s=Math.max(0,m.index-80),e=Math.min(text.length,m.index+m[0].length+80);
|
|
189
|
-
matches.push({match:m[0],ctx:text.slice(s,e)});
|
|
190
|
-
if(matches.length>=10)break;
|
|
191
|
-
}
|
|
192
|
-
results[patterns[i]]=matches;
|
|
193
|
-
}
|
|
194
|
-
return{size:text.length,results:results};
|
|
177
|
+
code: `(async function(){
|
|
178
|
+
var p=typeof __params__!=='undefined'?__params__:{};
|
|
179
|
+
if(!p.url)return{error:'params.url required'};
|
|
180
|
+
var resp=await fetch(p.url);
|
|
181
|
+
var text=await resp.text();
|
|
182
|
+
var patterns=p.patterns||[];
|
|
183
|
+
var results={};
|
|
184
|
+
for(var i=0;i<patterns.length;i++){
|
|
185
|
+
var re=new RegExp(patterns[i],'g');
|
|
186
|
+
var matches=[];var m;
|
|
187
|
+
while((m=re.exec(text))!==null){
|
|
188
|
+
var s=Math.max(0,m.index-80),e=Math.min(text.length,m.index+m[0].length+80);
|
|
189
|
+
matches.push({match:m[0],ctx:text.slice(s,e)});
|
|
190
|
+
if(matches.length>=10)break;
|
|
191
|
+
}
|
|
192
|
+
results[patterns[i]]=matches;
|
|
193
|
+
}
|
|
194
|
+
return{size:text.length,results:results};
|
|
195
195
|
})()`,
|
|
196
196
|
});
|
|
197
197
|
this.scriptRegistry.set('react_fill_form', {
|
|
198
198
|
description: 'Fill React controlled form inputs using native setter trick. params: { fields: { "selector": "value" } }',
|
|
199
|
-
code: `(function(){
|
|
200
|
-
var p=typeof __params__!=='undefined'?__params__:{};
|
|
201
|
-
var fields=p.fields||{};
|
|
202
|
-
var ns=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set;
|
|
203
|
-
var r={};
|
|
204
|
-
var entries=Object.entries(fields);
|
|
205
|
-
for(var i=0;i<entries.length;i++){
|
|
206
|
-
var sel=entries[i][0],val=entries[i][1];
|
|
207
|
-
var el=document.querySelector(sel);
|
|
208
|
-
if(!el){r[sel]='not found';continue;}
|
|
209
|
-
ns.call(el,val);
|
|
210
|
-
el.dispatchEvent(new Event('input',{bubbles:true}));
|
|
211
|
-
el.dispatchEvent(new Event('change',{bubbles:true}));
|
|
212
|
-
r[sel]='filled';
|
|
213
|
-
}
|
|
214
|
-
return r;
|
|
199
|
+
code: `(function(){
|
|
200
|
+
var p=typeof __params__!=='undefined'?__params__:{};
|
|
201
|
+
var fields=p.fields||{};
|
|
202
|
+
var ns=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set;
|
|
203
|
+
var r={};
|
|
204
|
+
var entries=Object.entries(fields);
|
|
205
|
+
for(var i=0;i<entries.length;i++){
|
|
206
|
+
var sel=entries[i][0],val=entries[i][1];
|
|
207
|
+
var el=document.querySelector(sel);
|
|
208
|
+
if(!el){r[sel]='not found';continue;}
|
|
209
|
+
ns.call(el,val);
|
|
210
|
+
el.dispatchEvent(new Event('input',{bubbles:true}));
|
|
211
|
+
el.dispatchEvent(new Event('change',{bubbles:true}));
|
|
212
|
+
r[sel]='filled';
|
|
213
|
+
}
|
|
214
|
+
return r;
|
|
215
215
|
})()`,
|
|
216
216
|
});
|
|
217
217
|
this.scriptRegistry.set('dom_find_upgrade_buttons', {
|
|
218
218
|
description: 'Scan the current page for upgrade/subscription/tier-related UI elements',
|
|
219
|
-
code: `(function(){
|
|
220
|
-
var kw=['upgrade','plus','pro','premium','subscribe','plan','tier','vip','membership'];
|
|
221
|
-
var r=[];
|
|
222
|
-
document.querySelectorAll('button,a,[role=button],[class*=upgrade],[class*=premium],[class*=plus]').forEach(function(el){
|
|
223
|
-
var t=(el.textContent||'').toLowerCase().trim();
|
|
224
|
-
var c=(el.className||'').toLowerCase();
|
|
225
|
-
if(kw.some(function(k){return t.includes(k)||c.includes(k);})){
|
|
226
|
-
r.push({tag:el.tagName,text:t.slice(0,120),cls:c.slice(0,100),href:el.href||null,id:el.id||null});
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
return r;
|
|
219
|
+
code: `(function(){
|
|
220
|
+
var kw=['upgrade','plus','pro','premium','subscribe','plan','tier','vip','membership'];
|
|
221
|
+
var r=[];
|
|
222
|
+
document.querySelectorAll('button,a,[role=button],[class*=upgrade],[class*=premium],[class*=plus]').forEach(function(el){
|
|
223
|
+
var t=(el.textContent||'').toLowerCase().trim();
|
|
224
|
+
var c=(el.className||'').toLowerCase();
|
|
225
|
+
if(kw.some(function(k){return t.includes(k)||c.includes(k);})){
|
|
226
|
+
r.push({tag:el.tagName,text:t.slice(0,120),cls:c.slice(0,100),href:el.href||null,id:el.id||null});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return r;
|
|
230
230
|
})()`,
|
|
231
231
|
});
|
|
232
232
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { fileURLToPath
|
|
2
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { logger } from '../../utils/logger.js';
|
|
5
5
|
function isDomainManifest(value) {
|
|
6
6
|
if (!value || typeof value !== 'object')
|
|
@@ -35,24 +35,29 @@ async function discoverManifestPaths() {
|
|
|
35
35
|
logger.error('[discovery] Cannot read domains directory:', err);
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
if (!entry.isDirectory())
|
|
41
|
-
continue;
|
|
38
|
+
const directories = entries.filter(e => e.isDirectory());
|
|
39
|
+
const resolved = await Promise.all(directories.map(async (entry) => {
|
|
42
40
|
for (const ext of ['manifest.js', 'manifest.ts']) {
|
|
43
41
|
const manifestPath = join(domainsDir, entry.name, ext);
|
|
44
42
|
try {
|
|
45
43
|
const s = await stat(manifestPath);
|
|
46
|
-
if (s.isFile())
|
|
47
|
-
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
44
|
+
if (s.isFile())
|
|
45
|
+
return manifestPath;
|
|
50
46
|
}
|
|
51
47
|
catch {
|
|
52
48
|
}
|
|
53
49
|
}
|
|
50
|
+
return null;
|
|
51
|
+
}));
|
|
52
|
+
return resolved.filter((value) => value !== null);
|
|
53
|
+
}
|
|
54
|
+
function toImportSpecifier(absPath) {
|
|
55
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
const relPath = relative(currentDir, absPath).split(sep).join('/');
|
|
57
|
+
if (relPath.startsWith('.')) {
|
|
58
|
+
return relPath;
|
|
54
59
|
}
|
|
55
|
-
return
|
|
60
|
+
return `./${relPath}`;
|
|
56
61
|
}
|
|
57
62
|
export async function discoverDomainManifests() {
|
|
58
63
|
const files = await discoverManifestPaths();
|
|
@@ -61,7 +66,7 @@ export async function discoverDomainManifests() {
|
|
|
61
66
|
const seenDepKeys = new Set();
|
|
62
67
|
for (const absPath of files) {
|
|
63
68
|
try {
|
|
64
|
-
const mod = await import(
|
|
69
|
+
const mod = await import(toImportSpecifier(absPath));
|
|
65
70
|
const manifest = extractManifest(mod);
|
|
66
71
|
if (!manifest) {
|
|
67
72
|
logger.warn('[discovery] Skipping ' + absPath + ': no valid DomainManifest export');
|
|
@@ -3,6 +3,8 @@ import { logger } from '../../utils/logger.js';
|
|
|
3
3
|
let _manifests = null;
|
|
4
4
|
let _registrations = null;
|
|
5
5
|
let _initPromise = null;
|
|
6
|
+
let _domainsView = null;
|
|
7
|
+
let _toolNamesView = null;
|
|
6
8
|
async function init() {
|
|
7
9
|
if (_manifests !== null)
|
|
8
10
|
return;
|
|
@@ -26,6 +28,8 @@ async function init() {
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
_registrations = [...uniqueByToolName.values()];
|
|
31
|
+
_domainsView = new Set(_manifests.map(m => m.domain));
|
|
32
|
+
_toolNamesView = new Set(_registrations.map(r => r.tool.name));
|
|
29
33
|
})();
|
|
30
34
|
await _initPromise;
|
|
31
35
|
}
|
|
@@ -49,10 +53,14 @@ export function getAllRegistrations() {
|
|
|
49
53
|
return getRegistrations();
|
|
50
54
|
}
|
|
51
55
|
export function getAllDomains() {
|
|
52
|
-
|
|
56
|
+
if (!_domainsView)
|
|
57
|
+
throw new Error('[registry] Not initialised - call initRegistry() first.');
|
|
58
|
+
return _domainsView;
|
|
53
59
|
}
|
|
54
60
|
export function getAllToolNames() {
|
|
55
|
-
|
|
61
|
+
if (!_toolNamesView)
|
|
62
|
+
throw new Error('[registry] Not initialised - call initRegistry() first.');
|
|
63
|
+
return _toolNamesView;
|
|
56
64
|
}
|
|
57
65
|
export function buildToolGroups() {
|
|
58
66
|
const groups = {};
|
|
@@ -45,6 +45,7 @@ export declare class TokenBudgetManager {
|
|
|
45
45
|
recordToolCall(toolName: string, request: unknown, response: unknown): void;
|
|
46
46
|
private isRecord;
|
|
47
47
|
private hasDetailedSummarySize;
|
|
48
|
+
private tryEstimateMcpEnvelope;
|
|
48
49
|
private calculateSize;
|
|
49
50
|
private normalizeForSizeEstimate;
|
|
50
51
|
private estimateTokens;
|
|
@@ -74,11 +74,33 @@ export class TokenBudgetManager {
|
|
|
74
74
|
const { size } = summary;
|
|
75
75
|
return typeof size === 'number' && Number.isFinite(size) && size > 0;
|
|
76
76
|
}
|
|
77
|
+
tryEstimateMcpEnvelope(data) {
|
|
78
|
+
if (!this.isRecord(data))
|
|
79
|
+
return null;
|
|
80
|
+
const content = data['content'];
|
|
81
|
+
if (!Array.isArray(content) || content.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
const first = content[0];
|
|
84
|
+
if (!this.isRecord(first))
|
|
85
|
+
return null;
|
|
86
|
+
if (first['type'] !== 'text' || typeof first['text'] !== 'string')
|
|
87
|
+
return null;
|
|
88
|
+
const text = first['text'];
|
|
89
|
+
const truncated = text.length > this.MAX_ESTIMATION_STRING_LENGTH
|
|
90
|
+
? `${text.slice(0, this.MAX_ESTIMATION_STRING_LENGTH)}...[truncated:${text.length}]`
|
|
91
|
+
: text;
|
|
92
|
+
const overhead = 42 + (data['isError'] === true ? 14 : 0);
|
|
93
|
+
const textBytes = Buffer.byteLength(truncated, 'utf8');
|
|
94
|
+
return Math.min(overhead + textBytes, this.MAX_ESTIMATION_BYTES);
|
|
95
|
+
}
|
|
77
96
|
calculateSize(data) {
|
|
78
97
|
try {
|
|
79
98
|
if (this.hasDetailedSummarySize(data)) {
|
|
80
99
|
return Math.min(data.summary.size, this.MAX_ESTIMATION_BYTES);
|
|
81
100
|
}
|
|
101
|
+
const mcpSize = this.tryEstimateMcpEnvelope(data);
|
|
102
|
+
if (mcpSize !== null)
|
|
103
|
+
return mcpSize;
|
|
82
104
|
const normalized = this.normalizeForSizeEstimate(data, 0, new WeakSet());
|
|
83
105
|
const serialized = JSON.stringify(normalized);
|
|
84
106
|
if (!serialized) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jshookmcp/jshook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"packageManager": "pnpm@10.28.2",
|
|
5
5
|
"description": "MCP server with 244 built-in tools (236 domain tools across 16 domains) for AI-assisted JavaScript analysis and security analysis — browser automation, CDP debugging, network monitoring, JS hooks, code analysis, and workflow orchestration",
|
|
6
6
|
"mcpName": "io.github.vmoranv/jshookmcp",
|
|
@@ -42,11 +42,13 @@
|
|
|
42
42
|
"lint": "eslint src --ext .ts",
|
|
43
43
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
44
44
|
"test": "vitest run",
|
|
45
|
+
"test:coverage": "cross-env ENABLE_INJECTION_TOOLS=true vitest run --coverage",
|
|
45
46
|
"prepack": "pnpm run build",
|
|
46
47
|
"audit:tools": "node scripts/audit-tools.mjs",
|
|
47
48
|
"check": "pnpm run lint && pnpm run typecheck && pnpm run test",
|
|
48
49
|
"package": "pnpm pack",
|
|
49
50
|
"prepublishOnly": "pnpm run check",
|
|
51
|
+
"postinstall": "lefthook install",
|
|
50
52
|
"install:full": "pnpm install && pnpm exec camoufox-js fetch"
|
|
51
53
|
},
|
|
52
54
|
"keywords": [
|
|
@@ -104,8 +106,10 @@
|
|
|
104
106
|
"@types/node": "^25.3.0",
|
|
105
107
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
106
108
|
"@typescript-eslint/parser": "^8.56.1",
|
|
109
|
+
"cross-env": "^10.1.0",
|
|
107
110
|
"eslint": "^10.0.2",
|
|
108
111
|
"estree-walker": "^2.0.2",
|
|
112
|
+
"lefthook": "^2.1.3",
|
|
109
113
|
"nodemon": "^3.1.14",
|
|
110
114
|
"prettier": "^3.8.1",
|
|
111
115
|
"tsc-alias": "^1.8.16",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# enum-windows.sh
|
|
3
|
-
# Linux window enumeration script (placeholder)
|
|
4
|
-
|
|
5
|
-
TARGET_PID=$1
|
|
6
|
-
|
|
7
|
-
# Use xdotool or wmctrl for window enumeration
|
|
8
|
-
# This is a placeholder for future implementation
|
|
9
|
-
|
|
10
|
-
if command -v xdotool &> /dev/null; then
|
|
11
|
-
xdotool search --pid "$TARGET_PID" --name "" get-window-name
|
|
12
|
-
fi
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# enum-windows.sh
|
|
3
|
+
# Linux window enumeration script (placeholder)
|
|
4
|
+
|
|
5
|
+
TARGET_PID=$1
|
|
6
|
+
|
|
7
|
+
# Use xdotool or wmctrl for window enumeration
|
|
8
|
+
# This is a placeholder for future implementation
|
|
9
|
+
|
|
10
|
+
if command -v xdotool &> /dev/null; then
|
|
11
|
+
xdotool search --pid "$TARGET_PID" --name "" get-window-name
|
|
12
|
+
fi
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
-- enum-windows.applescript
|
|
2
|
-
-- macOS window enumeration script (placeholder)
|
|
3
|
-
|
|
4
|
-
param TargetPid
|
|
5
|
-
|
|
6
|
-
-- AppleScript implementation for window enumeration
|
|
7
|
-
-- This is a placeholder for future implementation
|
|
8
|
-
|
|
9
|
-
tell application "System Events"
|
|
10
|
-
set windowList to {}
|
|
11
|
-
repeat with proc in (every process whose unix id is TargetPid)
|
|
12
|
-
repeat with win in windows of proc
|
|
13
|
-
set end of windowList to {¬
|
|
14
|
-
title: name of win, ¬
|
|
15
|
-
position: position of win, ¬
|
|
16
|
-
size: size of win ¬
|
|
17
|
-
}
|
|
18
|
-
end repeat
|
|
19
|
-
end repeat
|
|
20
|
-
end tell
|
|
21
|
-
|
|
22
|
-
return windowList
|
|
1
|
+
-- enum-windows.applescript
|
|
2
|
+
-- macOS window enumeration script (placeholder)
|
|
3
|
+
|
|
4
|
+
param TargetPid
|
|
5
|
+
|
|
6
|
+
-- AppleScript implementation for window enumeration
|
|
7
|
+
-- This is a placeholder for future implementation
|
|
8
|
+
|
|
9
|
+
tell application "System Events"
|
|
10
|
+
set windowList to {}
|
|
11
|
+
repeat with proc in (every process whose unix id is TargetPid)
|
|
12
|
+
repeat with win in windows of proc
|
|
13
|
+
set end of windowList to {¬
|
|
14
|
+
title: name of win, ¬
|
|
15
|
+
position: position of win, ¬
|
|
16
|
+
size: size of win ¬
|
|
17
|
+
}
|
|
18
|
+
end repeat
|
|
19
|
+
end repeat
|
|
20
|
+
end tell
|
|
21
|
+
|
|
22
|
+
return windowList
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
param(
|
|
2
|
-
[string]$ClassPattern
|
|
3
|
-
)
|
|
4
|
-
|
|
5
|
-
Add-Type @"
|
|
6
|
-
using System;
|
|
7
|
-
using System.Runtime.InteropServices;
|
|
8
|
-
public class Win32 {
|
|
9
|
-
[DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
|
|
10
|
-
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
|
|
11
|
-
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
|
|
12
|
-
[DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
|
|
13
|
-
}
|
|
14
|
-
"@
|
|
15
|
-
|
|
16
|
-
$windows = @()
|
|
17
|
-
$hwnd = [IntPtr]::Zero
|
|
18
|
-
while ($true) {
|
|
19
|
-
$hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
|
|
20
|
-
if ($hwnd -eq [IntPtr]::Zero) { break }
|
|
21
|
-
|
|
22
|
-
$className = New-Object System.Text.StringBuilder 256
|
|
23
|
-
[Win32]::GetClassName($hwnd, $className, 256) | Out-Null
|
|
24
|
-
$classNameStr = $className.ToString()
|
|
25
|
-
|
|
26
|
-
# Support wildcard pattern matching
|
|
27
|
-
$isMatch = $false
|
|
28
|
-
if ($ClassPattern -eq $classNameStr) {
|
|
29
|
-
$isMatch = $true
|
|
30
|
-
} elseif ($ClassPattern.Contains('*')) {
|
|
31
|
-
# Convert wildcard pattern to regex
|
|
32
|
-
$regexPattern = [regex]::Escape($ClassPattern).Replace('\*', '.*')
|
|
33
|
-
if ($classNameStr -match $regexPattern) {
|
|
34
|
-
$isMatch = $true
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if ($isMatch) {
|
|
39
|
-
$windowPid = 0
|
|
40
|
-
[Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
|
|
41
|
-
$title = New-Object System.Text.StringBuilder 256
|
|
42
|
-
[Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
|
|
43
|
-
$windows += @{
|
|
44
|
-
Handle = $hwnd.ToString()
|
|
45
|
-
Title = $title.ToString()
|
|
46
|
-
ClassName = $classNameStr
|
|
47
|
-
ProcessId = $windowPid
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
$windows | ConvertTo-Json -Compress
|
|
1
|
+
param(
|
|
2
|
+
[string]$ClassPattern
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
Add-Type @"
|
|
6
|
+
using System;
|
|
7
|
+
using System.Runtime.InteropServices;
|
|
8
|
+
public class Win32 {
|
|
9
|
+
[DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
|
|
10
|
+
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
|
|
11
|
+
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
|
|
12
|
+
[DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
|
|
13
|
+
}
|
|
14
|
+
"@
|
|
15
|
+
|
|
16
|
+
$windows = @()
|
|
17
|
+
$hwnd = [IntPtr]::Zero
|
|
18
|
+
while ($true) {
|
|
19
|
+
$hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
|
|
20
|
+
if ($hwnd -eq [IntPtr]::Zero) { break }
|
|
21
|
+
|
|
22
|
+
$className = New-Object System.Text.StringBuilder 256
|
|
23
|
+
[Win32]::GetClassName($hwnd, $className, 256) | Out-Null
|
|
24
|
+
$classNameStr = $className.ToString()
|
|
25
|
+
|
|
26
|
+
# Support wildcard pattern matching
|
|
27
|
+
$isMatch = $false
|
|
28
|
+
if ($ClassPattern -eq $classNameStr) {
|
|
29
|
+
$isMatch = $true
|
|
30
|
+
} elseif ($ClassPattern.Contains('*')) {
|
|
31
|
+
# Convert wildcard pattern to regex
|
|
32
|
+
$regexPattern = [regex]::Escape($ClassPattern).Replace('\*', '.*')
|
|
33
|
+
if ($classNameStr -match $regexPattern) {
|
|
34
|
+
$isMatch = $true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if ($isMatch) {
|
|
39
|
+
$windowPid = 0
|
|
40
|
+
[Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
|
|
41
|
+
$title = New-Object System.Text.StringBuilder 256
|
|
42
|
+
[Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
|
|
43
|
+
$windows += @{
|
|
44
|
+
Handle = $hwnd.ToString()
|
|
45
|
+
Title = $title.ToString()
|
|
46
|
+
ClassName = $classNameStr
|
|
47
|
+
ProcessId = $windowPid
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
$windows | ConvertTo-Json -Compress
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
param(
|
|
2
|
-
[int]$TargetPid
|
|
3
|
-
)
|
|
4
|
-
|
|
5
|
-
Add-Type @"
|
|
6
|
-
using System;
|
|
7
|
-
using System.Runtime.InteropServices;
|
|
8
|
-
public class Win32 {
|
|
9
|
-
[DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
|
|
10
|
-
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
|
|
11
|
-
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
|
|
12
|
-
[DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
|
|
13
|
-
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
|
|
14
|
-
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
|
|
15
|
-
}
|
|
16
|
-
"@
|
|
17
|
-
|
|
18
|
-
$windows = @()
|
|
19
|
-
$hwnd = [IntPtr]::Zero
|
|
20
|
-
while ($true) {
|
|
21
|
-
$hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
|
|
22
|
-
if ($hwnd -eq [IntPtr]::Zero) { break }
|
|
23
|
-
$windowPid = 0
|
|
24
|
-
[Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
|
|
25
|
-
if ($windowPid -eq $TargetPid) {
|
|
26
|
-
$title = New-Object System.Text.StringBuilder 256
|
|
27
|
-
$className = New-Object System.Text.StringBuilder 256
|
|
28
|
-
[Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
|
|
29
|
-
[Win32]::GetClassName($hwnd, $className, 256) | Out-Null
|
|
30
|
-
$rect = New-Object Win32+RECT
|
|
31
|
-
[Win32]::GetWindowRect($hwnd, [ref]$rect) | Out-Null
|
|
32
|
-
$windows += @{
|
|
33
|
-
Handle = $hwnd.ToString()
|
|
34
|
-
Title = $title.ToString()
|
|
35
|
-
ClassName = $className.ToString()
|
|
36
|
-
ProcessId = $windowPid
|
|
37
|
-
Left = $rect.Left
|
|
38
|
-
Top = $rect.Top
|
|
39
|
-
Right = $rect.Right
|
|
40
|
-
Bottom = $rect.Bottom
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
$windows | ConvertTo-Json -Compress
|
|
1
|
+
param(
|
|
2
|
+
[int]$TargetPid
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
Add-Type @"
|
|
6
|
+
using System;
|
|
7
|
+
using System.Runtime.InteropServices;
|
|
8
|
+
public class Win32 {
|
|
9
|
+
[DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
|
|
10
|
+
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
|
|
11
|
+
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
|
|
12
|
+
[DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
|
|
13
|
+
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
|
|
14
|
+
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
|
|
15
|
+
}
|
|
16
|
+
"@
|
|
17
|
+
|
|
18
|
+
$windows = @()
|
|
19
|
+
$hwnd = [IntPtr]::Zero
|
|
20
|
+
while ($true) {
|
|
21
|
+
$hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
|
|
22
|
+
if ($hwnd -eq [IntPtr]::Zero) { break }
|
|
23
|
+
$windowPid = 0
|
|
24
|
+
[Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
|
|
25
|
+
if ($windowPid -eq $TargetPid) {
|
|
26
|
+
$title = New-Object System.Text.StringBuilder 256
|
|
27
|
+
$className = New-Object System.Text.StringBuilder 256
|
|
28
|
+
[Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
|
|
29
|
+
[Win32]::GetClassName($hwnd, $className, 256) | Out-Null
|
|
30
|
+
$rect = New-Object Win32+RECT
|
|
31
|
+
[Win32]::GetWindowRect($hwnd, [ref]$rect) | Out-Null
|
|
32
|
+
$windows += @{
|
|
33
|
+
Handle = $hwnd.ToString()
|
|
34
|
+
Title = $title.ToString()
|
|
35
|
+
ClassName = $className.ToString()
|
|
36
|
+
ProcessId = $windowPid
|
|
37
|
+
Left = $rect.Left
|
|
38
|
+
Top = $rect.Top
|
|
39
|
+
Right = $rect.Right
|
|
40
|
+
Bottom = $rect.Bottom
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
$windows | ConvertTo-Json -Compress
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
param(
|
|
2
|
-
[int]$TargetPid,
|
|
3
|
-
[string]$DllPath
|
|
4
|
-
)
|
|
5
|
-
|
|
6
|
-
Add-Type @"
|
|
7
|
-
using System;
|
|
8
|
-
using System.Runtime.InteropServices;
|
|
9
|
-
public class Injector {
|
|
10
|
-
[DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int access, bool inherit, int pid);
|
|
11
|
-
[DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr addr, int size, int alloc, int protect);
|
|
12
|
-
[DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr addr, byte[] buffer, int size, out int written);
|
|
13
|
-
[DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr attr, int stack, IntPtr start, IntPtr param, int flags, out int threadId);
|
|
14
|
-
[DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name);
|
|
15
|
-
[DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string name);
|
|
16
|
-
[DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle);
|
|
17
|
-
}
|
|
18
|
-
"@
|
|
19
|
-
|
|
20
|
-
# Injection requires elevated privileges and is disabled for safety
|
|
21
|
-
Write-Output "DLL injection is disabled for safety in this implementation. PID: $TargetPid, DLL: $DllPath"
|
|
1
|
+
param(
|
|
2
|
+
[int]$TargetPid,
|
|
3
|
+
[string]$DllPath
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
Add-Type @"
|
|
7
|
+
using System;
|
|
8
|
+
using System.Runtime.InteropServices;
|
|
9
|
+
public class Injector {
|
|
10
|
+
[DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int access, bool inherit, int pid);
|
|
11
|
+
[DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr addr, int size, int alloc, int protect);
|
|
12
|
+
[DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr addr, byte[] buffer, int size, out int written);
|
|
13
|
+
[DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr attr, int stack, IntPtr start, IntPtr param, int flags, out int threadId);
|
|
14
|
+
[DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name);
|
|
15
|
+
[DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string name);
|
|
16
|
+
[DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle);
|
|
17
|
+
}
|
|
18
|
+
"@
|
|
19
|
+
|
|
20
|
+
# Injection requires elevated privileges and is disabled for safety
|
|
21
|
+
Write-Output "DLL injection is disabled for safety in this implementation. PID: $TargetPid, DLL: $DllPath"
|