Compare commits

...
38 Commits
Author SHA1 Message Date
87owo 630dc67058 Add files via upload 2026-08-21 14:19:12 +08:00
87owo 591507512c Delete Plugins/Rules/Report.json 2026-08-21 13:33:13 +08:00
87owo ff49cafc74 Add files via upload 2026-08-21 13:32:08 +08:00
87owo b077ba06bd Add files via upload 2026-08-19 17:20:02 +08:00
87owo a2b66aec64 Add files via upload 2026-08-14 12:43:24 +08:00
87owo 4b692b0c87 Add files via upload 2026-08-11 13:17:24 +08:00
87owo 99d1b20d0f Add files via upload 2026-08-09 19:52:15 +08:00
87owo fae5edb57b Add files via upload 2026-08-09 19:50:38 +08:00
87owo 6db91483a0 Add files via upload 2026-08-09 19:36:22 +08:00
87owo 90383f3d09 Add files via upload 2026-08-04 22:31:09 +08:00
87owo 966a5a3592 Add files via upload 2026-08-04 22:29:20 +08:00
87owo 48e14cd143 Add files via upload 2026-07-28 12:29:39 +08:00
87owo 4264f50ba3 Add files via upload 2026-07-28 12:12:10 +08:00
87owo 887e0718d0 Add files via upload 2026-07-28 12:10:36 +08:00
87owo 4870a5c480 Add files via upload 2026-07-28 12:09:57 +08:00
87owo e8cadf0537 Add files via upload 2026-07-27 17:30:57 +08:00
87owo f5124e0ef2 Add files via upload 2026-07-25 20:33:44 +08:00
87owo da9a520632 Add files via upload 2026-07-25 20:12:57 +08:00
87owo 81bebeda63 Add files via upload 2026-07-25 00:08:11 +08:00
87owo 4df1432be1 Add files via upload 2026-07-24 23:25:19 +08:00
87owo e699be6b2e Update Rules_Driver_P1.json 2026-07-24 23:22:26 +08:00
87owo e8dda40e7f Add files via upload 2026-07-22 17:21:30 +08:00
87owo 5b4cd6e879 Add files via upload 2026-07-22 16:55:36 +08:00
87owo 316b061d34 Add files via upload 2026-07-22 13:22:34 +08:00
87owo 6ff27679e7 Add files via upload 2026-07-22 13:17:06 +08:00
87owo 8f3adbc870 Add files via upload 2026-07-22 13:13:08 +08:00
87owo 5798a35456 Add files via upload 2026-07-18 18:08:03 +08:00
87owo a8a2060978 Add files via upload 2026-07-18 17:38:02 +08:00
87owo 7cf2763511 Add files via upload 2026-07-18 17:34:32 +08:00
87owo fc59619518 Revise Driver Signature notice in LICENSE
Updated the language in the Driver Signature section for clarity.
2026-07-18 17:17:58 +08:00
87owo d01cfd2dd6 Update LICENSE.txt with new date and driver notice
Updated the last modified date in the license agreement and added a new section regarding driver signature notice.
2026-07-18 17:03:00 +08:00
87owo 9563a4806a Add files via upload 2026-07-17 17:55:26 +08:00
87owo fa1be109e3 Add files via upload 2026-07-17 17:41:26 +08:00
87owo 89a5a5928c Add files via upload 2026-07-17 11:36:43 +08:00
87owo 7830378f23 Add files via upload 2026-07-17 09:42:55 +08:00
87owo 043f616469 Add files via upload 2026-07-17 09:40:34 +08:00
87owo 3bf631313a Add files via upload 2026-07-17 09:38:11 +08:00
87owo a416e2d4a8 Add files via upload 2026-07-16 16:21:57 +08:00
16 changed files with 5976 additions and 4392 deletions

No files matched your search

+1101 -744
View File
File diff suppressed because it is too large. Load diff
+1156 -798
View File
File diff suppressed because it is too large. Load diff
+7 -8
View File
@@ -58,15 +58,14 @@ def analyze_schema(jsonl_path):
for line in f:
num_lines += 1
if not base_keys:
try:
data = JSON_LOADS(line)
base_data = data.get('Base')
if base_data:
base_keys.update(base_data.keys())
try:
data = JSON_LOADS(line)
base_data = data.get('Base')
if base_data:
base_keys.update(base_data.keys())
except Exception:
pass
except Exception:
pass
base_schema = sorted([k for k in base_keys if k.lower().strip() not in EXCLUDE_FEATURES])
dll_schema = [f"DllHash_{i:03d}" for i in range(DLL_HASH_DIM)]
+7 -8
View File
@@ -58,15 +58,14 @@ def analyze_schema(jsonl_path):
for line in f:
num_lines += 1
if not base_keys:
try:
data = JSON_LOADS(line)
base_data = data.get('Base')
if base_data:
base_keys.update(base_data.keys())
try:
data = JSON_LOADS(line)
base_data = data.get('Base')
if base_data:
base_keys.update(base_data.keys())
except Exception:
pass
except Exception:
pass
base_schema = sorted([k for k in base_keys if k.lower().strip() not in EXCLUDE_FEATURES])
dll_schema = [f"DllHash_{i:03d}" for i in range(DLL_HASH_DIM)]
+4 -3
View File
@@ -1,4 +1,4 @@
* {
* {
box-sizing: border-box;
margin: 0;
padding: 0;
@@ -14,6 +14,7 @@
--bg-hover: rgba(0, 0, 0, 0.05);
--text-primary: rgb(29, 29, 31);
--text-secondary: rgb(134, 134, 139);
--text-on-accent: rgb(255, 255, 255);
--border-color: rgb(210, 210, 215);
--accent-color: rgb(0, 122, 255);
--accent-alpha: rgba(0, 122, 255, 0.1);
@@ -82,7 +83,7 @@ body {
}
.ctrl-btn:hover { background-color: var(--bg-hover); color: var(--text-primary); }
#close_button:hover { background-color: #ff3b30; color: white; }
#close_button:hover { background-color: #ff3b30; color: var(--text-on-accent); }
.theme-svg {
width: 16px;
@@ -258,7 +259,7 @@ body {
.primary-btn {
background-color: var(--accent-color);
color: white;
color: var(--text-on-accent);
border: none;
box-shadow: 0 2px 4px var(--accent-shadow);
}
+29 -19
View File
@@ -1,4 +1,4 @@
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
document.addEventListener(eventName, e => {
e.preventDefault();
});
@@ -88,9 +88,9 @@ document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
if (!startupOverlayClosed) {
closeStartupOverlay();
showStartupError("PYAS WebView2 initialization is taking too long. The application will retry automatically.");
}
}, 12000);
}, 20000);
const formatMsg = (key, ...args) => {
let msg = getMsg(key);
@@ -104,12 +104,12 @@ document.addEventListener('DOMContentLoaded', () => {
};
const themes = {
"white_switch": { "--bg-window": "245, 245, 247", "--bg-nav": "255, 255, 255", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(0,0,0,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--border-color":"210, 210, 215", "--accent-color":"0, 122, 255", "--accent-alpha":"rgba(0, 122, 255, 0.1)", "--accent-shadow":"rgba(0, 122, 255, 0.2)", "--accent-hover":"rgba(0, 122, 255, 0.3)" },
"black_switch": { "--bg-window": "0, 0, 0", "--bg-nav": "28, 28, 30", "--bg-panel": "28, 28, 30", "--bg-hover": "rgba(255,255,255,0.1)", "--text-primary": "245, 245, 247", "--text-secondary": "134, 134, 139", "--border-color":"44, 44, 46", "--accent-color":"10, 132, 255", "--accent-alpha":"rgba(10, 132, 255, 0.1)", "--accent-shadow":"rgba(10, 132, 255, 0.2)", "--accent-hover":"rgba(10, 132, 255, 0.3)" },
"red_switch": { "--bg-window": "253, 246, 246", "--bg-nav": "255, 240, 240", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(255,59,48,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--border-color":"250, 220, 220", "--accent-color":"255, 59, 48", "--accent-alpha":"rgba(255, 59, 48, 0.1)", "--accent-shadow":"rgba(255, 59, 48, 0.2)", "--accent-hover":"rgba(255, 59, 48, 0.3)" },
"yellow_switch": { "--bg-window": "254, 251, 243", "--bg-nav": "255, 248, 230", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(255,149,0,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--border-color":"250, 240, 215", "--accent-color":"255, 149, 0", "--accent-alpha":"rgba(255, 149, 0, 0.1)", "--accent-shadow":"rgba(255, 149, 0, 0.2)", "--accent-hover":"rgba(255, 149, 0, 0.3)" },
"green_switch": { "--bg-window": "246, 253, 248", "--bg-nav": "235, 250, 240", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(52,199,89,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--border-color":"220, 240, 225", "--accent-color":"52, 199, 89", "--accent-alpha":"rgba(52, 199, 89, 0.1)", "--accent-shadow":"rgba(52, 199, 89, 0.2)", "--accent-hover":"rgba(52, 199, 89, 0.3)" },
"blue_switch": { "--bg-window": "246, 249, 253", "--bg-nav": "235, 244, 255", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(0,122,255,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--border-color":"220, 230, 250", "--accent-color":"0, 122, 255", "--accent-alpha":"rgba(0, 122, 255, 0.1)", "--accent-shadow":"rgba(0, 122, 255, 0.2)", "--accent-hover":"rgba(0, 122, 255, 0.3)" }
"white_switch": { "--bg-window": "245, 245, 247", "--bg-nav": "255, 255, 255", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(0,0,0,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--text-on-accent": "255, 255, 255", "--border-color":"210, 210, 215", "--accent-color":"0, 122, 255", "--accent-alpha":"rgba(0, 122, 255, 0.1)", "--accent-shadow":"rgba(0, 122, 255, 0.2)", "--accent-hover":"rgba(0, 122, 255, 0.3)" },
"black_switch": { "--bg-window": "0, 0, 0", "--bg-nav": "28, 28, 30", "--bg-panel": "28, 28, 30", "--bg-hover": "rgba(255,255,255,0.1)", "--text-primary": "216, 216, 220", "--text-secondary": "134, 134, 139", "--text-on-accent": "216, 216, 220", "--border-color":"44, 44, 46", "--accent-color":"10, 132, 255", "--accent-alpha":"rgba(10, 132, 255, 0.1)", "--accent-shadow":"rgba(10, 132, 255, 0.2)", "--accent-hover":"rgba(10, 132, 255, 0.3)" },
"red_switch": { "--bg-window": "253, 246, 246", "--bg-nav": "255, 240, 240", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(255,59,48,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--text-on-accent": "255, 255, 255", "--border-color":"250, 220, 220", "--accent-color":"255, 59, 48", "--accent-alpha":"rgba(255, 59, 48, 0.1)", "--accent-shadow":"rgba(255, 59, 48, 0.2)", "--accent-hover":"rgba(255, 59, 48, 0.3)" },
"yellow_switch": { "--bg-window": "254, 251, 243", "--bg-nav": "255, 248, 230", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(255,149,0,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--text-on-accent": "255, 255, 255", "--border-color":"250, 240, 215", "--accent-color":"255, 149, 0", "--accent-alpha":"rgba(255, 149, 0, 0.1)", "--accent-shadow":"rgba(255, 149, 0, 0.2)", "--accent-hover":"rgba(255, 149, 0, 0.3)" },
"green_switch": { "--bg-window": "246, 253, 248", "--bg-nav": "235, 250, 240", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(52,199,89,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--text-on-accent": "255, 255, 255", "--border-color":"220, 240, 225", "--accent-color":"52, 199, 89", "--accent-alpha":"rgba(52, 199, 89, 0.1)", "--accent-shadow":"rgba(52, 199, 89, 0.2)", "--accent-hover":"rgba(52, 199, 89, 0.3)" },
"blue_switch": { "--bg-window": "246, 249, 253", "--bg-nav": "235, 244, 255", "--bg-panel": "255, 255, 255", "--bg-hover": "rgba(0,122,255,0.05)", "--text-primary": "29, 29, 31", "--text-secondary": "134, 134, 139", "--text-on-accent": "255, 255, 255", "--border-color":"220, 230, 250", "--accent-color":"0, 122, 255", "--accent-alpha":"rgba(0, 122, 255, 0.1)", "--accent-shadow":"rgba(0, 122, 255, 0.2)", "--accent-hover":"rgba(0, 122, 255, 0.3)" }
};
const cols = {
@@ -1120,8 +1120,17 @@ document.addEventListener('DOMContentLoaded', () => {
renderDataGrid('#log_export_window', [], cols.log, 'id', true);
renderDataGrid('#netmon_window', [], cols.netmon, 'pid', false);
window.addEventListener('pywebviewready', () => {
window.pywebview.api.get_config().then(cfg => {
let pywebviewInitStarted = false;
const initializePywebview = () => {
if (pywebviewInitStarted || !window.pywebview?.api) return;
pywebviewInitStarted = true;
const configTimeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Configuration request timed out")), 10000);
});
Promise.race([window.pywebview.api.get_config(), configTimeout]).then(cfg => {
const theme = cfg.theme || "white_switch";
const lang = cfg.language || "english_switch";
appState.firstLaunch = cfg.first_launch;
@@ -1132,24 +1141,25 @@ document.addEventListener('DOMContentLoaded', () => {
const switchMap = ["process_switch", "suspend_switch", "load_switch", "document_switch", "system_switch", "network_switch", "driver_switch", "sensitive_switch", "extension_switch", "cloud_switch", "suffix_switch", "autostart_switch", "context_switch"];
document.querySelectorAll('.toggle-switch input').forEach((toggle, index) => {
if (appState.firstLaunch) {
toggle.checked = false;
toggle.disabled = true;
if (appState.firstLaunch) {
toggle.checked = false;
toggle.disabled = true;
} else if (switchMap[index]) {
toggle.checked = !!cfg[switchMap[index]];
}
});
closeStartupOverlay();
window.pywebview.api.init_ui_ready();
}).catch(err => {
pywebviewInitStarted = false;
console.error("Config load failed:", err);
showStartupError(`Configuration failed to load: ${err?.message || err}`);
try {
window.pywebview.api.init_ui_ready();
} catch (e) {}
});
});
};
window.addEventListener('pywebviewready', initializePywebview);
initializePywebview();
window.onEngineReady = async () => {
if (!appState.firstLaunch) return;
+7 -5
View File
@@ -10,11 +10,12 @@
<script>
window.addEventListener('DOMContentLoaded', function () {
window.setTimeout(function () {
var app = document.querySelector('.app-container');
var overlay = document.getElementById('loading_overlay');
if (app) app.classList.add('fade-in');
if (overlay && !overlay.classList.contains('fade-out')) overlay.classList.add('fade-out');
}, 15000);
if (overlay && !overlay.classList.contains('fade-out') && !overlay.classList.contains('startup-error')) {
overlay.classList.add('startup-error');
overlay.innerHTML = '<div class="startup-error-box"><h1>PYAS failed to open</h1><p>WebView2 initialization timed out. PYAS will retry automatically.</p></div>';
}
}, 20000);
});
</script>
</head>
@@ -319,7 +320,7 @@
<div class="license-widget">
<textarea class="license-text" readonly>87owo Publicly Available Source Code License Agreement
Last Updated: 2026-06-09
Last Updated: 2026-07-18
IMPORTANT NOTICE: THIS LICENSE IS "SOURCE AVAILABLE" AND IS NOT AN OPEN SOURCE LICENSE APPROVED BY THE OPEN SOURCE INITIATIVE (OSI). BY DOWNLOADING, ACCESSING, OR USING THE SOFTWARE, YOU AGREE TO BE BOUND BY THESE TERMS.
1. Definitions and Interpretation
@@ -371,6 +372,7 @@ IMPORTANT NOTICE: THIS LICENSE IS "SOURCE AVAILABLE" AND IS NOT AN OPEN SOURCE L
- 7.3. Scope of Collected Extensions: Sample collection targets potential executable and system binary formats, which explicitly include, but are not limited to, files with the following extensions: `.exe`, `.dll`, `.sys`, `.ocx`, `.scr`, `.efi`, `.acm`, `.ax`, `.cpl`, `.drv`, `.com`, `.mui`, `.pyd`, `.wfx`, `.api`, `.awx`, `.rll`, and `.winmd`.
- 7.4. Public Disclosure of Threat Intelligence: You explicitly acknowledge and agree that the metadata, behavioral reports, and threat intelligence data generated from the cloud analysis of submitted samples may be publicly disclosed, published, or shared with the cybersecurity community for collaborative defense purposes.
- 7.5. Opt-Out Mechanism: Cloud-based telemetry and sample submission are fully optional. Users who do not wish to participate in sample collection or cloud-assisted analysis may disable the corresponding cloud services at any time via the toggle switches provided within the Software’s settings interface.
- 7.6. Driver Signature: Certain kernel-mode drivers distributed with this software may be digitally signed using code signing methods that are not certified by Microsoft Windows Hardware Quality Labs (WHQL). By installing or using this software, you acknowledge this and decide for yourself whether to install and trust such drivers on your system.
8. Warranty Disclaimer and Limitation of Liability
+2 -1
View File
@@ -1,6 +1,6 @@
87owo Publicly Available Source Code License Agreement
Last Updated: 2026-06-09
Last Updated: 2026-07-18
IMPORTANT NOTICE: THIS LICENSE IS "SOURCE AVAILABLE" AND IS NOT AN OPEN SOURCE LICENSE APPROVED BY THE OPEN SOURCE INITIATIVE (OSI). BY DOWNLOADING, ACCESSING, OR USING THE SOFTWARE, YOU AGREE TO BE BOUND BY THESE TERMS.
1. Definitions and Interpretation
@@ -52,6 +52,7 @@ IMPORTANT NOTICE: THIS LICENSE IS "SOURCE AVAILABLE" AND IS NOT AN OPEN SOURCE L
- 7.3. Scope of Collected Extensions: Sample collection targets potential executable and system binary formats, which explicitly include, but are not limited to, files with the following extensions: `.exe`, `.dll`, `.sys`, `.ocx`, `.scr`, `.efi`, `.acm`, `.ax`, `.cpl`, `.drv`, `.com`, `.mui`, `.pyd`, `.wfx`, `.api`, `.awx`, `.rll`, and `.winmd`.
- 7.4. Public Disclosure of Threat Intelligence: You explicitly acknowledge and agree that the metadata, behavioral reports, and threat intelligence data generated from the cloud analysis of submitted samples may be publicly disclosed, published, or shared with the cybersecurity community for collaborative defense purposes.
- 7.5. Opt-Out Mechanism: Cloud-based telemetry and sample submission are fully optional. Users who do not wish to participate in sample collection or cloud-assisted analysis may disable the corresponding cloud services at any time via the toggle switches provided within the Software’s settings interface.
- 7.6. Driver Signature: Certain kernel-mode drivers distributed with this software may be digitally signed using code signing methods that are not certified by Microsoft Windows Hardware Quality Labs (WHQL). By installing or using this software, you acknowledge this and decide for yourself whether to install and trust such drivers on your system.
8. Warranty Disclaimer and Limitation of Liability
+1456 -1323
View File
File diff suppressed because it is too large. Load diff
+1306 -970
View File
File diff suppressed because it is too large. Load diff
+216 -154
View File
@@ -1,6 +1,6 @@
#define AppId "{{a7d7bac3-93b8-4630-8308-c7a56bf7fdf4}"
#define AppName "PYAS"
#define AppVersion "3.6.3.0"
#define AppVersion "3.6.8.0"
#define AppPublisher "PYAS Security"
#define AppURL "https://github.com/87owo/PYAS"
#define AppExeName "PYAS.exe"
@@ -52,20 +52,22 @@ Name: "arabic"; MessagesFile: "SetupResources\Arabic.isl"
Name: "russian"; MessagesFile: "SetupResources\Russian.isl"
Name: "slovenian"; MessagesFile: "SetupResources\Slovenian.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
Name: "autostart"; Description: "{cm:AutoStartTask}"; GroupDescription: "{cm:AdditionalIcons}"
Name: "install_webview2"; Description: "{cm:InstallWebView2}"; GroupDescription: "{cm:Dependencies}"
Name: "install_vcredist"; Description: "{cm:InstallVCRedist}"; GroupDescription: "{cm:Dependencies}"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
[Files]
Source: "Payload\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Redist\VC_redist.x64.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion
Source: "Redist\MicrosoftEdgeWebview2Setup.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion
Source: "Redist\VC_redist.x64.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion; AfterInstall: EnsureVCRedist
Source: "Redist\MicrosoftEdgeWebview2Setup.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion; AfterInstall: EnsureWebView2
Source: "Payload\Engine\*"; DestDir: "{app}\Engine"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Payload\Interface\*"; DestDir: "{app}\Interface"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Payload\License\*"; DestDir: "{app}\License"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Payload\PYAS.exe"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: FinalizeDriverRemoval
Source: "Payload\Plugins\*"; DestDir: "{app}\Plugins"; Flags: ignoreversion recursesubdirs createallsubdirs
[Registry]
Root: HKCU; Subkey: "Software\Classes\*\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey
Root: HKCU; Subkey: "Software\Classes\Directory\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey
[Registry]
Root: HKCU; Subkey: "Software\Classes\*\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey
Root: HKCU; Subkey: "Software\Classes\Directory\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueName: "PYAS_Security"; Flags: uninsdeletevalue dontcreatekey
[UninstallDelete]
Type: filesandordirs; Name: "{commonappdata}\PYAS"
@@ -76,9 +78,7 @@ Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"
Name: "{group}\Uninstall {#AppName}"; Filename: "{uninstallexe}"
[Run]
Filename: "{tmp}\PYAS_Redist\VC_redist.x64.exe"; Parameters: "/quiet /norestart"; Flags: waituntilterminated runhidden; StatusMsg: "{cm:InstallingVCRuntime}"; Tasks: install_vcredist
Filename: "{tmp}\PYAS_Redist\MicrosoftEdgeWebview2Setup.exe"; Parameters: "/silent /install"; Flags: waituntilterminated runhidden; StatusMsg: "{cm:InstallingWebView2Runtime}"; Tasks: install_webview2
Filename: "{app}\{#AppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(AppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser
Filename: "{app}\{#AppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(AppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser; Check: CanLaunchApp
[CustomMessages]
english.InstallingVCRuntime=Installing Microsoft Visual C++ Runtime...
@@ -87,9 +87,6 @@ chinesetraditional.InstallingVCRuntime=正在安裝 Microsoft Visual C++ 執行
english.InstallingWebView2Runtime=Installing Microsoft Edge WebView2 Runtime...
chinesesimplified.InstallingWebView2Runtime=正在安装 Microsoft Edge WebView2 Runtime...
chinesetraditional.InstallingWebView2Runtime=正在安裝 Microsoft Edge WebView2 Runtime...
english.AutoStartTask=Run PYAS automatically at system startup
chinesesimplified.AutoStartTask=开机时自动运行 PYAS
chinesetraditional.AutoStartTask=開機時自動執行 PYAS
english.Dependencies=Dependencies:
chinesesimplified.Dependencies=运行环境:
chinesetraditional.Dependencies=執行環境:
@@ -100,154 +97,219 @@ english.InstallVCRedist=Install Microsoft Visual C++ Runtime
chinesesimplified.InstallVCRedist=安装 Microsoft Visual C++ 运行库
chinesetraditional.InstallVCRedist=安裝 Microsoft Visual C++ 執行庫
english.LegacyVersionDetected=An older version of PYAS was detected. Please uninstall it manually before installing.
english.QuitFailed=PYAS or its driver could not be stopped safely. Restart Windows and run Setup again.
english.DependencyInstallFailed=Required Microsoft runtime installation failed. Setup cannot continue.
chinesesimplified.LegacyVersionDetected=检测到存在旧版 PYAS。请先手动卸载旧版后,再运行本安装程序。
chinesetraditional.LegacyVersionDetected=檢測到存在舊版 PYAS。請先手動卸載舊版後,再執行本安裝程式。
[Code]
var
TasksInitialized: Boolean;
function IsWebView2Installed: Boolean;
var
RegKeyPath: string;
Version: string;
begin
RegKeyPath := 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}';
Result := False;
if RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then
if Length(Version) > 0 then Result := True;
if not Result and RegQueryStringValue(HKCU, RegKeyPath, 'pv', Version) then
if Length(Version) > 0 then Result := True;
if not Result and RegQueryStringValue(HKLM, RegKeyPath, 'pv', Version) then
if Length(Version) > 0 then Result := True;
end;
function IsVCRedistInstalled: Boolean;
var
Bld: Cardinal;
begin
Result := False;
if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Bld', Bld) then
if Bld > 0 then Result := True;
end;
procedure CurPageChanged(CurPageID: Integer);
var
I: Integer;
ItemText: string;
begin
if (CurPageID = wpSelectTasks) and not TasksInitialized then
begin
TasksInitialized := True;
for I := 0 to WizardForm.TasksList.Items.Count - 1 do
begin
ItemText := WizardForm.TasksList.Items[I];
if Pos('Visual C++', ItemText) > 0 then
WizardForm.TasksList.Checked[I] := not IsVCRedistInstalled
else if Pos('WebView2', ItemText) > 0 then
WizardForm.TasksList.Checked[I] := not IsWebView2Installed;
end;
end;
end;
procedure QuitOldInstance(InstallPath: string);
var
ResultCode: Integer;
ExePath: string;
begin
ExePath := InstallPath + '\{#AppExeName}';
if FileExists(ExePath) then
begin
Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
Sleep(500);
Exec(ExpandConstant('{sys}\taskkill.exe'), '/F /IM {#AppExeName} /T', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;
function InitializeSetup(): Boolean;
var
OldInstallPath: string;
LegacyPath: string;
begin
LegacyPath := ExpandConstant('{pf32}\{#AppName}');
if DirExists(LegacyPath) and FileExists(LegacyPath + '\{#AppExeName}') then
begin
MsgBox(CustomMessage('LegacyVersionDetected'), mbCriticalError, MB_OK);
Result := False;
Exit;
end;
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) or
RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) then
begin
QuitOldInstance(OldInstallPath);
end;
Result := True;
end;
function InitializeUninstall(): Boolean;
begin
QuitOldInstance(ExpandConstant('{app}'));
Result := True;
end;
procedure TryCreateStartupTask;
var
ResultCode: Integer;
PSExe: string;
PSCommand: string;
AppPath: string;
begin
AppPath := ExpandConstant('{app}\{#AppExeName}');
PSExe := ExpandConstant('{sys}\WindowsPowerShell\v1.0\powershell.exe');
PSCommand := '-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -Command ' +
'$Action = New-ScheduledTaskAction -Execute ''' + AppPath + ''' -Argument ''-hide''; ' +
'$Trigger = New-ScheduledTaskTrigger -AtLogOn; ' +
'$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries; ' +
'Register-ScheduledTask -TaskName ''PYAS_Security_ATS'' -Action $Action -Trigger $Trigger -Settings $Settings -RunLevel Highest -Force';
if not Exec(PSExe, PSCommand, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Log(Format('Failed to create scheduled task, Exec error code: %d', [ResultCode]));
end
else if ResultCode <> 0 then
begin
Log(Format('powershell returned exit code %d while creating the scheduled task', [ResultCode]));
end;
end;
procedure TryDeleteStartupTask;
var
ResultCode: Integer;
begin
if not Exec(ExpandConstant('{sys}\schtasks.exe'), '/Delete /TN "PYAS_Security_ATS" /F', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Log(Format('Failed to delete scheduled task, Exec error code: %d', [ResultCode]));
end
else if ResultCode <> 0 then
begin
Log(Format('schtasks returned exit code %d while deleting the scheduled task', [ResultCode]));
end;
end;
[Code]
var
DependencyRestartRequired: Boolean;
DependenciesReady: Boolean;
function FindWindow(lpClassName: LongWord; lpWindowName: string): HWND;
external '[email protected] stdcall';
function GetTickCount: Cardinal;
external '[email protected] stdcall';
function IsValidRuntimeVersion(Version: string): Boolean;
begin
Result := (Length(Trim(Version)) > 0) and (Trim(Version) <> '0.0.0.0');
end;
function IsWebView2Installed: Boolean;
var
Version: string;
begin
Result := False;
if RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then
Result := IsValidRuntimeVersion(Version);
if not Result and RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then
Result := IsValidRuntimeVersion(Version);
if not Result and RegQueryStringValue(HKCU, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then
Result := IsValidRuntimeVersion(Version);
end;
function IsVCRedistInstalled: Boolean;
var
Installed: Cardinal;
Version: string;
begin
Result := False;
if RegQueryDWordValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Installed', Installed) and (Installed = 1) then
begin
if RegQueryStringValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', Version) then
Result := IsValidRuntimeVersion(Version)
else
Result := True;
end;
end;
function DependencyExitCodeSucceeded(ResultCode: Integer): Boolean;
begin
Result := (ResultCode = 0) or (ResultCode = 1641) or (ResultCode = 3010);
if (ResultCode = 1641) or (ResultCode = 3010) then
DependencyRestartRequired := True;
end;
procedure EnsureVCRedist;
var
ResultCode: Integer;
InstallerPath: string;
begin
if IsVCRedistInstalled then Exit;
InstallerPath := ExpandConstant('{tmp}\PYAS_Redist\VC_redist.x64.exe');
WizardForm.StatusLabel.Caption := CustomMessage('InstallingVCRuntime');
if not Exec(InstallerPath, '/quiet /norestart', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or
not DependencyExitCodeSucceeded(ResultCode) or not IsVCRedistInstalled then
begin
DependenciesReady := False;
RaiseException(CustomMessage('DependencyInstallFailed'));
end;
end;
procedure EnsureWebView2;
var
ResultCode: Integer;
InstallerPath: string;
begin
if IsWebView2Installed then Exit;
InstallerPath := ExpandConstant('{tmp}\PYAS_Redist\MicrosoftEdgeWebview2Setup.exe');
WizardForm.StatusLabel.Caption := CustomMessage('InstallingWebView2Runtime');
if not Exec(InstallerPath, '/silent /install', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or
not DependencyExitCodeSucceeded(ResultCode) or not IsWebView2Installed then
begin
DependenciesReady := False;
RaiseException(CustomMessage('DependencyInstallFailed'));
end;
end;
function WaitForMainWindowToClose(TimeoutMs: Cardinal): Boolean;
var
Deadline: Cardinal;
begin
Deadline := GetTickCount + TimeoutMs;
repeat
if FindWindow(0, 'PYAS Security') = 0 then
begin
Result := True;
Exit;
end;
Sleep(100);
until GetTickCount >= Deadline;
Result := False;
end;
function QuitOldInstance(InstallPath: string): Boolean;
var
ResultCode: Integer;
ExePath: string;
begin
Result := True;
ExePath := InstallPath + '\{#AppExeName}';
if not FileExists(ExePath) then Exit;
if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Result := False;
Exit;
end;
Result := (ResultCode = 0) and WaitForMainWindowToClose(30000);
end;
procedure FinalizeDriverRemoval;
var
ResultCode: Integer;
ExePath: string;
begin
ExePath := ExpandConstant('{app}\{#AppExeName}');
if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or (ResultCode <> 0) then
RaiseException(CustomMessage('QuitFailed'));
end;
function InitializeSetup(): Boolean;
var
OldInstallPath: string;
LegacyPath: string;
begin
DependencyRestartRequired := False;
DependenciesReady := True;
LegacyPath := ExpandConstant('{pf32}\{#AppName}');
if DirExists(LegacyPath) and FileExists(LegacyPath + '\{#AppExeName}') then
begin
MsgBox(CustomMessage('LegacyVersionDetected'), mbCriticalError, MB_OK);
Result := False;
Exit;
end;
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) or
RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) then
begin
if not QuitOldInstance(OldInstallPath) then
begin
MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK);
Result := False;
Exit;
end;
end;
Result := True;
end;
function InitializeUninstall(): Boolean;
begin
Result := QuitOldInstance(ExpandConstant('{app}'));
if not Result then
MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK);
end;
function CanLaunchApp: Boolean;
begin
Result := DependenciesReady and not DependencyRestartRequired;
end;
function NeedRestart: Boolean;
begin
Result := DependencyRestartRequired;
end;
procedure RemoveLegacyStartupTask;
var
TaskService: Variant;
RootFolder: Variant;
begin
try
TaskService := CreateOleObject('Schedule.Service');
TaskService.Connect();
RootFolder := TaskService.GetFolder('\');
try
RootFolder.DeleteTask('PYAS_Security_ATS', 0);
Log('Removed legacy PYAS scheduled startup task');
except
Log('Legacy PYAS scheduled startup task was not present or could not be removed');
end;
except
Log('Task Scheduler COM was unavailable while cleaning the legacy startup task');
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
if WizardIsTaskSelected('autostart') then
begin
TryCreateStartupTask;
end;
end;
if CurStep = ssPostInstall then
begin
RemoveLegacyStartupTask;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then
begin
TryDeleteStartupTask;
if CurUninstallStep = usUninstall then
begin
RemoveLegacyStartupTask;
end
else if CurUninstallStep = usPostUninstall then
begin
DelTree(ExpandConstant('{app}'), True, True, True);
end;
end;
end;
+273 -119
View File
@@ -7,8 +7,18 @@ FLT_PORT_FLAG_SYNC_HANDLE = 0x00000001
HRESULT_IO_PENDING = 0x800703E5
ERROR_OPERATION_ABORTED = 995
ERROR_NOT_FOUND = 1168
ERROR_SHARING_VIOLATION = 32
ERROR_LOCK_VIOLATION = 33
WAIT_OBJECT_0 = 0
WAIT_TIMEOUT = 258
INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 0x00000001
OPEN_EXISTING = 3
FILE_ATTRIBUTE_NORMAL = 0x00000080
FILE_SCAN_DEBOUNCE_SECONDS = 0.35
FILE_SCAN_RETRY_SECONDS = 0.25
FILE_LOCK_RETRY_SECONDS = 0.5
PYAS_CONNECTION_MAGIC = 0x53415950
PYAS_CONNECTION_VERSION = 1
PROCESS_TERMINATE = 0x0001
@@ -72,97 +82,143 @@ class ProtectMixin:
def init_whitelist(self):
self.manage_named_list("white_list", [self.file_pyas], action="add")
def sync_driver_whitelist(self, file_path, is_add=True):
def _driver_whitelist_patterns(self, file_path, is_directory=None):
normalized_path = self.norm_path(file_path, must_exist=False)
if not normalized_path:
return []
if is_directory is None:
is_directory = os.path.isdir(normalized_path)
drive_letter = os.path.splitdrive(normalized_path)[0]
driver_path = "*" + normalized_path[len(drive_letter):] if drive_letter else normalized_path
patterns = [driver_path]
if is_directory:
descendant_pattern = driver_path.rstrip("\\/") + "\\*"
if descendant_pattern not in patterns:
patterns.append(descendant_pattern)
return patterns
def sync_driver_whitelist(self, file_path, is_add=True, is_directory=None):
with self.lock_driver:
if not self.driver_port:
return False
driver_path = str(file_path)
drive_letter = os.path.splitdrive(driver_path)[0]
if drive_letter:
driver_path = "*" + driver_path[len(drive_letter):]
msg = PYAS_USER_MESSAGE()
msg.Command = 1 if is_add else 2
msg.Path = driver_path
bytes_returned = ctypes.wintypes.DWORD(0)
try:
return self.fltlib.FilterSendMessage(self.driver_port, ctypes.byref(msg), ctypes.sizeof(msg), None, 0, ctypes.byref(bytes_returned)) == 0
except Exception:
patterns = self._driver_whitelist_patterns(file_path, is_directory)
if not patterns:
return False
success = True
for driver_path in patterns:
msg = PYAS_USER_MESSAGE()
msg.Command = 1 if is_add else 2
bytes_returned = ctypes.wintypes.DWORD(0)
try:
msg.Path = driver_path
if self.fltlib.FilterSendMessage(self.driver_port, ctypes.byref(msg), ctypes.sizeof(msg), None, 0, ctypes.byref(bytes_returned)) != 0:
success = False
except Exception:
success = False
return success
####################################################################################################
def lock_file(self, target_path, lock, quiet=False):
def _try_lock_file(self, file_path):
fd = None
try:
fd = os.open(file_path, os.O_RDWR | os.O_BINARY)
try:
size = os.path.getsize(file_path)
except Exception:
size = 1
lock_size = size if size > 0 else 1
msvcrt.locking(fd, msvcrt.LK_NBRLCK, lock_size)
self.virus_lock[file_path] = (fd, lock_size)
return True, None
except Exception as e:
if fd is not None:
try:
os.close(fd)
except Exception:
pass
return False, e
def _queue_file_lock(self, file_path):
self._schedule_file_task("lock", file_path, self._retry_file_lock, FILE_LOCK_RETRY_SECONDS)
def _retry_file_lock(self, file_path):
if not os.path.isfile(file_path):
return
with self.lock_file_ops:
if lock:
if not os.path.exists(target_path):
return
if file_path in self.virus_lock:
return
success, _ = self._try_lock_file(file_path)
paths_to_lock = []
if os.path.isdir(target_path):
for root, _, files in os.walk(target_path):
for f in files:
paths_to_lock.append(os.path.join(root, f))
else:
paths_to_lock.append(target_path)
if not success:
self._queue_file_lock(file_path)
def lock_file(self, target_path, lock, quiet=False):
if lock:
if not os.path.exists(target_path):
return False
paths_to_lock = []
if os.path.isdir(target_path):
for root, _, files in os.walk(target_path):
for file_name in files:
paths_to_lock.append(os.path.join(root, file_name))
else:
paths_to_lock.append(target_path)
failed_locks = []
with self.lock_file_ops:
for file_path in paths_to_lock:
if file_path in self.virus_lock:
continue
success = False
last_error = None
for _ in range(5):
try:
fd = os.open(file_path, os.O_RDWR | os.O_BINARY)
try:
try:
size = os.path.getsize(file_path)
except Exception:
size = 1
success, error = self._try_lock_file(file_path)
if not success:
failed_locks.append((file_path, error))
lock_size = size if size > 0 else 1
msvcrt.locking(fd, msvcrt.LK_NBRLCK, lock_size)
self.virus_lock[file_path] = (fd, lock_size)
success = True
break
for file_path, error in failed_locks:
self._queue_file_lock(file_path)
if not quiet:
self.write_log("INFO", "File Lock Deferred", source=file_path, detail=str(error))
except Exception as e:
os.close(fd)
raise e
return not failed_locks
except Exception as e:
last_error = e
time.sleep(0.1)
self._cancel_pending_file_tasks("lock", target_path)
with self.lock_file_ops:
target_norm = os.path.normcase(target_path)
target_dir = target_norm + os.sep
keys_to_unlock = []
if not success and not quiet:
self.write_log("WARN", "lock_file", source=file_path, detail=str(last_error), success=False)
else:
target_norm = os.path.normcase(target_path)
target_dir = target_norm + os.sep
keys_to_unlock = []
for locked_path in self.virus_lock:
locked_norm = os.path.normcase(locked_path)
if locked_norm == target_norm or locked_norm.startswith(target_dir):
keys_to_unlock.append(locked_path)
for locked_path in self.virus_lock:
locked_norm = os.path.normcase(locked_path)
if locked_norm == target_norm or locked_norm.startswith(target_dir):
keys_to_unlock.append(locked_path)
for file_path in keys_to_unlock:
fd, lock_size = self.virus_lock[file_path]
for file_path in keys_to_unlock:
fd, lock_size = self.virus_lock[file_path]
try:
msvcrt.locking(fd, msvcrt.LK_UNLCK, lock_size)
except Exception as e:
if not quiet:
self.write_log("WARN", "unlock_file", source=file_path, detail=str(e), success=False)
finally:
try:
msvcrt.locking(fd, msvcrt.LK_UNLCK, lock_size)
except Exception as e:
if not quiet:
self.write_log("WARN", "unlock_file", source=file_path, detail=str(e), success=False)
os.close(fd)
except Exception:
pass
del self.virus_lock[file_path]
finally:
try:
os.close(fd)
except Exception:
pass
del self.virus_lock[file_path]
return True
def relock_file(self):
while True:
@@ -665,7 +721,7 @@ class ProtectMixin:
suffix = self.pyas_config.get("suffix", [])
if not ext_filter or os.path.splitext(file_path)[-1].lower() in suffix:
self.protect_pool.submit(self.handle_new_file, file_path)
self._queue_file_scan(file_path)
if notify.NextEntryOffset == 0:
break
@@ -683,33 +739,106 @@ class ProtectMixin:
pass
self.h_dir_file = None
def _cancel_pending_file_tasks(self, task_name=None, target_path=None):
target_norm = os.path.normcase(target_path) if target_path else None
target_dir = target_norm + os.sep if target_norm else None
with self.lock_file_ops:
task_keys = []
for task_key in self.file_task_timers:
name, path_key = task_key
if task_name and name != task_name:
continue
if target_norm and path_key != target_norm and not path_key.startswith(target_dir):
continue
task_keys.append(task_key)
timers = [self.file_task_timers.pop(task_key) for task_key in task_keys]
for task_key in task_keys:
self.file_task_generations.pop(task_key, None)
for timer in timers:
timer.cancel()
def _cancel_pending_file_scans(self):
self._cancel_pending_file_tasks("scan")
def _schedule_file_task(self, task_name, file_path, callback, delay):
task_key = (task_name, os.path.normcase(file_path))
with self.lock_file_ops:
previous_timer = self.file_task_timers.get(task_key)
if previous_timer:
previous_timer.cancel()
generation = self.file_task_generations.get(task_key, 0) + 1
timer = threading.Timer(delay, self._run_file_task, args=(task_key, file_path, generation, callback))
timer.daemon = True
self.file_task_timers[task_key] = timer
self.file_task_generations[task_key] = generation
timer.start()
def _run_file_task(self, task_key, file_path, generation, callback):
with self.lock_file_ops:
if self.file_task_generations.get(task_key) != generation:
return
if self.file_task_timers.get(task_key) is threading.current_thread():
self.file_task_timers.pop(task_key, None)
try:
callback(file_path)
finally:
with self.lock_file_ops:
if self.file_task_generations.get(task_key) == generation:
self.file_task_timers.pop(task_key, None)
self.file_task_generations.pop(task_key, None)
def _queue_file_scan(self, file_path, delay=FILE_SCAN_DEBOUNCE_SECONDS):
self._schedule_file_task("scan", file_path, self.handle_new_file, delay)
def _acquire_file_scan_gate(self, file_path):
ctypes.set_last_error(0)
handle = self.kernel32.CreateFileW(
file_path,
GENERIC_READ,
FILE_SHARE_READ,
None,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
None
)
if handle == INVALID_HANDLE_VALUE:
return None, ctypes.get_last_error()
return handle, 0
def handle_new_file(self, file_path):
try:
for _ in range(5):
try:
fd = os.open(file_path, os.O_RDONLY | os.O_BINARY)
os.close(fd)
with self.lock_config:
if not self.pyas_config.get("document_switch", False):
return
size = os.path.getsize(file_path)
if size > 0:
break
except Exception:
pass
time.sleep(0.1)
else:
gate_handle, error = self._acquire_file_scan_gate(file_path)
if not gate_handle:
if error in (ERROR_SHARING_VIOLATION, ERROR_LOCK_VIOLATION):
self._queue_file_scan(file_path, FILE_SCAN_RETRY_SECONDS)
return
with self.lock_file_ops:
if file_path in self.virus_lock: return
try:
with self.lock_file_ops:
if file_path in self.virus_lock:
return
result = self.safe_scan_engine(file_path)
self.cloud_check(file_path)
if result:
if self.manage_named_list("quarantine", [file_path], action="add", lock_func=self.lock_file) > 0:
self.write_log("BLOCK", "File Block", source=file_path, file_hash=self.calc_file_hash(file_path))
result = self.safe_scan_engine(file_path)
self.cloud_check(file_path)
if result:
if self.manage_named_list("quarantine", [file_path], action="add", lock_func=self.lock_file) > 0:
self.write_log("BLOCK", "File Block", source=file_path, file_hash=self.calc_file_hash(file_path))
finally:
self.kernel32.CloseHandle(gate_handle)
except Exception:
pass
@@ -785,7 +914,10 @@ class ProtectMixin:
running = any(exe_name.lower() == "explorer.exe" for _, exe_name in self._enum_processes())
if not running:
subprocess.Popen("explorer.exe", shell=True)
explorer = self._find_windows_tool("explorer.exe")
if not explorer:
return
subprocess.Popen([explorer])
self.write_log("INFO", "System Restart", source="explorer.exe")
except Exception:
@@ -1081,36 +1213,59 @@ class ProtectMixin:
self.advapi32.CloseServiceHandle(service)
self.advapi32.CloseServiceHandle(scm)
def _delete_driver_service(self):
scm = self.advapi32.OpenSCManagerW(None, None, 0x0001)
if not scm:
return False, ctypes.get_last_error()
def uninstall_system_driver(self):
if not self.stop_system_driver():
return False, 1051
return self._delete_driver_service()
service = None
try:
service = self.advapi32.OpenServiceW(scm, "PYAS_Driver", 0x0004 | 0x00010000)
if not service:
error = ctypes.get_last_error()
return (True, 0) if error in (1060, 1072) else (False, error)
def _delete_driver_service(self, timeout=15.0):
deadline = time.monotonic() + timeout
last_error = 0
delete_requested = False
state, error = self._query_service_state_handle(service)
if error:
return False, error
if state in (2, 3, 4):
return False, 1051
while time.monotonic() < deadline:
scm = self.advapi32.OpenSCManagerW(None, None, 0x0001)
if not scm:
return False, ctypes.get_last_error()
ctypes.set_last_error(0)
if self.advapi32.DeleteService(service):
return True, 0
service = None
try:
ctypes.set_last_error(0)
service = self.advapi32.OpenServiceW(scm, "PYAS_Driver", 0x0004 | 0x00010000)
if not service:
last_error = ctypes.get_last_error()
if last_error == 1060:
return True, 0
if last_error != 1072:
return False, last_error
else:
state, status_error = self._query_service_state_handle(service)
if status_error:
return False, status_error
error = ctypes.get_last_error()
if error in (1060, 1072):
return True, 0
return False, error
finally:
if service:
self.advapi32.CloseServiceHandle(service)
self.advapi32.CloseServiceHandle(scm)
if state not in (2, 3, 4) and not delete_requested:
ctypes.set_last_error(0)
if self.advapi32.DeleteService(service):
delete_requested = True
last_error = 1072
else:
last_error = ctypes.get_last_error()
if last_error == 1060:
return True, 0
if last_error == 1072:
delete_requested = True
else:
return False, last_error
elif state in (2, 3, 4):
last_error = 1051
finally:
if service:
self.advapi32.CloseServiceHandle(service)
self.advapi32.CloseServiceHandle(scm)
time.sleep(0.1)
return False, last_error or 1072
def install_system_driver(self):
try:
@@ -1776,7 +1931,7 @@ class ProtectMixin:
if self.driver_stop_event.is_set():
break
if isinstance(item, dict) and item.get("file"):
self.sync_driver_whitelist(item["file"], True)
self.sync_driver_whitelist(item["file"], True, item.get("is_dir"))
if self.driver_stop_event.is_set():
break
@@ -1843,4 +1998,3 @@ class ProtectMixin:
with self.lock_driver:
if self.driver_listener_thread is threading.current_thread():
self.driver_listener_thread = None
+50 -13
View File
@@ -437,6 +437,47 @@ class ScannerMixin:
####################################################################################################
def _queue_virus_delete(self, file_path):
self._schedule_file_task("delete", file_path, self._retry_virus_delete, 0.5)
def _retry_virus_delete(self, file_path):
file_hash = self.calc_file_hash(file_path)
try:
with self.lock_file_ops:
if file_path in self.virus_lock:
self.lock_file(file_path, False)
target_key = os.path.normcase(self.norm_path(file_path, must_exist=False) or file_path)
for proc in self.get_process_list():
proc_path = proc.get("path")
if not proc_path or proc_path == "None":
continue
proc_key = os.path.normcase(self.norm_path(proc_path, must_exist=False) or proc_path)
if proc_key == target_key:
self.kill_process(proc["pid"])
try:
os.chmod(file_path, stat.S_IWRITE)
except Exception:
pass
os.remove(file_path)
except FileNotFoundError:
pass
except Exception as e:
self.lock_file(file_path, True, quiet=True)
self._queue_virus_delete(file_path)
self.write_log("INFO", "Virus Delete Deferred", source=file_path, detail=str(e))
return
self.remove_list_items("quarantine", [file_path])
with self.lock_virus:
target_key = os.path.normcase(self.norm_path(file_path, must_exist=False) or file_path)
self.virus_results = [
result for result in self.virus_results
if os.path.normcase(self.norm_path(result, must_exist=False) or result) != target_key
]
self.write_log("INFO", "Virus Delete", source=file_path, file_hash=file_hash, operate=True, success=True)
def solve_scan(self, file_paths):
deleted_paths = []
proc_map = {}
@@ -477,23 +518,19 @@ class ScannerMixin:
except Exception:
pass
delete_success = False
for _ in range(5):
try:
os.remove(path)
delete_success = True
break
except Exception:
time.sleep(0.1)
if not delete_success:
file_hash = self.calc_file_hash(path)
try:
os.remove(path)
except Exception as e:
self.lock_file(path, True, quiet=True)
self._queue_virus_delete(path)
self.write_log("INFO", "Virus Delete Deferred", source=path, detail=str(e))
continue
self.remove_list_items("quarantine", [path])
deleted_paths.append(raw_path)
deleted_paths.append(raw_path)
deleted_set.add(path)
self.write_log("INFO", "Virus Delete", source=path, file_hash=self.calc_file_hash(path), operate=True, success=True)
self.write_log("INFO", "Virus Delete", source=path, file_hash=file_hash, operate=True, success=True)
except Exception as e:
self.lock_file(path, True)
+336 -43
View File
@@ -1,4 +1,4 @@
import os, re, io, csv, time, shutil, threading
import os, re, io, csv, json, time, shutil, threading
import pefile, hashlib, winreg, requests, subprocess
import ctypes, ctypes.wintypes
@@ -167,6 +167,186 @@ class RECT(ctypes.Structure):
####################################################################################################
class ToolsMixin:
def _find_windows_tool(self, *names):
windows_dir = os.environ.get("SystemRoot") or os.environ.get("WINDIR") or r"C:\Windows"
search_dirs = [
os.path.join(windows_dir, "Sysnative"),
os.path.join(windows_dir, "System32"),
windows_dir
]
for name in names:
executable_name = name if name.lower().endswith(".exe") else name + ".exe"
for directory in search_dirs:
candidate = os.path.join(directory, executable_name)
if os.path.isfile(candidate):
return candidate
candidate = shutil.which(name)
if candidate:
return candidate
return None
def _run_windows_tool(self, tool_names, arguments, **kwargs):
executable = self._find_windows_tool(*tool_names)
if not executable:
return None
options = {"creationflags": 0x08000000}
options.update(kwargs)
try:
return subprocess.run([executable, *arguments], **options)
except (FileNotFoundError, OSError):
return None
def _run_powershell(self, command, **kwargs):
return self._run_windows_tool(
("powershell.exe", "pwsh.exe"),
["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command", command],
**kwargs
)
def _set_registry_autostart(self, enable):
run_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
value_name = "PYAS_Security"
if enable:
command = f'"{self.file_pyas}" -hide'
return self._reg_write(winreg.HKEY_CURRENT_USER, run_key, value_name, winreg.REG_SZ, command)
try:
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, run_key, 0, winreg.KEY_SET_VALUE) as reg:
try:
winreg.DeleteValue(reg, value_name)
except FileNotFoundError:
pass
return True
except FileNotFoundError:
return True
except Exception:
return False
def _clear_event_log(self, log_name):
result = self._run_windows_tool(
("wevtutil.exe",),
["cl", log_name],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
if result is not None and result.returncode == 0:
return True
try:
wevtapi = ctypes.WinDLL("wevtapi", use_last_error=True)
wevtapi.EvtClearLog.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.LPCWSTR, ctypes.wintypes.LPCWSTR, ctypes.wintypes.DWORD]
wevtapi.EvtClearLog.restype = ctypes.wintypes.BOOL
return bool(wevtapi.EvtClearLog(None, log_name, None, 0))
except Exception:
return False
def _manage_service_native(self, service_name, action):
SC_MANAGER_CONNECT = 0x0001
SERVICE_CHANGE_CONFIG = 0x0002
DELETE = 0x00010000
SERVICE_NO_CHANGE = 0xFFFFFFFF
SERVICE_AUTO_START = 0x00000002
SERVICE_DISABLED = 0x00000004
try:
advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
advapi32.OpenSCManagerW.argtypes = [ctypes.wintypes.LPCWSTR, ctypes.wintypes.LPCWSTR, ctypes.wintypes.DWORD]
advapi32.OpenSCManagerW.restype = ctypes.wintypes.HANDLE
advapi32.OpenServiceW.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.LPCWSTR, ctypes.wintypes.DWORD]
advapi32.OpenServiceW.restype = ctypes.wintypes.HANDLE
advapi32.CloseServiceHandle.argtypes = [ctypes.wintypes.HANDLE]
advapi32.CloseServiceHandle.restype = ctypes.wintypes.BOOL
manager = advapi32.OpenSCManagerW(None, None, SC_MANAGER_CONNECT)
if not manager:
return False
service = None
try:
desired_access = DELETE if action == "delete" else SERVICE_CHANGE_CONFIG
service = advapi32.OpenServiceW(manager, service_name, desired_access)
if not service:
return False
if action == "delete":
advapi32.DeleteService.argtypes = [ctypes.wintypes.HANDLE]
advapi32.DeleteService.restype = ctypes.wintypes.BOOL
return bool(advapi32.DeleteService(service))
start_type = SERVICE_AUTO_START if action == "enable" else SERVICE_DISABLED
advapi32.ChangeServiceConfigW.argtypes = [
ctypes.wintypes.HANDLE,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.LPCWSTR,
ctypes.wintypes.LPCWSTR,
ctypes.POINTER(ctypes.wintypes.DWORD),
ctypes.wintypes.LPCWSTR,
ctypes.wintypes.LPCWSTR,
ctypes.wintypes.LPCWSTR,
ctypes.wintypes.LPCWSTR
]
advapi32.ChangeServiceConfigW.restype = ctypes.wintypes.BOOL
return bool(advapi32.ChangeServiceConfigW(
service,
SERVICE_NO_CHANGE,
start_type,
SERVICE_NO_CHANGE,
None,
None,
None,
None,
None,
None,
None
))
finally:
if service:
advapi32.CloseServiceHandle(service)
advapi32.CloseServiceHandle(manager)
except Exception:
return False
def _manage_scheduled_task(self, task_path, action):
schtasks_action = "/delete" if action == "delete" else "/change"
arguments = [schtasks_action, "/tn", task_path]
if action == "delete":
arguments.append("/f")
else:
arguments.append("/enable" if action == "enable" else "/disable")
result = self._run_windows_tool(
("schtasks.exe",),
arguments,
capture_output=True,
text=True
)
if result is not None and result.returncode == 0:
return True
escaped_path = task_path.replace("'", "''")
operation = {
"delete": "Unregister-ScheduledTask -InputObject $Task -Confirm:$false",
"enable": "Enable-ScheduledTask -InputObject $Task | Out-Null",
"disable": "Disable-ScheduledTask -InputObject $Task | Out-Null"
}.get(action)
if not operation:
return False
command = (
f"$FullName = '{escaped_path}'; "
"$Task = Get-ScheduledTask -ErrorAction SilentlyContinue | "
"Where-Object { ($_.TaskPath + $_.TaskName) -eq $FullName } | Select-Object -First 1; "
f"if ($Task) {{ {operation} }} else {{ exit 1 }}"
)
result = self._run_powershell(command, capture_output=True, text=True)
return bool(result and result.returncode == 0)
def _reg_read(self, root, path, value_name):
try:
with winreg.OpenKey(root, path, 0, winreg.KEY_READ) as reg:
@@ -203,18 +383,81 @@ class ToolsMixin:
####################################################################################################
def manage_autostart(self, enable):
try:
task_name = "PYAS_Security_ATS"
if enable:
cmd = f"$Action = New-ScheduledTaskAction -Execute '{self.file_pyas}' -Argument '-hide'; $Trigger = New-ScheduledTaskTrigger -AtLogOn; $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries; Register-ScheduledTask -TaskName '{task_name}' -Action $Action -Trigger $Trigger -Settings $Settings -RunLevel Highest -Force"
subprocess.run(["powershell", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command", cmd], creationflags=0x08000000)
else:
subprocess.run(["schtasks", "/Delete", "/TN", task_name, "/F"], creationflags=0x08000000)
task_name = "PYAS_Security_ATS"
executable = os.path.normpath(self.file_pyas)
escaped_executable = executable.replace("'", "''")
errors = []
return True
except Exception as e:
self.write_log("WARN", "manage_autostart", detail=str(e), success=False)
return False
if enable:
task_command = f'"{executable}" -hide'
result = self._run_windows_tool(
("schtasks.exe",),
["/Create", "/TN", task_name, "/TR", task_command, "/SC", "ONLOGON", "/RL", "HIGHEST", "/F"],
capture_output=True,
text=True
)
if result and result.returncode == 0:
self._set_registry_autostart(False)
return True
if result:
errors.append((result.stderr or result.stdout or f"schtasks exit {result.returncode}").strip())
command = (
f"$Action = New-ScheduledTaskAction -Execute '{escaped_executable}' -Argument '-hide'; "
"$Trigger = New-ScheduledTaskTrigger -AtLogOn; "
"$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries; "
f"Register-ScheduledTask -TaskName '{task_name}' -Action $Action -Trigger $Trigger -Settings $Settings -RunLevel Highest -Force | Out-Null"
)
result = self._run_powershell(command, capture_output=True, text=True)
if result and result.returncode == 0:
self._set_registry_autostart(False)
return True
if result:
errors.append((result.stderr or result.stdout or f"PowerShell exit {result.returncode}").strip())
if self._set_registry_autostart(True):
self.write_log("INFO", "manage_autostart", detail="Scheduled Task unavailable; using HKCU Run fallback", success=True)
return True
else:
task_removed = False
query_result = self._run_windows_tool(
("schtasks.exe",),
["/Query", "/TN", task_name],
capture_output=True,
text=True
)
result = None
if query_result is not None and query_result.returncode != 0:
task_removed = True
elif query_result is not None:
result = self._run_windows_tool(
("schtasks.exe",),
["/Delete", "/TN", task_name, "/F"],
capture_output=True,
text=True
)
task_removed = bool(result and result.returncode == 0)
if query_result is None or not task_removed:
command = (
f"$Task = Get-ScheduledTask -TaskName '{task_name}' -ErrorAction SilentlyContinue; "
"if ($Task) { $Task | Unregister-ScheduledTask -Confirm:$false }"
)
powershell_result = self._run_powershell(command, capture_output=True, text=True)
if powershell_result is not None:
task_removed = powershell_result.returncode == 0
result = powershell_result
if result and result.returncode != 0:
errors.append((result.stderr or result.stdout or f"task removal exit {result.returncode}").strip())
registry_removed = self._set_registry_autostart(False)
if registry_removed and (task_removed or query_result is None and result is None):
return True
detail = "; ".join(error for error in errors if error) or "No supported autostart method was available"
self.write_log("WARN", "manage_autostart", detail=detail, success=False)
return False
####################################################################################################
@@ -292,10 +535,16 @@ class ToolsMixin:
if lock_func:
lock_func(path, True)
target_list.append({"file": path, "time": time.time()})
new_item = {"file": path, "time": time.time()}
is_directory = None
if list_key == "white_list":
is_directory = os.path.isdir(path)
new_item["is_dir"] = is_directory
target_list.append(new_item)
acted_items.append(path)
if list_key == "white_list":
self.sync_driver_whitelist(path, True)
self.sync_driver_whitelist(path, True, is_directory)
elif action == "remove":
norm_paths_case = {os.path.normcase(p) for p in norm_paths}
@@ -311,7 +560,8 @@ class ToolsMixin:
acted_items.append(val)
if list_key == "white_list":
self.sync_driver_whitelist(val, False)
is_directory = item.get("is_dir") if isinstance(item, dict) else None
self.sync_driver_whitelist(val, False, is_directory)
continue
new_list.append(item)
@@ -356,7 +606,8 @@ class ToolsMixin:
if np and os.path.normcase(np) in norm_paths_to_remove:
removed_items.append(val)
if list_key == "white_list":
self.sync_driver_whitelist(val, False)
is_directory = item.get("is_dir") if isinstance(item, dict) else None
self.sync_driver_whitelist(val, False, is_directory)
continue
new_list.append(item)
@@ -888,7 +1139,7 @@ class ToolsMixin:
log_path = os.path.join(self.path_system, "System32", "winevt", "Logs", f"{log_type}.evtx")
size = os.path.getsize(log_path) if os.path.exists(log_path) else 0
if subprocess.run(["wevtutil", "cl", log_type], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, creationflags=0x08000000).returncode == 0:
if self._clear_event_log(log_type):
total_deleted += size
except Exception:
@@ -1035,20 +1286,57 @@ class ToolsMixin:
def get_tasks():
res = []
try:
proc = subprocess.run(["schtasks", "/query", "/fo", "csv", "/v"], capture_output=True, text=True, creationflags=0x08000000)
reader = csv.reader(io.StringIO(proc.stdout))
next(reader, None)
proc = self._run_windows_tool(
("schtasks.exe",),
["/query", "/fo", "csv", "/v"],
capture_output=True,
text=True
)
if proc is not None and proc.returncode == 0:
reader = csv.reader(io.StringIO(proc.stdout))
next(reader, None)
for row in reader:
if len(row) > 8 and row[1].strip() and row[8].strip() and row[8] != "N/A":
name = row[1].split('\\')[-1]
path = row[8]
status = row[3]
for row in reader:
if len(row) > 8 and row[1].strip() and row[8].strip() and row[8] != "N/A":
name = row[1].split('\\')[-1]
path = row[8]
status = row[3]
if path and "windows" not in path.lower():
fp = self.extract_paths_from_cmdline(path)
fpp = fp[0] if fp else path
res.append({"id": f"tsk|{row[1]}", "type": "type_tsk", "name": name, "status": "disabled" if status == "Disabled" else "enabled", "path": fpp})
if path and "windows" not in path.lower():
fp = self.extract_paths_from_cmdline(path)
fpp = fp[0] if fp else path
res.append({"id": f"tsk|{row[1]}", "type": "type_tsk", "name": name, "status": "disabled" if status.lower() == "disabled" else "enabled", "path": fpp})
return res
command = (
"[Console]::OutputEncoding = [Text.UTF8Encoding]::new(); "
"Get-ScheduledTask -ErrorAction SilentlyContinue | ForEach-Object { "
"$Action = @($_.Actions)[0]; "
"[pscustomobject]@{Name=$_.TaskName; FullName=($_.TaskPath + $_.TaskName); "
"State=[string]$_.State; Execute=$Action.Execute; Arguments=$Action.Arguments} "
"} | ConvertTo-Json -Compress"
)
proc = self._run_powershell(command, capture_output=True, text=True, encoding="utf-8", errors="replace")
if not proc or proc.returncode != 0 or not proc.stdout.strip():
return res
task_data = json.loads(proc.stdout)
if isinstance(task_data, dict):
task_data = [task_data]
for task in task_data:
name = str(task.get("Name") or "").strip()
full_name = str(task.get("FullName") or name).strip()
execute = str(task.get("Execute") or "").strip()
arguments = str(task.get("Arguments") or "").strip()
command_line = " ".join(part for part in (execute, arguments) if part)
if not name or not command_line or "windows" in command_line.lower():
continue
paths = self.extract_paths_from_cmdline(command_line)
path = paths[0] if paths else execute or command_line
status = "disabled" if str(task.get("State") or "").lower() == "disabled" else "enabled"
res.append({"id": f"tsk|{full_name}", "type": "type_tsk", "name": name, "status": status, "path": path})
except Exception:
pass
@@ -1068,44 +1356,49 @@ class ToolsMixin:
def manage_startup(self, items, action):
def process_item(item_id):
try:
parts = item_id.split('|')
parts = item_id.split('|', 3)
stype = parts[0]
if stype == "reg":
root, old_path, name = int(parts[1]), parts[2], parts[3]
if action == "delete":
self._reg_delete(root, old_path, name)
return self._reg_delete(root, old_path, name)
else:
new_path = old_path.replace("_Disabled", "") if action == "enable" else (old_path if "_Disabled" in old_path else old_path + "_Disabled")
if old_path != new_path:
val = self._reg_read(root, old_path, name)
if val:
self._reg_write(root, new_path, name, winreg.REG_SZ, val)
self._reg_delete(root, old_path, name)
return self._reg_write(root, new_path, name, winreg.REG_SZ, val) and self._reg_delete(root, old_path, name)
return True
elif stype == "srv":
name = parts[1]
if action == "delete":
subprocess.run(["sc", "delete", name], capture_output=True, creationflags=0x08000000)
result = self._run_windows_tool(("sc.exe",), ["delete", name], capture_output=True)
else:
mode = "auto" if action == "enable" else "disabled"
subprocess.run(["sc", "config", name, f"start=", mode], capture_output=True, creationflags=0x08000000)
result = self._run_windows_tool(("sc.exe",), ["config", name, "start=", mode], capture_output=True)
if result is not None and result.returncode == 0:
return True
return self._manage_service_native(name, action)
elif stype == "tsk":
name = parts[1]
if action == "delete":
subprocess.run(["schtasks", "/delete", "/tn", name, "/f"], capture_output=True, creationflags=0x08000000)
name = item_id.partition('|')[2]
return self._manage_scheduled_task(name, action)
else:
cmd = "/enable" if action == "enable" else "/disable"
subprocess.run(["schtasks", "/change", "/tn", name, cmd], capture_output=True, creationflags=0x08000000)
return False
except Exception as e:
self.write_log("WARN", "manage_startup", detail=str(e), success=False)
return False
with ThreadPoolExecutor(max_workers=5) as executor:
list(executor.map(process_item, items))
results = list(executor.map(process_item, items))
return True
success = all(results) if results else True
if not success:
self.write_log("WARN", "manage_startup", detail="One or more startup items could not be updated", success=False)
return success
+1 -1
View File
@@ -2,7 +2,7 @@ import pyinstaller_versionfile
pyinstaller_versionfile.create_versionfile(
output_file="versionfile.txt",
version='3.6.3.0',
version='3.6.8.0',
company_name="PYAS Security",
file_description="PYAS Security Antivirus",
internal_name="PYAS",
+25 -183
View File
@@ -61,18 +61,24 @@
"Category": "Process",
"InitiatorExclude": [
"*\\PYAS.exe",
"*\\PYAS_Setup.exe",
"*\\unins000.exe",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\Temp\\*\\PYAS_Setup.tmp",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\Temp\\*\\_unins.tmp",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\sogoupdf\\pdfpopcl.exe",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\WeGame\\*\\tiny_dl\\TinyDL.exe",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\Microsoft\\OneDrive\\OneDrive.exe",
"\\Device\\HarddiskVolume*\\Windows\\explorer.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\csrss.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\lsass.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\services.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\svchost.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\msiexec.exe",
"\\Device\\HarddiskVolume*\\Windows\\SystemApps\\*\\SearchHost.exe",
"\\Device\\HarddiskVolume*\\Program Files\\*",
"\\Device\\HarddiskVolume*\\Program Files (x86)\\*",
"*\\games\\Arknights Game\\Arknights.exe",
"*\\games\\EndField Game\\EndField.exe",
"*\\cm\\FeverGames\\*\\FeverGamesInstaller.exe",
"*\\Davinci\\Resolve.exe",
],
"Target": [
"*\\PYAS.exe",
@@ -195,152 +201,6 @@
],
"Priority": 160,
},
{
"Name": "Memory_Protect_Critical_Process_CreateRemoteThread",
"Code": 1007,
"Kill": false,
"Category": "Memory",
"InitiatorExclude": [
"\\Device\\HarddiskVolume*\\Windows\\*",
"\\Device\\HarddiskVolume*\\Program Files\\*",
"\\Device\\HarddiskVolume*\\Program Files (x86)\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\*",
"*\\Huorong\\Sysdiag\\bin\\HipsDaemon.exe",
"*\\360Safe.exe",
"*\\PYAS.exe",
],
"Target": [
"\\Device\\HarddiskVolume*\\Windows\\System32\\lsass.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\winlogon.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\services.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\csrss.exe",
],
"Operations": [
"WriteMemory",
"VmOperation",
"CreateThread",
],
"OperationMatch": "All",
"MinimumRiskScore": 90,
"HandleTypes": [
"Create",
"Duplicate",
],
"ObjectTypes": [
"Process",
],
"Priority": 175,
},
{
"Name": "Memory_Protect_Critical_Process_ThreadHijack",
"Code": 1008,
"Kill": false,
"Category": "Memory",
"InitiatorExclude": [
"\\Device\\HarddiskVolume*\\Windows\\*",
"\\Device\\HarddiskVolume*\\Program Files\\*",
"\\Device\\HarddiskVolume*\\Program Files (x86)\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\*",
"*\\Huorong\\Sysdiag\\bin\\HipsDaemon.exe",
"*\\360Safe.exe",
"*\\PYAS.exe",
],
"Target": [
"\\Device\\HarddiskVolume*\\Windows\\System32\\lsass.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\winlogon.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\services.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\csrss.exe",
],
"Operations": [
"WriteMemory",
"VmOperation",
"SetThreadContext",
],
"OperationMatch": "All",
"MinimumRiskScore": 90,
"HandleTypes": [
"Create",
"Duplicate",
],
"ObjectTypes": [
"Process",
],
"Priority": 175,
},
{
"Name": "Memory_Protect_Service_Process_CreateRemoteThread",
"Code": 1009,
"Kill": false,
"Category": "Memory",
"InitiatorExclude": [
"\\Device\\HarddiskVolume*\\Windows\\*",
"\\Device\\HarddiskVolume*\\Program Files\\*",
"\\Device\\HarddiskVolume*\\Program Files (x86)\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\*",
"*\\Huorong\\Sysdiag\\bin\\HipsDaemon.exe",
"*\\360Safe.exe",
"*\\PYAS.exe",
],
"Target": [
"\\Device\\HarddiskVolume*\\Windows\\System32\\svchost.exe",
"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\svchost.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\spoolsv.exe",
],
"Operations": [
"WriteMemory",
"VmOperation",
"CreateThread",
],
"OperationMatch": "All",
"MinimumRiskScore": 90,
"HandleTypes": [
"Create",
"Duplicate",
],
"ObjectTypes": [
"Process",
],
"Priority": 170,
},
{
"Name": "Memory_Protect_Service_Process_ThreadHijack",
"Code": 1010,
"Kill": false,
"Category": "Memory",
"InitiatorExclude": [
"\\Device\\HarddiskVolume*\\Windows\\*",
"\\Device\\HarddiskVolume*\\Program Files\\*",
"\\Device\\HarddiskVolume*\\Program Files (x86)\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\*",
"*\\Huorong\\Sysdiag\\bin\\HipsDaemon.exe",
"*\\360Safe.exe",
"*\\PYAS.exe",
],
"Target": [
"\\Device\\HarddiskVolume*\\Windows\\System32\\svchost.exe",
"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\svchost.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\spoolsv.exe",
],
"Operations": [
"WriteMemory",
"VmOperation",
"SetThreadContext",
],
"OperationMatch": "All",
"MinimumRiskScore": 90,
"HandleTypes": [
"Create",
"Duplicate",
],
"ObjectTypes": [
"Process",
],
"Priority": 170,
},
{
"Name": "Self_Antivirus_Protect_File",
"Code": 2001,
@@ -348,8 +208,6 @@
"Category": "File",
"InitiatorExclude": [
"*\\PYAS.exe",
"*\\PYAS_Setup.exe",
"*\\unins000.exe",
"*\\notepad*.exe",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\Temp\\*\\PYAS_Setup.tmp",
"\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Local\\Temp\\*\\_unins.tmp",
@@ -388,6 +246,7 @@
"InitiatorExclude": [
"*\\PYAS.exe",
"*\\Huorong\\Sysdiag\\bin\\sysclean.exe",
"\\Device\\HarddiskVolume*\\Windows\\explorer.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\SearchIndexer.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\lsass.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\svchost.exe",
@@ -395,6 +254,7 @@
"\\Device\\HarddiskVolume*\\Windows\\System32\\taskhostw.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\TrustedInstaller.exe",
"\\Device\\HarddiskVolume*\\Windows\\WinSxS\\*\\TiWorker.exe",
"\\Device\\HarddiskVolume*\\Windows\\UUS\\amd64\\wuaucltcore.exe",
"\\Device\\HarddiskVolume*\\$WinREAgent\\Scratch\\*\\DismHost.exe",
],
"Target": [
@@ -547,6 +407,8 @@
"*\\ventoy\\Boot\\*",
"*\\AdminRegionConfig.*",
"*\\nt_qq\\nt_*\\*",
"*\\nt_qq\\global\\nt_*\\*",
"\\Device\\HarddiskVolume*\\Users\\*\\Documents\\Tencent Files\\*",
],
"Extensions": [
".zip",
@@ -585,7 +447,7 @@
"Delete",
"Rename",
],
"Threshold": 5,
"Threshold": 10,
"TimeWindow": 3000,
},
{
@@ -597,11 +459,13 @@
"*\\PYAS.exe",
"*\\rufus-*.exe",
"*\\DiskInfo*.exe",
"\\Device\\HarddiskVolume*\\Program Files\\*\\launcher\\ca_launcher.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\diskpart.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\diskmgmt.msc",
"\\Device\\HarddiskVolume*\\Windows\\System32\\taskhostw.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\vds.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\format.com",
"\\Device\\HarddiskVolume*\\Windows\\System32\\WinSAT.exe",
],
"Operations": [
"Ioctl",
@@ -634,8 +498,6 @@
"*\\DefaultPassword",
"*\\AltDefaultUserName",
"*\\AltDefaultPassword",
"*\\LegalNoticeCaption",
"*\\LegalNoticeText",
"*\\AutoReboot",
"*\\DisableAutomaticRestartOnFailure",
"*\\SystemBiosVersion",
@@ -723,7 +585,6 @@
"*\\SystemStartOptions",
"*\\Userinit",
"*\\UIHost",
"*\\Debugger",
"*\\NoControlPanel",
"*\\NoDrives",
"*\\NoFileMenu",
@@ -810,42 +671,20 @@
"Priority": 170,
},
{
"Name": "Registry_Protect_Pending_File_Rename",
"Name": "Registry_Protect_OOBE_Reset",
"Code": 3006,
"Kill": false,
"Category": "Registry",
"InitiatorExclude": [
"\\Device\\HarddiskVolume*\\Windows\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender\\*",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\*",
"*\\Sources\\SetupHost.exe",
"*\\Work\\*\\DismHost.exe",
"*\\Huorong\\Sysdiag\\bin\\HipsDaemon.exe",
"*\\360Safe.exe",
"*\\PYAS.exe",
],
"Target": [
"\\REGISTRY\\MACHINE\\SYSTEM\\*ControlSet*\\Control\\Session Manager\\PendingFileRenameOperations",
"\\REGISTRY\\MACHINE\\SYSTEM\\*ControlSet*\\Control\\Session Manager\\PendingFileRenameOperations2",
],
"Operations": [
"Write",
"Delete",
"Create",
],
"Priority": 140,
},
{
"Name": "Registry_Protect_OOBE_Reset",
"Code": 3007,
"Kill": true,
"Category": "Registry",
"InitiatorExclude": [
"*\\Sources\\SetupHost.exe",
"*\\Work\\*\\DismHost.exe",
"*\\Windows\\UUS\\amd64\\MoUsoCoreWorker.exe",
"*\\Windows\\UUS\\Packages\\Preview\\amd64\\MoUsoCoreWorker.exe",
"*\\Windows\\System32\\MoUsoCoreWorker.exe",
"*\\Windows\\System32\\Sysprep\\sysprep.exe",
"*\\Windows\\System32\\oobe\\*",
"*\\Windows\\UUS\\amd64\\MoUsoCoreWorker.exe",
"*\\Windows\\System32\\svchost.exe",
"*\\Windows\\explorer.exe",
"*\\PYAS.exe",
],
"Target": [
@@ -862,6 +701,9 @@
"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OOBE\\*",
"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE\\*",
],
"TargetExclude": [
"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE\\TelemetryCorrelation",
],
"Operations": [
"Write",
"Delete",
@@ -870,4 +712,4 @@
"Priority": 175,
},
]
}
}