Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58795b9349 | ||
|
|
1ef769842b | ||
|
|
6051570414 | ||
|
|
da5d5d0dc7 | ||
|
|
782aa22d4d | ||
|
|
0084867f38 | ||
|
|
5a27858f86 | ||
|
|
7905d8375f | ||
|
|
ba8aa63d75 | ||
|
|
ac82778e26 | ||
|
|
55d2661e38 |
No files matched your search
@@ -151,12 +151,12 @@ class MainWindow_Controller(QMainWindow):
|
||||
"hindi_switch", "arabic_switch", "russian_switch", "slovenian_switch",
|
||||
]
|
||||
self.pyas_default = {
|
||||
"version": "3.4.2",
|
||||
"version": "3.4.4",
|
||||
"api_host": "https://pyas-security.com/",
|
||||
"api_key": "fBRZxYS1UxykM-qzNOlKOEl63WILzlvgNMn6QfsG6FXCAAIktCrOPTAfY5_hEyuZ",
|
||||
"suffix": [".exe", ".dll", ".sys", ".ocx", ".scr", ".efi", ".acm", ".ax", ".cpl", ".drv", ".com", ".mui", ".pyd"],
|
||||
"block": [2001, 3001, 4001, 5001, 6001],
|
||||
"size": 256 * 1024 * 1024,
|
||||
"block": [3001, 5001, 6001],
|
||||
"size": 100 * 1024 * 1024,
|
||||
"language": "english_switch",
|
||||
"theme": "white_switch",
|
||||
"process_switch": True,
|
||||
@@ -632,7 +632,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
if widget in (scan_win, method_win):
|
||||
if getattr(self, "scan_finished", False):
|
||||
self.widgets["solve_button"].setVisible(len(self.virus_results) > 0)
|
||||
self.widgets["solve_button"].setVisible(False)
|
||||
self.widgets["stop_button"].hide()
|
||||
self.widgets["method_button"].show()
|
||||
|
||||
@@ -861,7 +861,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
@Slot()
|
||||
def slot_scan_reset(self):
|
||||
count = len(self.virus_results)
|
||||
self.widgets["solve_button"].setVisible(count > 0)
|
||||
self.widgets["solve_button"].setVisible(False)
|
||||
self.widgets["virus_list"].clear()
|
||||
self.widgets["method_window"].hide()
|
||||
self.widgets["stop_button"].setVisible(self.scan_running)
|
||||
@@ -1035,7 +1035,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
####################################################################################################
|
||||
|
||||
def init_cloud_worker(self):
|
||||
for _ in range(1):
|
||||
for _ in range(4):
|
||||
t = threading.Thread(target=self.cloud_worker, daemon=True)
|
||||
t.start()
|
||||
|
||||
@@ -1068,7 +1068,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
was_locked = True
|
||||
|
||||
size = os.path.getsize(file_path)
|
||||
if size > self.pyas_config.get("size", 256 * 1024 * 1024):
|
||||
if size > self.pyas_config.get("size", 100 * 1024 * 1024):
|
||||
if was_locked:
|
||||
self.lock_file(file_path, True)
|
||||
return False
|
||||
@@ -1101,6 +1101,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def solve_button(self):
|
||||
if self.send_message("您確定要刪除檔案嗎?", "quest"):
|
||||
self.widgets["solve_button"].setVisible(False)
|
||||
deleted = 0
|
||||
virus_list = self.widgets["virus_list"]
|
||||
start_ts = time.time()
|
||||
@@ -1208,9 +1209,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
except Exception as e:
|
||||
self.send_message(f"show_scan_menu | {e}", "warn", False)
|
||||
|
||||
count = len(self.virus_results)
|
||||
self.widgets["solve_button"].setVisible(count > 0)
|
||||
|
||||
####################################################################################################
|
||||
|
||||
def list_process(self):
|
||||
|
||||
+97
-79
@@ -800,7 +800,26 @@ class pe_scanner:
|
||||
|
||||
class cloud_scanner:
|
||||
def __init__(self):
|
||||
pass
|
||||
self.session = None
|
||||
self.api_host = None
|
||||
self.api_key = None
|
||||
self.timeout = 30
|
||||
|
||||
def _init_session(self, api_host, api_key):
|
||||
if self.session is None or self.api_host != api_host or self.api_key != api_key:
|
||||
self.api_host = api_host.rstrip('/')
|
||||
self.api_key = api_key
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({"X-API-Key": api_key, "User-Agent": "PYAS-Engine/1.2"})
|
||||
|
||||
def _request(self, method, endpoint, **kwargs):
|
||||
try:
|
||||
r = self.session.request(method, f"{self.api_host}{endpoint}", timeout=self.timeout, **kwargs)
|
||||
if r.status_code == 200:
|
||||
return r
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def calc_hash(self, file_path, block_size=65536):
|
||||
try:
|
||||
@@ -814,107 +833,106 @@ class cloud_scanner:
|
||||
|
||||
####################################################################################################
|
||||
|
||||
def upload_file(self, file_path, api_host, api_key):
|
||||
def rescan(self, sha256, api_host, api_key):
|
||||
self._init_session(api_host, api_key)
|
||||
r = self._request("POST", f"/api/rescan/{sha256}")
|
||||
return r is not None and r.json().get('status') == 'success'
|
||||
|
||||
def upload_file(self, file_path, api_host, api_key, chunk_size=5242880):
|
||||
try:
|
||||
self._init_session(api_host, api_key)
|
||||
sha256 = self.calc_hash(file_path)
|
||||
if not sha256:
|
||||
return False, None
|
||||
|
||||
base = api_host.rstrip('/')
|
||||
base_headers = {"X-API-Key": api_key, "User-Agent": "PYAS-Client/1.0"}
|
||||
status_req = self._request("GET", f"/api/processing_status/{sha256}")
|
||||
if status_req and status_req.json().get('status') != 'missing':
|
||||
self.rescan(sha256, api_host, api_key)
|
||||
return True, sha256
|
||||
|
||||
def _req(m, ep, files=None, req_timeout=5, **k):
|
||||
try:
|
||||
return requests.request(m, f"{base}{ep}", headers=base_headers, files=files, timeout=req_timeout, **k)
|
||||
except:
|
||||
return None
|
||||
file_size = os.path.getsize(file_path)
|
||||
if file_size > 104857600:
|
||||
return False, sha256
|
||||
|
||||
r = _req("GET", f"/api/processing_status/{sha256}", req_timeout=15)
|
||||
|
||||
status = 'missing'
|
||||
if r and r.status_code == 200:
|
||||
try:
|
||||
status = r.json().get('status', 'missing')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if status in ['failed', 'error']:
|
||||
status = 'missing'
|
||||
|
||||
if status == 'missing':
|
||||
if file_size > chunk_size:
|
||||
total_chunks = (file_size + chunk_size - 1) // chunk_size
|
||||
upload_id = os.urandom(16).hex()
|
||||
with open(file_path, 'rb') as f:
|
||||
r = _req("POST", "/api/upload", files={'file': f}, req_timeout=30)
|
||||
if not r or r.status_code != 200:
|
||||
return False, sha256
|
||||
for i in range(total_chunks):
|
||||
chunk_data = f.read(chunk_size)
|
||||
headers = {
|
||||
"X-Chunk-Index": str(i),
|
||||
"X-Total-Chunks": str(total_chunks),
|
||||
"X-Upload-ID": upload_id
|
||||
}
|
||||
|
||||
chunk_success = False
|
||||
for _ in range(3):
|
||||
r = self._request("POST", "/api/upload", files={'file': (os.path.basename(file_path), chunk_data)}, headers=headers)
|
||||
if r:
|
||||
chunk_success = True
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
if not chunk_success:
|
||||
return False, sha256
|
||||
return True, sha256
|
||||
|
||||
return True, sha256
|
||||
with open(file_path, 'rb') as f:
|
||||
file_data = f.read()
|
||||
|
||||
for _ in range(3):
|
||||
r = self._request("POST", "/api/upload", files={'file': (os.path.basename(file_path), file_data)})
|
||||
if r:
|
||||
return True, sha256
|
||||
time.sleep(1)
|
||||
|
||||
return False, sha256
|
||||
except Exception:
|
||||
return False, None
|
||||
|
||||
####################################################################################################
|
||||
|
||||
def get_result(self, sha256, api_host, api_key):
|
||||
def get_result(self, sha256, api_host, api_key, max_retries=6, interval=10):
|
||||
try:
|
||||
if not sha256:
|
||||
return False
|
||||
self._init_session(api_host, api_key)
|
||||
|
||||
base = api_host.rstrip('/')
|
||||
headers = {"X-API-Key": api_key, "User-Agent": "PYAS-Client/1.0"}
|
||||
|
||||
def _req(m, ep, req_timeout, **k):
|
||||
try:
|
||||
return requests.request(m, f"{base}{ep}", headers=headers, timeout=req_timeout, **k)
|
||||
except requests.exceptions.Timeout:
|
||||
return "timeout"
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
timeout_count = 0
|
||||
for _ in range(30):
|
||||
r = _req("GET", f"/api/processing_status/{sha256}", req_timeout=15)
|
||||
|
||||
if r == "timeout" or r is None:
|
||||
timeout_count += 1
|
||||
if timeout_count >= 3:
|
||||
is_done = False
|
||||
for _ in range(max_retries):
|
||||
r = self._request("GET", f"/api/processing_status/{sha256}")
|
||||
if r:
|
||||
st = r.json().get('status', 'error')
|
||||
if st == 'done':
|
||||
is_done = True
|
||||
break
|
||||
if st in ['error', 'failed']:
|
||||
return False
|
||||
time.sleep(1)
|
||||
continue
|
||||
time.sleep(interval)
|
||||
|
||||
st = 'error'
|
||||
if r.status_code == 200:
|
||||
try:
|
||||
st = r.json().get('status', 'error')
|
||||
except Exception:
|
||||
pass
|
||||
if not is_done:
|
||||
return False
|
||||
|
||||
if st == 'done':
|
||||
break
|
||||
if st in ['error', 'failed']:
|
||||
return False
|
||||
time.sleep(1)
|
||||
r = self._request("GET", f"/api/report/{sha256}")
|
||||
if r:
|
||||
data = r.json().get('data', {})
|
||||
metadata = data.get('metadata', {})
|
||||
label = metadata.get('label', 'Unsupport')
|
||||
score = metadata.get('score', 0)
|
||||
sims = data.get('similar', [])
|
||||
|
||||
r = _req("GET", f"/api/report/{sha256}", req_timeout=30)
|
||||
if r and r != "timeout" and r.status_code == 200:
|
||||
try:
|
||||
data = r.json().get('data', {})
|
||||
res = data.get('detection', {}).get('results', {}).get('PYAS', {})
|
||||
label = res.get('label', 'Unsupport')
|
||||
score = res.get('score', 100)
|
||||
sims = data.get('similar', [])
|
||||
is_malicious = 'General' in label
|
||||
sim_malicious_count = 0
|
||||
valid_sim_count = 0
|
||||
for s in sims:
|
||||
if s.get('similarity', 0) > 80:
|
||||
valid_sim_count += 1
|
||||
if "General" in s.get('label', ''):
|
||||
sim_malicious_count += 1
|
||||
|
||||
is_malicious = 'General' in label
|
||||
sim_malicious_count = 0
|
||||
valid_sim_count = 0
|
||||
for s in sims:
|
||||
if s.get('similarity', 0) > 80:
|
||||
valid_sim_count += 1
|
||||
if "General" in s.get('label', ''):
|
||||
sim_malicious_count += 1
|
||||
|
||||
if is_malicious and (valid_sim_count == 0 or sim_malicious_count == valid_sim_count):
|
||||
return f"General:WinPE/Unknown.{score}!cl"
|
||||
except Exception:
|
||||
pass
|
||||
if is_malicious and (valid_sim_count == 0 or sim_malicious_count == valid_sim_count):
|
||||
return f"General:WinPE/Unknown.{score}!cl"
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
+1
-1
@@ -2,7 +2,7 @@ import pyinstaller_versionfile
|
||||
|
||||
pyinstaller_versionfile.create_versionfile(
|
||||
output_file="versionfile.txt",
|
||||
version='3.4.2',
|
||||
version='3.4.4',
|
||||
company_name="PYAS Security",
|
||||
file_description="Python Antivirus Software",
|
||||
internal_name="PYAS",
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
"\\REGISTRY\\MACHINE\\BCD00000000",
|
||||
"\\REGISTRY\\MACHINE\\BCD00000000\\*",
|
||||
"*\\Image File Execution Options\\*",
|
||||
|
||||
"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\NetWire\\*",
|
||||
"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\Remcos*\\*",
|
||||
"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\DC3_FEXEC\\*",
|
||||
|
||||
|
||||
"*\\Classes\\.exe",
|
||||
"*\\Classes\\.bat",
|
||||
"*\\Classes\\.cmd",
|
||||
@@ -19,7 +15,6 @@
|
||||
|
||||
"*\\mouclass",
|
||||
"*\\kbdclass",
|
||||
"*\\DefaultIcon",
|
||||
"*\\DisableAntiSpyware",
|
||||
"*\\DisableWindowsUpdateAccess",
|
||||
"*\\EnableLUA",
|
||||
@@ -79,7 +74,6 @@
|
||||
"*\\NoInteractiveServices",
|
||||
"*\\ShutdownWithoutLogon",
|
||||
"*\\AutoAdminLogon",
|
||||
"*\\ImagePath",
|
||||
"*\\BootExecute",
|
||||
"*\\SubSystems",
|
||||
"*\\FirmwareBootDevice",
|
||||
@@ -89,7 +83,6 @@
|
||||
"*\\DisableAutomaticRestartOnFailure",
|
||||
"*\\SystemBiosVersion",
|
||||
"*\\NoTheme",
|
||||
"*\\PendingFileRenameOperations",
|
||||
"*\\SystemSetupInProgress",
|
||||
"*\\CmdLine",
|
||||
"*\\SetupType",
|
||||
@@ -108,17 +101,21 @@
|
||||
"Rule_Registry_TrustedList": [
|
||||
],
|
||||
"Rule_Process_TrustedPaths": [
|
||||
"*\\Windows\\*",
|
||||
"*\\Windows Defender\\*",
|
||||
"*\\Windows Defender Advanced Threat Protection\\*",
|
||||
"*\\Program Files\\*",
|
||||
"*\\Program Files (x86)\\*",
|
||||
"\\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\\*",
|
||||
|
||||
"*\\Google\\Chrome\\Application\\chrome.exe",
|
||||
"*\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||
"*\\Mozilla Firefox\\firefox.exe",
|
||||
|
||||
"*\\Steam\\steam.exe",
|
||||
"*\\steam\\*\\steam.exe",
|
||||
"*\\Battle.net\\*\\Battle.net.exe",
|
||||
"*\\Epic Games\\Launcher\\Portal\\Binaries\\*\\EpicGamesLauncher.exe"
|
||||
"*\\Epic Games\\Launcher\\Portal\\Binaries\\*\\EpicGamesLauncher.exe",
|
||||
],
|
||||
"Rule_Process_ExploitableBlacklist": [
|
||||
"*\\cmd.exe",
|
||||
@@ -159,25 +156,18 @@
|
||||
"*\\PYAS.exe",
|
||||
"*\\PYAS_Driver.sys",
|
||||
"*\\ProgramData\\PYAS\\*.json",
|
||||
"*\\Plugins\\Rules\\Rules_Driver_P1.json",
|
||||
"*\\Engine\\Pattern\\*.onnx",
|
||||
"*\\Engine\\Properties\\*.onnx",
|
||||
|
||||
"*\\bootmgr",
|
||||
"*\\boot.ini",
|
||||
"*\\BOOTNXT",
|
||||
"*\\BCD",
|
||||
"*\\EFI\\*",
|
||||
"*\\Boot\\*",
|
||||
"*\\Recovery\\*",
|
||||
|
||||
"*\\Windows\\*.exe",
|
||||
"*\\Windows\\*.dll",
|
||||
"*\\Windows\\*.sys",
|
||||
"*\\Windows\\System32\\*.exe",
|
||||
"*\\Windows\\System32\\*.dll",
|
||||
"*\\Windows\\System32\\*.sys",
|
||||
"*\\Windows\\SysWOW64\\*.exe",
|
||||
"*\\Windows\\SysWOW64\\*.dll",
|
||||
"*\\Windows\\SysWOW64\\*.sys",
|
||||
"*\\System Volume Information\\*",
|
||||
"\\Device\\HarddiskVolume*\\bootmgr",
|
||||
"\\Device\\HarddiskVolume*\\boot.ini",
|
||||
"\\Device\\HarddiskVolume*\\BOOTNXT",
|
||||
"\\Device\\HarddiskVolume*\\EFI\\*",
|
||||
"\\Device\\HarddiskVolume*\\Boot\\*",
|
||||
"\\Device\\HarddiskVolume*\\Recovery\\*",
|
||||
"\\Device\\HarddiskVolume*\\System Volume Information\\*",
|
||||
"\\Device\\HarddiskVolume*\\Windows\\System32\\config\\*",
|
||||
|
||||
"*\\CON",
|
||||
"*\\CON\\*",
|
||||
@@ -191,20 +181,19 @@
|
||||
"*\\COM?\\*",
|
||||
"*\\LPT?",
|
||||
"*\\LPT?\\*",
|
||||
"*\\LPT?",
|
||||
"*\\LPT?\\*",
|
||||
"*\\OSDATA",
|
||||
"*\\OSDATA\\*",
|
||||
|
||||
"*\\*<*",
|
||||
"*\\*>*",
|
||||
"*\\*:*",
|
||||
],
|
||||
"Rule_File_ExceptionPaths": [
|
||||
"*\\AppData\\*"
|
||||
"*\\Users\\*\\steam\\*",
|
||||
"*\\AppData\\*",
|
||||
"*\\Temp\\*",
|
||||
"*\\Local\\Temp\\*",
|
||||
"*\\ventoy\\Boot\\*",
|
||||
],
|
||||
"Rule_File_RansomwareExtensions": [
|
||||
".exe", ".dll", ".sys", ".com", ".scr",
|
||||
".zip", ".7z", ".rar", ".tar", ".gz",
|
||||
".js", ".bat", ".cmd", ".ps1", ".vbs",
|
||||
".ppt", ".pptx", ".wps", ".txt", ".rtf",
|
||||
@@ -214,6 +203,6 @@
|
||||
".mp4", ".avi", ".mov", ".wmv", ".mkv",
|
||||
".aux", ".cur", ".mui", ".ttf", ".efi",
|
||||
".cpp", ".h", ".c", ".hpp", ".cs", ".java", ".py", ".go", ".rs",
|
||||
".php", ".html", ".css", ".xml", ".sql", ".db"
|
||||
".php", ".html", ".css", ".xml", ".sql", ".db",
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user