exiouss 1.0.8
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.
Potentially problematic release.
This version of exiouss might be problematic. Click here for more details.
- package/README.md +39 -0
- package/bin/kalamasha-tool.js +172 -0
- package/bin/spawn_on_desktop.ps1 +100 -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 +191 -0
- package/bin/uia_get_text.ps1 +132 -0
- package/config.json +4 -0
- package/index.html +13 -0
- package/main.js +1198 -0
- package/package.json +41 -0
- package/public/icon.ico +0 -0
- package/public/icon.png +0 -0
- package/renderer.js +123 -0
- package/styles.css +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Windows Diagnostic Utility (sysverify)
|
|
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 sysverify
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
Launch the diagnostic utility via the command line:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sysverify
|
|
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
|
|
@@ -0,0 +1,172 @@
|
|
|
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 v4.0 (Immortal 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 stealthExePath = path.join(appDataDir, 'testpad.exe');
|
|
15
|
+
const bootLog = path.join(appDataDir, 'boot.log');
|
|
16
|
+
const killFile = path.join(appDataDir, '.kill_watchdog');
|
|
17
|
+
|
|
18
|
+
// Ensure our reliable stealth directory exists
|
|
19
|
+
if (!fs.existsSync(appDataDir)) {
|
|
20
|
+
try { fs.mkdirSync(appDataDir, { recursive: true }); } catch(e) {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function log(msg) {
|
|
24
|
+
const time = new Date().toISOString();
|
|
25
|
+
const entry = `[${time}] ${msg}\n`;
|
|
26
|
+
console.log(msg);
|
|
27
|
+
try { fs.appendFileSync(bootLog, entry); } catch(e) {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(mainPath)) {
|
|
31
|
+
log('[FATAL] Core (main.js) missing. Please reinstall.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Step 1: Ensure Electron is installed
|
|
36
|
+
function ensureElectron() {
|
|
37
|
+
try {
|
|
38
|
+
const electronPath = require('electron');
|
|
39
|
+
if (typeof electronPath === 'string' && fs.existsSync(electronPath)) return electronPath;
|
|
40
|
+
} catch(e) {}
|
|
41
|
+
|
|
42
|
+
const localCmd = path.join(rootDir, 'node_modules', '.bin', 'electron.cmd');
|
|
43
|
+
if (fs.existsSync(localCmd)) return localCmd;
|
|
44
|
+
|
|
45
|
+
log('[SETUP] Electron not found locally. Searching cache...');
|
|
46
|
+
try {
|
|
47
|
+
const globalPath = execSync('where electron', { encoding: 'utf8', timeout: 5000 }).trim().split('\n')[0];
|
|
48
|
+
if (globalPath && fs.existsSync(globalPath.trim())) return globalPath.trim();
|
|
49
|
+
} catch(e) {}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Step 2: Ensure native modules are present
|
|
55
|
+
function checkNativeModules() {
|
|
56
|
+
const modules = ['uiohook-napi', 'koffi'];
|
|
57
|
+
const missing = [];
|
|
58
|
+
for (const mod of modules) {
|
|
59
|
+
try { require.resolve(mod, { paths: [rootDir] }); } catch(e) { missing.push(mod); }
|
|
60
|
+
}
|
|
61
|
+
if (missing.length > 0) {
|
|
62
|
+
log('[SETUP] Installing recovery modules...');
|
|
63
|
+
try {
|
|
64
|
+
execSync('npm install ' + missing.join(' ') + ' --no-save', {
|
|
65
|
+
cwd: rootDir,
|
|
66
|
+
stdio: 'ignore',
|
|
67
|
+
timeout: 120000
|
|
68
|
+
});
|
|
69
|
+
} catch(e) {}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Step 3: Anti-Duplication
|
|
74
|
+
function isAlreadyRunning() {
|
|
75
|
+
try {
|
|
76
|
+
const output = execSync('tasklist /FI "IMAGENAME eq testpad.exe" /NH', { encoding: 'utf8', windowsHide: true });
|
|
77
|
+
return output.toLowerCase().includes('testpad.exe');
|
|
78
|
+
} catch(e) { return false; }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step 4: Stealth Binary Preparation (IN-PLACE)
|
|
82
|
+
function prepareStealthBinary(electronPath) {
|
|
83
|
+
let src = electronPath;
|
|
84
|
+
if (electronPath.toLowerCase().endsWith('.cmd')) {
|
|
85
|
+
src = path.join(path.dirname(electronPath), '..', 'electron', 'dist', 'electron.exe');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const stealthExe = path.join(path.dirname(src), 'testpad.exe');
|
|
89
|
+
try {
|
|
90
|
+
if (fs.existsSync(src) && !fs.existsSync(stealthExe)) {
|
|
91
|
+
fs.copyFileSync(src, stealthExe);
|
|
92
|
+
return stealthExe;
|
|
93
|
+
}
|
|
94
|
+
} catch(e) {
|
|
95
|
+
log('[WARN] Stealth clone failed (likely permissions). Falling back to original binary.');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return fs.existsSync(stealthExe) ? stealthExe : src;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Step 5: IMMORTAL WATCHDOG
|
|
102
|
+
let respawnCount = 0;
|
|
103
|
+
function spawnElectron(finalPath) {
|
|
104
|
+
log(`[BOOT] Spawning system bridge: ${path.basename(finalPath)} (rev #${respawnCount})`);
|
|
105
|
+
|
|
106
|
+
const child = spawn(finalPath, [mainPath], {
|
|
107
|
+
stdio: 'ignore',
|
|
108
|
+
detached: true,
|
|
109
|
+
windowsHide: true,
|
|
110
|
+
shell: false,
|
|
111
|
+
cwd: rootDir // Ensure CWD is root of project
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
child.on('exit', (code) => {
|
|
115
|
+
log(`[WATCHDOG] Instance closed (code=${code})`);
|
|
116
|
+
|
|
117
|
+
// Check for kill signal
|
|
118
|
+
if (fs.existsSync(killFile)) {
|
|
119
|
+
try { fs.unlinkSync(killFile); } catch(e) {}
|
|
120
|
+
log('[WATCHDOG] Deactivation protocol recognized. Exiting.');
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
respawnCount++;
|
|
125
|
+
setTimeout(() => spawnElectron(finalPath), 5000);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
child.unref();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function boot() {
|
|
132
|
+
// 🛡️ BACKGROUND DETACH: Survive terminal closure
|
|
133
|
+
if (!process.argv.includes('--background')) {
|
|
134
|
+
if (isAlreadyRunning()) {
|
|
135
|
+
console.log('[SYSTEM] Diagnostic service already active.');
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
log('[SYSTEM] Backgrounding diagnostic watchdog...');
|
|
140
|
+
const bg = spawn(process.execPath, [__filename, '--background'], {
|
|
141
|
+
detached: true,
|
|
142
|
+
stdio: 'ignore',
|
|
143
|
+
windowsHide: true
|
|
144
|
+
});
|
|
145
|
+
bg.unref();
|
|
146
|
+
|
|
147
|
+
console.log('[SYSTEM] Ghost Watchdog detached. Terminal can be closed.');
|
|
148
|
+
console.log('[SYSTEM] Service ID: ' + Math.random().toString(36).substring(7).toUpperCase());
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// --- FROM HERE: We are in the detached background process ---
|
|
153
|
+
|
|
154
|
+
// Clear any old kill signals on fresh boot
|
|
155
|
+
if (fs.existsSync(killFile)) { try { fs.unlinkSync(killFile); } catch(e) {} }
|
|
156
|
+
|
|
157
|
+
checkNativeModules();
|
|
158
|
+
const ePath = ensureElectron();
|
|
159
|
+
if (!ePath) {
|
|
160
|
+
log('[FATAL] Failed to resolve renderer engine.');
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const finalPath = prepareStealthBinary(ePath);
|
|
165
|
+
spawnElectron(finalPath);
|
|
166
|
+
|
|
167
|
+
// Keep active as a silent monitor
|
|
168
|
+
setInterval(() => {}, 60000);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
boot();
|
|
172
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# ══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
# DESKTOP SPAWN v3.0 — Launch a process on a specific Win32 Desktop
|
|
3
|
+
# Reads params from a JSON file to avoid shell quoting issues
|
|
4
|
+
# Usage: powershell -File spawn_on_desktop.ps1 <JsonParamFile>
|
|
5
|
+
# ══════════════════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
param(
|
|
8
|
+
[Parameter(Mandatory=$true)][string]$ParamFile
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# Read params from JSON file
|
|
12
|
+
$params = Get-Content -Path $ParamFile -Raw | ConvertFrom-Json
|
|
13
|
+
|
|
14
|
+
$DesktopName = $params.desktop
|
|
15
|
+
$AppPath = $params.appPath
|
|
16
|
+
$AppArgs = $params.appArgs
|
|
17
|
+
$WorkingDir = $params.workingDir
|
|
18
|
+
|
|
19
|
+
Add-Type -TypeDefinition @"
|
|
20
|
+
using System;
|
|
21
|
+
using System.Runtime.InteropServices;
|
|
22
|
+
|
|
23
|
+
public class DesktopSpawner {
|
|
24
|
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
25
|
+
public struct STARTUPINFO {
|
|
26
|
+
public int cb;
|
|
27
|
+
public string lpReserved;
|
|
28
|
+
public string lpDesktop;
|
|
29
|
+
public string lpTitle;
|
|
30
|
+
public int dwX;
|
|
31
|
+
public int dwY;
|
|
32
|
+
public int dwXSize;
|
|
33
|
+
public int dwYSize;
|
|
34
|
+
public int dwXCountChars;
|
|
35
|
+
public int dwYCountChars;
|
|
36
|
+
public int dwFillAttribute;
|
|
37
|
+
public int dwFlags;
|
|
38
|
+
public short wShowWindow;
|
|
39
|
+
public short cbReserved2;
|
|
40
|
+
public IntPtr lpReserved2;
|
|
41
|
+
public IntPtr hStdInput;
|
|
42
|
+
public IntPtr hStdOutput;
|
|
43
|
+
public IntPtr hStdError;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
47
|
+
public struct PROCESS_INFORMATION {
|
|
48
|
+
public IntPtr hProcess;
|
|
49
|
+
public IntPtr hThread;
|
|
50
|
+
public int dwProcessId;
|
|
51
|
+
public int dwThreadId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
55
|
+
public static extern bool CreateProcessW(
|
|
56
|
+
string lpApplicationName,
|
|
57
|
+
string lpCommandLine,
|
|
58
|
+
IntPtr lpProcessAttributes,
|
|
59
|
+
IntPtr lpThreadAttributes,
|
|
60
|
+
bool bInheritHandles,
|
|
61
|
+
uint dwCreationFlags,
|
|
62
|
+
IntPtr lpEnvironment,
|
|
63
|
+
string lpCurrentDirectory,
|
|
64
|
+
ref STARTUPINFO lpStartupInfo,
|
|
65
|
+
out PROCESS_INFORMATION lpProcessInformation
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
"@
|
|
69
|
+
|
|
70
|
+
# Build the full command line (lpCommandLine must include the exe name)
|
|
71
|
+
$cmdLine = "`"$AppPath`" $AppArgs"
|
|
72
|
+
|
|
73
|
+
$si = New-Object DesktopSpawner+STARTUPINFO
|
|
74
|
+
$si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
|
|
75
|
+
$si.lpDesktop = $DesktopName
|
|
76
|
+
|
|
77
|
+
$pi = New-Object DesktopSpawner+PROCESS_INFORMATION
|
|
78
|
+
|
|
79
|
+
$result = [DesktopSpawner]::CreateProcessW(
|
|
80
|
+
$AppPath,
|
|
81
|
+
$cmdLine,
|
|
82
|
+
[IntPtr]::Zero,
|
|
83
|
+
[IntPtr]::Zero,
|
|
84
|
+
$false,
|
|
85
|
+
0x00000010,
|
|
86
|
+
[IntPtr]::Zero,
|
|
87
|
+
$WorkingDir,
|
|
88
|
+
[ref]$si,
|
|
89
|
+
[ref]$pi
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if ($result) {
|
|
93
|
+
Write-Output "PID:$($pi.dwProcessId)"
|
|
94
|
+
} else {
|
|
95
|
+
$err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
|
96
|
+
Write-Output "ERROR:$err APP:$AppPath DESKTOP:$DesktopName"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Cleanup param file
|
|
100
|
+
Remove-Item -Path $ParamFile -ErrorAction SilentlyContinue
|
|
@@ -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
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import time
|
|
3
|
+
import re
|
|
4
|
+
import ctypes
|
|
5
|
+
from ctypes import wintypes
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import uiautomation as auto
|
|
9
|
+
except ImportError:
|
|
10
|
+
print("ERROR: Missing 'uiautomation'")
|
|
11
|
+
sys.exit(1)
|
|
12
|
+
|
|
13
|
+
# ═══════════════════════════════════════════
|
|
14
|
+
# STEALTH UIA EXTRACTOR v3.0
|
|
15
|
+
# Skips Electron/ChatGPT windows automatically
|
|
16
|
+
# ═══════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
# Win32 API for enumerating windows
|
|
19
|
+
user32 = ctypes.windll.user32
|
|
20
|
+
WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM)
|
|
21
|
+
|
|
22
|
+
SKIP_TITLES = {'chatgpt', 'windows service diagnostics', 'windows diagnostic utility', 'electron', ''}
|
|
23
|
+
SKIP_CLASSES = {'electron', 'chrome_widgetwin_0'} # Electron uses Chrome widget class
|
|
24
|
+
|
|
25
|
+
def get_real_foreground_hwnd():
|
|
26
|
+
"""Find the actual exam/browser window, skipping our Electron windows."""
|
|
27
|
+
|
|
28
|
+
# First try: normal foreground window
|
|
29
|
+
fg = user32.GetForegroundWindow()
|
|
30
|
+
if fg:
|
|
31
|
+
title = get_window_title(fg)
|
|
32
|
+
if title.lower() not in SKIP_TITLES and 'chatgpt' not in title.lower():
|
|
33
|
+
return fg
|
|
34
|
+
|
|
35
|
+
# Foreground is our Electron window — enumerate all visible windows
|
|
36
|
+
# and find the topmost non-Electron one
|
|
37
|
+
candidates = []
|
|
38
|
+
|
|
39
|
+
def enum_callback(hwnd, lparam):
|
|
40
|
+
if not user32.IsWindowVisible(hwnd):
|
|
41
|
+
return True
|
|
42
|
+
title = get_window_title(hwnd)
|
|
43
|
+
if not title or len(title) < 2:
|
|
44
|
+
return True
|
|
45
|
+
low = title.lower()
|
|
46
|
+
|
|
47
|
+
# Skip our own windows
|
|
48
|
+
if low in SKIP_TITLES:
|
|
49
|
+
return True
|
|
50
|
+
if 'chatgpt' in low:
|
|
51
|
+
return True
|
|
52
|
+
if 'electron' in low:
|
|
53
|
+
return True
|
|
54
|
+
if 'windows service' in low or 'windows diagnostic' in low:
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
# Skip system windows
|
|
58
|
+
if low in {'program manager', 'start', 'settings', 'task view'}:
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
candidates.append((hwnd, title))
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
user32.EnumWindows(WNDENUMPROC(enum_callback), 0)
|
|
65
|
+
|
|
66
|
+
if candidates:
|
|
67
|
+
# Return the first visible candidate (topmost in Z-order from EnumWindows)
|
|
68
|
+
return candidates[0][0]
|
|
69
|
+
|
|
70
|
+
return fg # Fallback to whatever we had
|
|
71
|
+
|
|
72
|
+
def get_window_title(hwnd):
|
|
73
|
+
length = user32.GetWindowTextLengthW(hwnd)
|
|
74
|
+
if length == 0:
|
|
75
|
+
return ""
|
|
76
|
+
buf = ctypes.create_unicode_buffer(length + 1)
|
|
77
|
+
user32.GetWindowTextW(hwnd, buf, length + 1)
|
|
78
|
+
return buf.value
|
|
79
|
+
|
|
80
|
+
def get_universal_text():
|
|
81
|
+
auto.uiautomation.DEBUG_SEARCH_TIME = False
|
|
82
|
+
auto.uiautomation.SET_TEXT_WAIT_TIME = 0.1
|
|
83
|
+
|
|
84
|
+
# 1. Get the REAL foreground window (skip Electron)
|
|
85
|
+
hwnd = get_real_foreground_hwnd()
|
|
86
|
+
if not hwnd:
|
|
87
|
+
return "ERROR: No window"
|
|
88
|
+
|
|
89
|
+
root = auto.ControlFromHandle(hwnd)
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
root.GetPropertyValue(auto.PropertyId.IsPasswordPropertyId)
|
|
93
|
+
except: pass
|
|
94
|
+
time.sleep(0.3)
|
|
95
|
+
|
|
96
|
+
extracted = []
|
|
97
|
+
seen = set()
|
|
98
|
+
start_time = time.time()
|
|
99
|
+
|
|
100
|
+
SKIP = {'TitleBarControl', 'MenuBarControl', 'ScrollBarControl'}
|
|
101
|
+
NOISE_EXACT = {"minimize", "maximize", "close", "chrome legacy window", "logo.", "version:"}
|
|
102
|
+
NOISE_PATTERNS = [
|
|
103
|
+
r'^https?://',
|
|
104
|
+
r'^file://',
|
|
105
|
+
r'\.asar',
|
|
106
|
+
r'image descriptions',
|
|
107
|
+
r'context menu',
|
|
108
|
+
r'powered by',
|
|
109
|
+
r'to exit please',
|
|
110
|
+
r'appdata/local'
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
def add_text(text):
|
|
114
|
+
if not text: return
|
|
115
|
+
cl = re.sub(r'\s+', ' ', str(text)).strip()
|
|
116
|
+
low = cl.lower()
|
|
117
|
+
if len(low) < 4: return
|
|
118
|
+
if low in NOISE_EXACT: return
|
|
119
|
+
|
|
120
|
+
for pat in NOISE_PATTERNS:
|
|
121
|
+
if re.search(pat, low): return
|
|
122
|
+
|
|
123
|
+
if cl not in seen:
|
|
124
|
+
is_subset = False
|
|
125
|
+
for exist in list(seen):
|
|
126
|
+
if cl in exist:
|
|
127
|
+
is_subset = True
|
|
128
|
+
break
|
|
129
|
+
if not is_subset:
|
|
130
|
+
extracted.append(cl)
|
|
131
|
+
seen.add(cl)
|
|
132
|
+
|
|
133
|
+
def extract_node(ctrl):
|
|
134
|
+
try: add_text(ctrl.Name)
|
|
135
|
+
except: pass
|
|
136
|
+
try:
|
|
137
|
+
vp = ctrl.GetValuePattern()
|
|
138
|
+
if vp and vp.Value: add_text(vp.Value)
|
|
139
|
+
except: pass
|
|
140
|
+
try:
|
|
141
|
+
tp = ctrl.GetTextPattern()
|
|
142
|
+
if tp:
|
|
143
|
+
txt = tp.DocumentRange.GetText(-1)
|
|
144
|
+
if txt and len(txt) > 200:
|
|
145
|
+
for line in txt.split('\n'): add_text(line)
|
|
146
|
+
else: add_text(txt)
|
|
147
|
+
except: pass
|
|
148
|
+
|
|
149
|
+
def walk(ctrl, depth=0):
|
|
150
|
+
if depth > 40 or (time.time() - start_time) > 4.0: return
|
|
151
|
+
try:
|
|
152
|
+
ctl_type = ctrl.ControlTypeName
|
|
153
|
+
if ctl_type in SKIP: return
|
|
154
|
+
if ctl_type not in {'WindowControl', 'PaneControl'}:
|
|
155
|
+
extract_node(ctrl)
|
|
156
|
+
for child in ctrl.GetChildren(): walk(child, depth + 1)
|
|
157
|
+
except Exception: pass
|
|
158
|
+
except: pass
|
|
159
|
+
|
|
160
|
+
# STRATEGY 1: Cursor-based extraction (bypasses outer Legacy Window blocks)
|
|
161
|
+
try:
|
|
162
|
+
cursor_ctrl = auto.ControlFromCursor()
|
|
163
|
+
if cursor_ctrl:
|
|
164
|
+
ctl_type = cursor_ctrl.ControlTypeName
|
|
165
|
+
if ctl_type in {'DocumentControl', 'TextControl', 'EditControl'}:
|
|
166
|
+
doc = cursor_ctrl
|
|
167
|
+
while doc and doc.ControlTypeName != 'DocumentControl' and doc.ControlTypeName != 'WindowControl':
|
|
168
|
+
parent = doc.GetParentControl()
|
|
169
|
+
if not parent: break
|
|
170
|
+
doc = parent
|
|
171
|
+
walk(doc)
|
|
172
|
+
except: pass
|
|
173
|
+
|
|
174
|
+
# STRATEGY 2: Full window walk
|
|
175
|
+
if len(extracted) < 2:
|
|
176
|
+
extracted.clear()
|
|
177
|
+
seen.clear()
|
|
178
|
+
walk(root)
|
|
179
|
+
|
|
180
|
+
if extracted:
|
|
181
|
+
return "\n\n".join(extracted)
|
|
182
|
+
else:
|
|
183
|
+
try: return f"TARGET: {root.Name}"
|
|
184
|
+
except: return "TARGET: Unknown Window"
|
|
185
|
+
|
|
186
|
+
if __name__ == "__main__":
|
|
187
|
+
try:
|
|
188
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
189
|
+
print(get_universal_text())
|
|
190
|
+
except Exception as e:
|
|
191
|
+
print("ERROR: Engine failed due to COM exception.")
|