Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d872604855 | ||
|
|
2b6fb933a4 | ||
|
|
1da892e863 | ||
|
|
19bfedd1a3 | ||
|
|
cb87392d9d | ||
|
|
7cd5bc9ec3 | ||
|
|
edcc1a30ab | ||
|
|
6f93f6ab06 | ||
|
|
9de1f44288 | ||
|
|
3d360b0881 | ||
|
|
cf1c415846 | ||
|
|
90133e2444 | ||
|
|
81246046b8 | ||
|
|
20e037ab9e | ||
|
|
bc27036ba7 | ||
|
|
1cd470b90b | ||
|
|
64471e34bc | ||
|
|
f4c5d3de09 | ||
|
|
0dc59405e3 | ||
|
|
7c775bdc9b | ||
|
|
61400ff4d4 | ||
|
|
e119e34ebe | ||
|
|
6f059747bf | ||
|
|
24d72641fa | ||
|
|
b91fca3aa6 | ||
|
|
a6f1947837 | ||
|
|
6919131cef | ||
|
|
9186d801fc | ||
|
|
76e2f200bd | ||
|
|
1400bbd9ce | ||
|
|
fd37628ac2 | ||
|
|
4396d5afc4 | ||
|
|
f5faf80883 | ||
|
|
ba32da97c8 | ||
|
|
ec2de73d3a | ||
|
|
d1035268f6 | ||
|
|
8968f30bf9 | ||
|
|
84c2c29600 | ||
|
|
b2a59f261c | ||
|
|
363a330f8e | ||
|
|
1d2aa059ee | ||
|
|
f2bfa908a1 |
No files matched your search
@@ -20,7 +20,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.pyas = sys.argv[0].replace("\\", "/")
|
||||
self.dir = os.path.dirname(self.pyas)
|
||||
self.pyae_version = "SimHash Engine"
|
||||
self.pyas_version = "3.0.5"
|
||||
self.pyas_version = "3.0.8"
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
self.init_show_pyas()
|
||||
@@ -624,29 +624,11 @@ class MainWindow_Controller(QMainWindow):
|
||||
except:
|
||||
pass
|
||||
|
||||
def update_database(self):
|
||||
try:
|
||||
if self.question_event("您確定要更新數據庫嗎?"):
|
||||
file_path = os.path.join(self.dir, "PYAS_Model.json")
|
||||
response = requests.get('http://27.147.30.238:5001/model', params={"version": self.pyae_version}, timeout=10)
|
||||
if response.status_code == 200:
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
self.init_data_base()
|
||||
self.init_lang_text()
|
||||
self.info_event(f"數據庫更新成功: {self.pyae_version}")
|
||||
elif response.status_code == 204:
|
||||
self.info_event(f"數據庫已經是最新: {self.pyae_version}")
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
|
||||
def show_menu(self):
|
||||
self.WindowMenu = QMenu()
|
||||
Main_Settings = QAction(self.trans("設定"),self)
|
||||
#Main_Update = QAction(self.trans("更新"),self)
|
||||
Main_About = QAction(self.trans("關於"),self)
|
||||
self.WindowMenu.addAction(Main_Settings)
|
||||
#self.WindowMenu.addAction(Main_Update)
|
||||
self.WindowMenu.addAction(Main_About)
|
||||
Qusetion = self.WindowMenu.exec_(self.ui.Menu_Button.mapToGlobal(QPoint(0, 30)))
|
||||
if Qusetion == Main_About and self.ui.About_widget.isHidden():
|
||||
@@ -664,8 +646,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Window_widget.raise_()
|
||||
self.change_animation_3(self.ui.Setting_widget,0.5)
|
||||
self.change_animation_5(self.ui.Setting_widget,10,50,831,481)
|
||||
#if Qusetion == Main_Update:
|
||||
#self.update_database()
|
||||
|
||||
def change_sensitive(self):
|
||||
sw_state = self.ui.high_sensitivity_switch_Button.text()
|
||||
@@ -767,14 +747,15 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def write_scan(self, state, file):
|
||||
try:
|
||||
self.lock_file(file, True)
|
||||
self.virus_list.append(file)
|
||||
self.virus_list_ui.append(f"[{state}] {file}")
|
||||
item = QListWidgetItem()
|
||||
item.setText(f"[{state}] {file}")
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Checked)
|
||||
self.ui.Virus_Scan_output.addItem(item)
|
||||
if state and file:
|
||||
self.lock_file(file, True)
|
||||
self.virus_list.append(file)
|
||||
self.virus_list_ui.append(f"[{state}] {file}")
|
||||
item = QListWidgetItem()
|
||||
item.setText(f"[{state}] {file}")
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Checked)
|
||||
self.ui.Virus_Scan_output.addItem(item)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -812,7 +793,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
file = str(QFileDialog.getOpenFileName(self,self.trans("病毒掃描"),"C:/")[0])
|
||||
if file and file not in self.whitelist:
|
||||
self.init_scan()
|
||||
self.start_scan(file)
|
||||
self.write_scan(self.start_scan(file),file)
|
||||
self.answer_scan()
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
@@ -840,22 +821,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.bug_event(e)
|
||||
self.virus_scan_break()
|
||||
|
||||
def start_scan(self, file):
|
||||
try:
|
||||
file_type = str(f".{file.split('.')[-1]}").lower()
|
||||
if self.json["high_sensitive"] and file != self.pyas:
|
||||
if self.api_scan(file):
|
||||
self.write_scan(self.trans("惡意"),file)
|
||||
elif self.pe_scan(file):
|
||||
self.write_scan(self.trans("可疑"),file)
|
||||
elif file_type in slist and file != self.pyas:
|
||||
if self.api_scan(file):
|
||||
self.write_scan(self.trans("惡意"),file)
|
||||
elif self.pe_scan(file):
|
||||
self.write_scan(self.trans("可疑"),file)
|
||||
except:
|
||||
pass
|
||||
|
||||
def traverse_path(self,path):
|
||||
for fd in os.listdir(path):
|
||||
try:
|
||||
@@ -867,29 +832,48 @@ class MainWindow_Controller(QMainWindow):
|
||||
elif file not in self.whitelist:
|
||||
self.ui.Virus_Scan_text.setText(self.trans(f"正在掃描: ")+file)
|
||||
QApplication.processEvents()
|
||||
self.start_scan(file)
|
||||
self.write_scan(self.start_scan(file),file)
|
||||
gc.collect()
|
||||
except:
|
||||
pass
|
||||
|
||||
def api_scan(self, file):
|
||||
def start_scan(self, file):
|
||||
try:
|
||||
if self.json["cloud_services"] == 1:
|
||||
with open(file, "rb") as f:
|
||||
text = str(hashlib.md5(f.read()).hexdigest())
|
||||
strBody = f'-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="md5s"\r\n\r\n{text}\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="format"\r\n\r\nXML\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="product"\r\n\r\n360zip\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="combo"\r\n\r\n360zip_main\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="v"\r\n\r\n2\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="osver"\r\n\r\n5.1\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="vk"\r\n\r\na03bc211\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="mid"\r\n\r\n8a40d9eff408a78fe9ec10a0e7e60f62\r\n-------------------------------7d83e2d7a141e--'
|
||||
response = requests.post('http://qup.f.360.cn/file_health_info.php', data=strBody, timeout=5)
|
||||
return response.status_code == 200 and float(xmlet.fromstring(response.text).find('.//e_level').text) > 50
|
||||
label, level = self.api_scan(file)
|
||||
if file != self.pyas and level > 50:
|
||||
return f"{label}"#.{level}"
|
||||
elif file != self.pyas and level > 10:
|
||||
label_2, level_2 = self.pe_scan(file)
|
||||
if "White" not in label_2 and "Unknown" not in label_2:
|
||||
return f"{label_2}"#.{int(level_2*100)}"
|
||||
elif "Unknown" in label_2 and self.json["high_sensitive"]:
|
||||
return f"{label_2}"#.{int(level_2*100)}"
|
||||
elif file != self.pyas and not level:
|
||||
label_2, level_2 = self.pe_scan(file)
|
||||
if "White" not in label_2 and "Unknown" not in label_2:
|
||||
return f"{label_2}"#.{int(level_2*100)}"
|
||||
elif "Unknown" in label_2 and self.json["high_sensitive"]:
|
||||
return f"{label_2}"#.{int(level_2*100)}"
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def sign_scan(self, file):
|
||||
def api_scan(self, file):
|
||||
try:
|
||||
with pefile.PE(file, fast_load=True) as pe:
|
||||
return pe.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"]].VirtualAddress == 0
|
||||
if self.json["cloud_services"]:
|
||||
with open(file, "rb") as f:
|
||||
text = str(hashlib.md5(f.read()).hexdigest())
|
||||
QApplication.processEvents()
|
||||
strBody = f'-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="md5s"\r\n\r\n{text}\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="format"\r\n\r\nXML\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="product"\r\n\r\n360zip\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="combo"\r\n\r\n360zip_main\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="v"\r\n\r\n2\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="osver"\r\n\r\n5.1\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="vk"\r\n\r\na03bc211\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="mid"\r\n\r\n8a40d9eff408a78fe9ec10a0e7e60f62\r\n-------------------------------7d83e2d7a141e--'
|
||||
response = requests.post('http://qup.f.360.cn/file_health_info.php', data=strBody, timeout=5)
|
||||
QApplication.processEvents()
|
||||
if response.status_code == 200:
|
||||
label = str(xmlet.fromstring(response.text).find('.//malware').text).split('/')[1].split('.')
|
||||
level = int(float(xmlet.fromstring(response.text).find('.//e_level').text))
|
||||
return f"{label[0]}", level#/{label[1]}"
|
||||
return False, False
|
||||
except:
|
||||
return True
|
||||
return False, False
|
||||
|
||||
def pe_scan(self, file):
|
||||
try:
|
||||
@@ -901,20 +885,26 @@ class MainWindow_Controller(QMainWindow):
|
||||
fn.append(str(func.name, "utf-8"))
|
||||
except:
|
||||
pass
|
||||
m1, m0 = self.pe.predict(fn)
|
||||
#print(m1, m0, file)
|
||||
if self.json["high_sensitive"]:
|
||||
return m1 >= m0
|
||||
return m1 > 0.95 and m1 > m0
|
||||
QApplication.processEvents()
|
||||
return self.pe.predict(fn)
|
||||
except:
|
||||
return False
|
||||
return False, False
|
||||
|
||||
def sign_scan(self, file):
|
||||
try:
|
||||
with pefile.PE(file, fast_load=True) as pe:
|
||||
return pe.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"]].VirtualAddress == 0
|
||||
except:
|
||||
return True
|
||||
|
||||
def proc_scan(self, p):
|
||||
try:
|
||||
if isinstance(p, str) and os.path.exists(p):
|
||||
return self.start_scan(file)
|
||||
for entry in psutil.Process(p.pid).memory_maps():
|
||||
file = entry.path.replace("\\", "/")
|
||||
if ":/Windows" not in file and ":/Program" not in file:
|
||||
if self.api_scan(file) or self.pe_scan(file):
|
||||
if self.start_scan(file):
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
@@ -1021,9 +1011,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
for i in Permission:
|
||||
try:
|
||||
win32api.RegDeleteValue(key,i)
|
||||
self.kill_process(self.proc)
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意行為攔截: ")+file)
|
||||
self.kill_process(self.proc, "惡意行為攔截")
|
||||
except:
|
||||
pass
|
||||
win32api.RegCloseKey(key)
|
||||
@@ -1247,41 +1235,40 @@ class MainWindow_Controller(QMainWindow):
|
||||
Thread(target=self.protect_net_thread, daemon=True).start()
|
||||
|
||||
def protect_proc_thread(self):
|
||||
existing_processes = set()
|
||||
existing_process = set()
|
||||
for p in psutil.process_iter():
|
||||
existing_processes.add(p.pid)
|
||||
psutil.Process(os.getpid()).nice(256)
|
||||
existing_process.add(p.pid)
|
||||
while self.proc_protect:
|
||||
time.sleep(0.01)
|
||||
new_process = set()
|
||||
for p in psutil.process_iter():
|
||||
new_process.add(p.pid)
|
||||
for pid in new_process - existing_process:
|
||||
try:
|
||||
if p.pid not in existing_processes:
|
||||
name, file, cmd = p.name(), p.exe().replace("\\", "/"), p.cmdline()
|
||||
if file != self.pyas and file not in self.whitelist:
|
||||
self.lock_process(p, True)
|
||||
if "powershell" in name and self.api_scan(cmd[-1].split("'")[-2]):
|
||||
self.kill_process(p)
|
||||
file = cmd[-1].split("'")[-2].replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意腳本攔截: ")+file)
|
||||
elif "cmd.exe" in name and self.api_scan(" ".join(cmd[2:])):
|
||||
self.kill_process(p)
|
||||
file = " ".join(cmd[2:]).replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意腳本攔截: ")+file)
|
||||
elif ":/Windows" in file and self.api_scan(cmd[-1]):
|
||||
self.kill_process(p)
|
||||
file = cmd[-1].replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意軟體攔截: ")+file)
|
||||
elif ":/Windows" not in file and self.proc_scan(p):
|
||||
self.kill_process(p)
|
||||
self.send_notify(self.trans("惡意軟體攔截: ")+file)
|
||||
elif ":/Windows" not in file and self.sign_scan(file):
|
||||
self.proc = p
|
||||
self.lock_process(p, False)
|
||||
existing_processes.add(p.pid)
|
||||
elif not psutil.pid_exists(p.pid):
|
||||
existing_processes.remove(p.pid)
|
||||
p = psutil.Process(pid)
|
||||
self.handle_new_process(p)
|
||||
except:
|
||||
self.lock_process(p, False)
|
||||
pass
|
||||
existing_process = new_process
|
||||
|
||||
def handle_new_process(self, p):
|
||||
try:
|
||||
name, file, cmd = p.name(), p.exe().replace("\\", "/"), p.cmdline()
|
||||
if file != self.pyas and file not in self.whitelist:
|
||||
self.lock_process(p, True)
|
||||
if "powershell" in name and self.start_scan(cmd[-1].split("'")[-2]):
|
||||
self.kill_process(p, "惡意腳本攔截")
|
||||
elif "cmd.exe" in name and self.start_scan(" ".join(cmd[2:])):
|
||||
self.kill_process(p, "惡意腳本攔截")
|
||||
elif ":/Windows" in file and self.start_scan(cmd[-1]):
|
||||
self.kill_process(p, "惡意軟體攔截")
|
||||
elif ":/Windows" not in file and self.proc_scan(p):
|
||||
self.kill_process(p, "惡意軟體攔截")
|
||||
elif ":/Windows" not in file and self.sign_scan(file):
|
||||
self.proc = p
|
||||
self.lock_process(p, False)
|
||||
except:
|
||||
self.lock_process(p, False)
|
||||
|
||||
def lock_process(self, p, lock):
|
||||
try:
|
||||
@@ -1292,11 +1279,15 @@ class MainWindow_Controller(QMainWindow):
|
||||
except:
|
||||
pass
|
||||
|
||||
def kill_process(self, parent):
|
||||
def kill_process(self, parent, info):
|
||||
try:
|
||||
parent.kill()
|
||||
for child in parent.children(recursive=True):
|
||||
child.kill()
|
||||
if psutil.pid_exists(parent.pid):
|
||||
file = parent.exe().replace("\\", "/")
|
||||
self.send_notify(self.trans(f"{info}: ")+file)
|
||||
for child in parent.children(recursive=True):
|
||||
child.kill()
|
||||
parent.kill()
|
||||
self.proc = None
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -1308,16 +1299,14 @@ class MainWindow_Controller(QMainWindow):
|
||||
fpath = str(f"C:/{file}").replace("\\", "/")
|
||||
ftype = str(f".{fpath.split('.')[-1]}").lower()
|
||||
if action == 2 and ":/Users" in fpath and "/AppData/" not in fpath:
|
||||
if ftype in alist:
|
||||
self.kill_process(self.proc)
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
self.send_notify(self.trans("勒索行為攔截: ")+file)
|
||||
elif action == 3 and os.path.getsize(fpath) <= 20971520 and ftype in slist:
|
||||
if ":/Users" in fpath or ":/Windows" not in fpath:
|
||||
if self.api_scan(fpath) or self.pe_scan(fpath):
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
if ":/Program" not in file and ftype in alist:
|
||||
self.kill_process(self.proc, "勒索行為攔截")
|
||||
elif action == 3 and ":/Users" in fpath and "/AppData/" not in fpath:
|
||||
if os.path.getsize(fpath) <= 52428800 and ftype in slist:
|
||||
if self.start_scan(fpath):
|
||||
os.remove(fpath)
|
||||
self.send_notify(self.trans("惡意軟體刪除: ")+fpath)
|
||||
gc.collect()
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -1327,17 +1316,13 @@ class MainWindow_Controller(QMainWindow):
|
||||
time.sleep(0.2)
|
||||
with open(r"\\.\PhysicalDrive0", "r+b") as f:
|
||||
if self.mbr_value[510:512] != b'\x55\xAA':
|
||||
self.kill_process(self.proc)
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意行為攔截: ")+file)
|
||||
self.kill_process(self.proc, "惡意行為攔截")
|
||||
elif f.read(512) != self.mbr_value:
|
||||
f.seek(0)
|
||||
f.write(self.mbr_value)
|
||||
self.kill_process(self.proc)
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
self.send_notify(self.trans("惡意行為攔截: ")+file)
|
||||
self.kill_process(self.proc, "惡意行為攔截")
|
||||
except:
|
||||
pass
|
||||
self.kill_process(self.proc, "惡意行為攔截")
|
||||
|
||||
def protect_reg_thread(self):
|
||||
while self.reg_protect:
|
||||
@@ -1356,11 +1341,9 @@ class MainWindow_Controller(QMainWindow):
|
||||
time.sleep(0.2)
|
||||
local = socket.gethostbyname(socket.gethostname())
|
||||
for conn in self.proc.connections():
|
||||
file = self.proc.exe().replace("\\", "/")
|
||||
if ":/Windows" not in file and ":/Program" not in file:
|
||||
if "/AppData/" not in file and ":/Program" not in file:
|
||||
if conn.laddr.ip == local:
|
||||
self.kill_process(self.proc)
|
||||
self.send_notify(self.trans("網路通訊攔截: ")+file)
|
||||
self.kill_process(self.proc, "網路通訊攔截")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
+36
-35
@@ -1,5 +1,5 @@
|
||||
import re, time, json, hashlib, numpy
|
||||
from itertools import groupby
|
||||
import time, json, hashlib, numpy
|
||||
from collections import Counter
|
||||
|
||||
class ListSimHash:
|
||||
def __init__(self):
|
||||
@@ -19,38 +19,24 @@ class ListSimHash:
|
||||
def get_model(self, label):
|
||||
return self.model[label]
|
||||
|
||||
def train_model(self, ones, zero, feature=128, batch_size=1000):
|
||||
self.model["ones"] = []
|
||||
self.model["zero"] = []
|
||||
self.model["feature"] = feature
|
||||
self.model["batch_size"] = batch_size
|
||||
def train_model(self, label, data):
|
||||
start = time.time()
|
||||
print("Convert ones")
|
||||
for i, x in enumerate(ones, 1):
|
||||
self.model["ones"].append(self.build_text(x))
|
||||
print(f"Convert {label}")
|
||||
if label not in self.model:
|
||||
self.model[label] = []
|
||||
for i, x in enumerate(data, 1):
|
||||
self.model[label].append(self.build_text(x))
|
||||
used = "{0:.2f}".format(time.time()-start)
|
||||
self.progress_bar(i, len(ones), prefix=f'{i}/{len(ones)}:', suffix=f'{used}s')
|
||||
start = time.time()
|
||||
print("Convert zero")
|
||||
for i, y in enumerate(zero, 1):
|
||||
self.model["zero"].append(self.build_text(y))
|
||||
used = "{0:.2f}".format(time.time()-start)
|
||||
self.progress_bar(i, len(zero), prefix=f'{i}/{len(zero)}:', suffix=f'{used}s')
|
||||
prefix, suffix = f'{i}/{len(data)}:', f'{used}s'
|
||||
self.progress_bar(i, len(data), prefix, suffix)
|
||||
|
||||
def build_text(self, content, width=4):
|
||||
def build_text(self, content):
|
||||
sums, batch, count = [], [], 0
|
||||
if isinstance(content, list):
|
||||
content = ' '.join(content)
|
||||
elif isinstance(content, bytes):
|
||||
content = content.decode('utf-8', errors='ignore')
|
||||
content = ''.join(re.findall(r'[\w\u4e00-\u9fcc]+', content.lower()))
|
||||
features = [content[i:i + width] for i in range(max(len(content) - width + 1, 1))]
|
||||
features = {k: sum(1 for _ in g) for k, g in groupby(sorted(features))}
|
||||
features = dict(Counter(sorted(content)))
|
||||
for f, w in features.items():
|
||||
count += w
|
||||
h = hashlib.md5(f.encode('utf-8')).digest()
|
||||
batch.append(h * w)
|
||||
if len(batch) >= self.model["batch_size"]:
|
||||
batch.append(hashlib.md5(json.dumps(f).encode('utf-8')).digest() * w)
|
||||
if len(batch) >= 10000:
|
||||
sums.append(self.sum_hashes(batch))
|
||||
batch = []
|
||||
if batch:
|
||||
@@ -61,7 +47,7 @@ class ListSimHash:
|
||||
|
||||
def sum_hashes(self, digests):
|
||||
bitarray = numpy.unpackbits(numpy.frombuffer(b''.join(digests), dtype='>B'))
|
||||
return numpy.sum(numpy.reshape(bitarray, (-1, self.model["feature"])), 0)
|
||||
return numpy.sum(numpy.reshape(bitarray, (-1, 128)), 0)
|
||||
|
||||
def progress_bar(self, iteration, total, prefix='', suffix='', length=50, fill='█'):
|
||||
percent = min(100.0, max(0.0, 100 * (iteration / float(total))))
|
||||
@@ -71,13 +57,28 @@ class ListSimHash:
|
||||
bar = fill * filled_length + ' ' * (length - filled_length)
|
||||
print(f'\r {prefix: <10} |{bar}| {percent_string}% {suffix}', end=end_char)
|
||||
|
||||
def predict(self, query):
|
||||
def predict_all(self, query):
|
||||
label_similarities = {}
|
||||
query_hash = self.build_text(query)
|
||||
max_ones = max(self.similar(x, query_hash) for x in self.model["ones"])
|
||||
max_zero = max(self.similar(y, query_hash) for y in self.model["zero"])
|
||||
return max_ones, max_zero
|
||||
for label in self.model:
|
||||
max_similarity = 0
|
||||
for data_point in self.model[label]:
|
||||
similarity = self.similar(data_point, query_hash)
|
||||
if similarity > max_similarity:
|
||||
max_similarity = similarity
|
||||
label_similarities[label] = max_similarity
|
||||
return label_similarities
|
||||
|
||||
def predict(self, query):
|
||||
max_similarity, max_label = 0, None
|
||||
query_hash = self.build_text(query)
|
||||
for label in self.model:
|
||||
for data_point in self.model[label]:
|
||||
similarity = self.similar(data_point, query_hash)
|
||||
if similarity > max_similarity:
|
||||
max_similarity, max_label = similarity, label
|
||||
return max_label, max_similarity
|
||||
|
||||
def similar(self, x, y):
|
||||
hamming_distance = bin(x ^ y).count('1')
|
||||
similarity = 1 - hamming_distance / self.model["feature"]
|
||||
return similarity
|
||||
return 1 - hamming_distance / 128
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"ones": [138514579140422510314615591404235408110, 138884061479927293269157399561321625124, 106913533745562494950237068000717194857, 56400517596638244422894049797604820621, 57509758994800025148320631233619478382, 266907975564823269757642468520682218021, 268764573572222081482569414853338147421, 301824928671740406049708617676147983911, 216322613833371885512412681366080352834, 305869899604823982125728318036880769198, 139390375862009821188813492031092843045, 140636369840301821837859972310736757357, 93525514883026399429643965685843744494, 85423552611944120389541188728576853614, 212959202992585676402479957744392065258, 310175323171803986711996189701871919269, 267073946987621142567955636205481517613, 130213060982497483351391950606798445166, 309453635424025901100964431663839207981, 98595718339270037315648519699911042861, 804810740308425468096265735208257617, 308840950453806983092423514217084578476, 322017788596429201866715226549004966766, 96855081274446633945978062387702817317, 309443088174281869980853203902500569645, 145963460354456926129955518358155059877, 100726355023313678737270049805708838766, 163055950804159105041684713458861453642, 139400638929619405534171854486176686629, 314740690747489056417995540920077280813, 309174548517306493765742812127600992824, 42649730517016866640152470265639253071, 266991032348753532132223164567115948653, 310834785753961546009345771577019752617, 138794485055151379651410532066913608701, 131790595577365633473641510877883811372, 333214357055760258309229460312077263456, 266919150567781465017126522717174383268, 309443250354319958579894353439906751021, 314760122553781807187305329030403597869, 309526327094009133336072658832466510380, 140783818610473943253735333316647117357, 266908765191386477077819778373267636908, 141960523677151839211304480019230155437, 236708587517087268685876607084596151010, 147109497140790587393132625769962294828, 98101030488836797416915605797123547821, 309443006965336732125112839751851204645, 163777668652403995261587270005386479850, 96850943187510051473774485962306807341, 314740690747489056417995540920077280813, 266907874033546142647711315245141475885, 128087963732730699244600678440497496745, 122948904762874323200167759687292791479, 144623683762647410432822459404215795881, 175281760716791954210630508746562429745, 98185566304403225600012489980760220205, 312173101091522310981766359248219144333, 165719174729833763978390369816514151589, 130453416906105788293089319006359032458, 309459962424693681697118037040663257637, 312110631309585432258276350165909913633, 266898908365541525694120496365498163769, 301974605256105130746947982559953757414, 46088979409888770325991887802833783310, 98097114716132427630865195752911955500, 98179117726185629973687845690377904685, 128833381668692705604881271753964704076, 288187285762824132116353144464193487405, 440767454710337817086060213441032296, 308755229979748206303057066098374746633, 310789353473439559353693532556983984677, 309443331008521396576751777765001683629, 272224825421632604778319829685274829501, 314740690747489056417995540920077280813, 288162135445850533606754792760600323239, 266908765349823459293196338896727065260, 266919475084642627997330537792153215533, 118095062731544531316068994170817536096, 309460205972074921952248716662523977893, 138980104556989140895595181268125835917, 96753309757095605084115148461573554213, 96783566280022178361451345888136274605, 267006527672619154632784726463056593709, 268325411442133354907118265595969561133, 45423085047571636176304357087088791778, 140693602135645422745421550777944908460, 266908927450643968163503768535437820588, 139317724478784922140315175893335437861, 98075229203956313888405997203836658285, 139307136862901466424877793378792006181, 141949813792938456152307200983465099405, 266887023150038950813539942248450810413, 266907873517942888138024343981564256813, 309527625168214095599527134475951948333, 288176899901775619274666676430489666220, 132687201639749430771754766010675328697, 298809467903569967359434970965896200999, 266909251929602884051145652263806452396, 96856378081010667424655802311172842021, 334364013698977648789398548127408169731, 138478276465840759527093181786120602252, 309517280516176477337549624053815730737, 309532816881431070079891773455787762221, 267006688625182579765726710919333306917, 301342822028899395690309866891238953529, 140889247564697972421510238399255437956, 301704982992736118799149217975167423010, 123342205008290812825969949820881134509, 309444547834874662752143629118327890477, 120368316428277902366824346477250637709, 96608366161759132771693290653207750157, 309258884864988268167108821321512280229, 266887185302388558609052276779780547237, 120204759374330029658546372684809684013, 266750361825108195839408748923433296011, 309541905261615072912890344878225383465, 136838710717061085016646030313491257547, 139400638929619405533018932981569839653, 309535252305417442974606230157044113441, 96865343064503306525844664637493502501, 98091942701683498853848791423305786021, 12268668727495Line truncated
|
||||
{"Unknown": [10199010580531108378153827424457992432, 20965212707052912989658218281213053170, 20963924773736013955013492889397430514, 20965222847950647661922877313293420786, 20963924773736089512877253988092938483, 10533913729454048551192748670221101302, 10497567570978277785165438149536581872, 230418814927598623996991522865620895293], "White": [126672244860282820431531292152154892541, 126555244512863767515621062938772454385, 78206639303253050193082960917406129821, 180439547362931620767428561827016696106, 96103515196312870469979178835907426963, 106202738889863580199047548478556282224, 260681472954591486442301293972682570259, 334352372173892944739362819086050576826, 270698534086324527574602815275595168743, 52278935817957542072232518657580445973, 99964490807793194121661552779445205157, 114471449979609419026325537602253303510, 170288120086869810213050150585452458992, 20129952829430162432875533418501193427, 266141180604311766657329911262256522695, 194231769680954789184967343915738715269, 137555894938392968938334822886799145665, 32033385634193095265531812355001705364, 110412723075988544148987035520371252041, 95564371670156926573557604030875376880, 95235309747885939408380636606625811569, 272762168699147334321583996672002378255, 95234011064914281942190040816173653105, 94471327154819245031506476509638106704, 95313696146069105288568328992515893493, 93984468150284189415663958982282127605, 191147052097100843670989027331488156725, 103210672664238242772979731817227685237, 56724333007221946388761990730009660128, 101562244577076015330628724737265682909, 97287175069805646577858533189449166301, 137063300177336245346774014048969161649, 316391968656924997605188916362257077459, 264287352948858755174876745019957203391, 127136776672701393662717729226704358773, 9912885994425979960261799249926495473, 214498205255495472884061693173662060219, 105039659248652423950583866198328679776, 106486519388821918892958052791862913681, 81533898116464931264738244322343722087, 127128973031678141900306064284785253496, 257976287344519798598519417614968543943, 95234579695571071996043856278635879538, 307531936139217865648235621101964847809, 205524205305644077365818951604097443015, 10082933643349790779259596715866791152, 105863211359421133420308580490619723120, 105536091507504387016141979202387910000, 115256152418524974755063297364983094641, 258226055192645594643924661804242821079, 184879672381654838626194080314169453584, 105909917863928976433791749005432917096, 34668429459089199253155684394504639701, 9333342038490638804353570140444499409, 49992947087053905927423189110869930637, 114390951894751980367497997972138956045, 40525380716593540848111929430426386129, 92531564279929657078344831661770634033, 137845158706024438551516917025209916775, 82711778578996712205456007623860083392, 142895363148849470268902285117702200512, 176210598858636561054489191954962668740, 133988075388031745460051108783604183680, 127463789261350104996635356465169505635, 98401956749501984262112138828559240544, 105619903475864025251671385889627380849, 194216192765620392180514937530431948487, 178730848644410936934440792379530771324, 258767967557372966404648755263173813716, 95568909833307793735851930883495894385, 105203216600314032187918420804040465776, 10160172324731669179270431009861737585, 95562338257159239457022778648277753201, 125705675445940363792857463789011840389, 105782103246308081595321955114562886777, 34490061240648476397849656073168201108, 337793686977585440073129666111702532467, 278253338747731733314329375842609871921, 204788843742030229839080201679229506773, 106117654063199359331238217293466812006, 123266687541636144245366511635599982231, 113845713591553304589832425329269218672, 102400300404095555238772811174816483363, 115752031916027952368786798048662461543, 205193551069866139019248248605938239445, 101437234347196055762008445071888009636, 148030553843923537774182040572301348817, 95562399131158503793285318098946563443, 144743835053038288880188325484490464627, 329456512868359962875761871381429648792, 214132526311861388081693372283346711315, 212807863125887894065170197859985748755, 90639505994802779364701320439314232445, 109312881611100283088661575235655027037, 268695571549372555579983860480753996530, 276556254823007156956265006607247855228, 158532724662396204460585683955318721251, 190236918274156159301867868769173894064, 115505281197039501762156314342977388146, 181151739907962908273686170106830254275, 103040304820632656358846714092274654455, 283839353929015376840553872262568182165, 126305356110326106528653817459839286387, 232772214119775911616044955505922667440, 267224571901232164108563912343781345315, 248870611769713486967773923305072182805, 94401261442397178213607895041941511616, 126697942675733486251713755064939650169, 52680527483000227468312744969526057584, 100468409853345213529992161170862574067, 195546595259106600444307572967932415185, 121396668310321681197001161772784753777, 102772203717048361679815565428970429489, 118636962645139146202043096156604144755, 130735009156835Line truncated
|
||||
+1
-1
@@ -2,7 +2,7 @@ import pyinstaller_versionfile
|
||||
|
||||
pyinstaller_versionfile.create_versionfile(
|
||||
output_file="versionfile.txt",
|
||||
version='3.0.5',
|
||||
version='3.0.8',
|
||||
company_name="PYAS Security",
|
||||
file_description="Python Antivirus Software",
|
||||
internal_name="PYAS",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# PYAS (Python Antivirus Software)
|
||||
|
||||

|
||||

|
||||
|
||||
## Readme Language
|
||||
|
||||
[繁體中文](https://github.com/zackzheng1121/PYAS/blob/main/README_zh.md)
|
||||
|
||||
## File Information
|
||||
|
||||
@@ -113,6 +117,8 @@ def proc_detect():
|
||||
print(f"File: {file}")
|
||||
print(f"Pid: {p.pid}")
|
||||
print(f"Cmd: {cmd}")
|
||||
elif not psutil.pid_exists(p.pid):
|
||||
existing_processes.remove(p.pid)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
# PYAS (Python 防毒軟體)
|
||||
|
||||

|
||||
|
||||
## 文件訊息
|
||||
|
||||
PYAS.py -> PYAS主程式(包括動畫、掃描、保護功能等)
|
||||
|
||||
PYAS_Engine.py -> 轉換資料庫(用於相互轉換資料庫字典和清單)
|
||||
|
||||
PYAS_Extension.py -> 檔案副檔名(包括掃描檔案副檔名和常用檔案副檔名)
|
||||
|
||||
PYAS_Model.* -> 病毒庫(病毒庫必須放在同一目錄下)
|
||||
|
||||
PYAS_Interface.py -> PyQt5 Interface(由QT設計師設計,必須與主程式相符)
|
||||
|
||||
PYAS_Resource.py -> PyQt5資源(狀態圖片、圖示包、按鈕圖示等)
|
||||
|
||||
PYAS_Language.py -> 翻譯字典(繁體中文、簡體中文、英文)
|
||||
|
||||
PYAS_Version.py -> Pyinstaller Info(檔案資訊、版本資訊、原名等)
|
||||
|
||||
## 要求
|
||||
|
||||
使用 pip install requirements 來安裝需要的模組
|
||||
|
||||
```
|
||||
psutil==5.9.5
|
||||
pefile==2023.2.7
|
||||
requests==2.31.0
|
||||
pyperclip==1.8.2
|
||||
pywin32==306
|
||||
PyQt5==5.15.9
|
||||
```
|
||||
|
||||
## 哈希掃描
|
||||
|
||||
使用奇虎360雲端服務掃描已知惡意文件
|
||||
|
||||
```
|
||||
import hashlib, requests
|
||||
import xml.etree.ElementTree as xmlet
|
||||
|
||||
def hash_scan(file):
|
||||
try:
|
||||
with open(file, "rb") as f:
|
||||
text = str(hashlib.md5(f.read()).hexdigest())
|
||||
strBody = f'-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="md5s"\r\n\r\n{text}\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="format"\r\n\r\nXML\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="product"\r\n\r\n360zip\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="combo"\r\n\r\n360zip_main\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="v"\r\n\r\n2\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="osver"\r\n\r\n5.1\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="vk"\r\n\r\na03bc211\r\n-------------------------------7d83e2d7a141e\r\nContent-Disposition: form-data; name="mid"\r\n\r\n8a40d9eff408a78fe9ec10a0e7e60f62\r\n-------------------------------7d83e2d7a141e--'
|
||||
response = requests.post('http://qup.f.360.cn/file_health_info.php', data=strBody, timeout=3)
|
||||
if response.status_code == 200:
|
||||
level = float(xmlet.fromstring(response.text).find('.//e_level').text)
|
||||
if level > 50:
|
||||
return "Virus"
|
||||
elif level <= 10:
|
||||
return "Safe"
|
||||
return "Unknown"
|
||||
return f"Error: {response.status_code}"
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
info = hash_scan("path to file")
|
||||
print(info)
|
||||
```
|
||||
|
||||
## 文件掃描
|
||||
|
||||
取得pefile檔案函數導入表進行掃描
|
||||
|
||||
```
|
||||
import pefile
|
||||
|
||||
def pe_scan(file):
|
||||
try:
|
||||
fn = []
|
||||
with pefile.PE(file) as pe:
|
||||
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
for func in entry.imports:
|
||||
try:
|
||||
fn.append(str(func.name, "utf-8"))
|
||||
except:
|
||||
pass
|
||||
if fn in known_malicious_list:
|
||||
return "Virus"
|
||||
return "Safe"
|
||||
return "Unknown"
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
info = pe_scan("path to file")
|
||||
print(info)
|
||||
```
|
||||
|
||||
## 進程偵測
|
||||
|
||||
顯示新進程名稱、檔案路徑、cmd 行、pid
|
||||
```
|
||||
import psutil, time
|
||||
|
||||
def proc_detect():
|
||||
existing_processes = set()
|
||||
for p in psutil.process_iter():
|
||||
if p.pid not in existing_processes:
|
||||
existing_processes.add(p.pid)
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
if p.pid not in existing_processes:
|
||||
existing_processes.add(p.pid)
|
||||
name, file, cmd = p.name(), p.exe(), p.cmdline()
|
||||
print(f"Name: {name}")
|
||||
print(f"File: {file}")
|
||||
print(f"Pid: {p.pid}")
|
||||
print(f"Cmd: {cmd}")
|
||||
except:
|
||||
pass
|
||||
|
||||
proc_detect()
|
||||
```
|
||||
|
||||
## 檔案偵測
|
||||
|
||||
監控指定路徑下的檔案變化
|
||||
```
|
||||
import os, win32file, win32con
|
||||
|
||||
def file_detect(path):
|
||||
hDir = win32file.CreateFile(path,win32con.GENERIC_READ,win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE|win32con.FILE_SHARE_DELETE,None,win32con.OPEN_EXISTING,win32con.FILE_FLAG_BACKUP_SEMANTICS,None)
|
||||
while True:
|
||||
for action, file in win32file.ReadDirectoryChangesW(hDir,10485760,True,win32con.FILE_NOTIFY_CHANGE_FILE_NAME|win32con.FILE_NOTIFY_CHANGE_DIR_NAME|win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES|win32con.FILE_NOTIFY_CHANGE_SIZE|win32con.FILE_NOTIFY_CHANGE_LAST_WRITE|win32con.FILE_NOTIFY_CHANGE_SECURITY,None,None):
|
||||
try:
|
||||
fpath = os.path.join(path, file)
|
||||
if action == 1:
|
||||
print(f"File Create: {fpath}")
|
||||
elif action == 2:
|
||||
print(f"File Delete: {fpath}")
|
||||
elif action == 3:
|
||||
print(f"File Modify: {fpath}")
|
||||
elif action == 4:
|
||||
print(f"File Rename: {fpath}")
|
||||
elif action == 5:
|
||||
print(f"File Rename: {fpath}")
|
||||
except:
|
||||
pass
|
||||
|
||||
file_detect("path")
|
||||
```
|
||||
|
||||
## 官方網頁
|
||||
|
||||
https://pyantivirus.wixsite.com/pyas
|
||||
|
||||
https://github.com/87owo/PYAS
|
||||
|
||||
## 開源許可證
|
||||
|
||||
https://github.com/87owo/PYAS/blob/main/LICENSE.md
|
||||
|
||||
## 支援的系統
|
||||
|
||||
Windows 8.1, 10, 11 (64-bit),記憶體 1GB, 磁碟容量 1GB 或更高
|
||||
Other systems may experience software malfunctions or crash
|
||||
|
||||
## Special Thanks
|
||||
360, Wix, VirusShare, mtkiao129, AV-T Team of LisectGroup
|
||||
|
||||
Copyright© 2020~2024 PYAS Security By 87owo
|
||||
Reference in new issue
Block a user