Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
316882bcd0 | ||
|
|
b204e52297 | ||
|
|
f82a63f4c8 | ||
|
|
cb0f2108a4 | ||
|
|
300b7a7a68 | ||
|
|
c3852ca60d | ||
|
|
a5fb735c93 | ||
|
|
d0b04ba84f | ||
|
|
9552742a39 | ||
|
|
8e9bdf6c0c | ||
|
|
818cc48502 | ||
|
|
adc4e28eb8 | ||
|
|
2e3a4d3bf1 | ||
|
|
d9bcac78e7 | ||
|
|
2342947849 | ||
|
|
19204dee8d | ||
|
|
863fa90b80 | ||
|
|
6fdef4a8f1 | ||
|
|
9469ceaa02 | ||
|
|
857f184409 | ||
|
|
a2f4a725f5 | ||
|
|
d12449bbb9 | ||
|
|
a41f4711dd |
No files matched your search
@@ -1,13 +1,9 @@
|
||||
{
|
||||
"Suffix": [".exe", ".dll", ".sys", ".bat", ".cmd", ".ps1", ".vbs"],
|
||||
|
||||
"Labels": ["White/Pefile", "White/Script", "Virus/Pefile", "Virus/Script"],
|
||||
|
||||
"Detect": ["Virus/Pefile", "Virus/Script"],
|
||||
|
||||
"Models": ["PYAS_Model_A1.onnx", "PYAS_Model_A2.onnx", "PYAS_Model_A3.onnx"],
|
||||
|
||||
"Pixels": [300, 300],
|
||||
"Pixels": [224, 224],
|
||||
|
||||
"Values": 95
|
||||
}
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
import os, gc, sys, time, json, psutil
|
||||
import ctypes, msvcrt, pyperclip, win32file
|
||||
import win32gui, win32api, win32con
|
||||
import ctypes, struct, msvcrt, pyperclip
|
||||
import win32gui, win32api, win32con, win32file
|
||||
from PYAS_Engine import YRScan, DLScan
|
||||
from PYAS_Suffixes import slist, alist
|
||||
from PYAS_Language import translate_dict
|
||||
@@ -19,7 +19,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.pyas = sys.argv[0].replace("\\", "/")
|
||||
self.dir = os.path.dirname(self.pyas)
|
||||
self.pyae_version = "AI Engine"
|
||||
self.pyas_version = "3.1.7"
|
||||
self.pyas_version = "3.2.1"
|
||||
self.first_startup = True
|
||||
self.init_data_base()
|
||||
self.init_tray_icon()
|
||||
@@ -646,7 +646,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
# question event message
|
||||
print(f"[Quest] > {text}")
|
||||
if self.first_startup != True:
|
||||
return QMessageBox.question(self, "Quest", self.trans(str(text)),QMessageBox.Yes|QMessageBox.No) == 16384
|
||||
return QMessageBox.question(self, "Quest",
|
||||
self.trans(str(text)),QMessageBox.Yes|QMessageBox.No) == 16384
|
||||
except:
|
||||
return False
|
||||
|
||||
@@ -655,7 +656,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
# send system notification
|
||||
now_time = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
print(f"[Notify] > [{now_time}] {text}")
|
||||
QMetaObject.invokeMethod(self.ui.State_output, "append", Qt.QueuedConnection, Q_ARG(str, f"[{now_time}] {text}"))
|
||||
QMetaObject.invokeMethod(self.ui.State_output, "append",
|
||||
Qt.QueuedConnection, Q_ARG(str, f"[{now_time}] {text}"))
|
||||
if self.first_startup == False and notify_bar == True:
|
||||
self.tray_icon.showMessage(now_time, text, 5000)
|
||||
except:
|
||||
@@ -819,7 +821,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Checked)
|
||||
self.ui.Virus_Scan_output.addItem(item)
|
||||
self.send_notify(self.trans(f"發現病毒: ")+file, False)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -864,7 +865,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
file = str(QFileDialog.getOpenFileName(self,self.trans("病毒掃描"),"C:/")[0])
|
||||
if file and file not in self.whitelist and file != self.pyas:
|
||||
self.init_scan()
|
||||
self.scan_thread = Thread(target=self.write_scan, args=(self.start_scan(file),file,), daemon=True)
|
||||
self.scan_thread = Thread(target=self.write_scan,
|
||||
args=(self.start_scan(file),file,), daemon=True)
|
||||
self.scan_thread.start()
|
||||
while self.scan_thread.is_alive():
|
||||
QApplication.processEvents()
|
||||
@@ -921,17 +923,19 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def start_scan(self, file):
|
||||
try:
|
||||
if os.path.exists(file):
|
||||
self.send_notify(self.trans(f"正在掃描: ")+file, False)
|
||||
label, level = self.model.dl_scan(file)
|
||||
if label and label in self.model.detect:
|
||||
if self.json["high_sensitive"]:
|
||||
return label
|
||||
elif level >= self.model.values:
|
||||
return label
|
||||
if isinstance(file, dict):
|
||||
match_data = file
|
||||
elif os.path.exists(file):
|
||||
match_data = self.model.get_type(file)
|
||||
for ftype, data in match_data.items():
|
||||
label, level = self.model.dl_scan(data)
|
||||
if label and label in self.model.detect:
|
||||
if self.json["high_sensitive"]:
|
||||
return label
|
||||
elif level >= self.model.values:
|
||||
return label
|
||||
if self.json["extension_kits"]:
|
||||
if self.rules.yr_scan(file):
|
||||
return "Virus/Rules"
|
||||
return self.rules.yr_scan(file)[0]
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
@@ -1330,15 +1334,18 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.kill_process("病毒攔截", p, file, False)
|
||||
elif self.load_scan(p):
|
||||
self.kill_process("加載攔截", p, file, False)
|
||||
elif self.memory_scan(p):
|
||||
self.kill_process("記憶體攔截", p, file, False)
|
||||
elif ":/Windows" not in file and ":/Program" not in file:
|
||||
if os.path.exists(file):
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
if os.path.exists(file) and ftype in slist:
|
||||
self.track_proc = p, file, True
|
||||
except:
|
||||
pass
|
||||
|
||||
def load_scan(self, p):
|
||||
try:
|
||||
for entry in p.memory_maps():
|
||||
for entry in p.memory_maps(grouped=True):
|
||||
file = str(entry.path).replace("\\", "/")
|
||||
if ":/Windows" not in file and file not in self.whitelist:
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
@@ -1348,19 +1355,50 @@ class MainWindow_Controller(QMainWindow):
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_module_base(self, p):
|
||||
try:
|
||||
for entry in p.memory_maps(grouped=False):
|
||||
file = str(entry.path).replace("\\", "/")
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
if ftype in [".exe"] and file not in self.whitelist:
|
||||
return int(entry.addr, 16)
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def memory_scan(self, p):
|
||||
try:
|
||||
memory_bytes = {}
|
||||
m = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, p.pid)
|
||||
for memory_range in p.memory_maps(grouped=False):
|
||||
base_addr = int(memory_range.addr, 16)
|
||||
buffer = ctypes.create_string_buffer(memory_range.rss)
|
||||
if ctypes.windll.kernel32.ReadProcessMemory(m, ctypes.c_void_p(base_addr),
|
||||
buffer, memory_range.rss, ctypes.byref(ctypes.c_size_t(0))):
|
||||
file = str(memory_range.path).replace("\\", "/")
|
||||
if ":/Windows" not in file and self.start_scan(buffer.raw):
|
||||
return True
|
||||
ctypes.windll.kernel32.CloseHandle(m)
|
||||
match_data = {}
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
base_address = self.get_module_base(p)
|
||||
process_handle = kernel32.OpenProcess(0x1F0FFF, False, p.pid)
|
||||
dos_header = ctypes.create_string_buffer(64)
|
||||
kernel32.ReadProcessMemory(process_handle, ctypes.c_void_p(base_address), dos_header, 64, None)
|
||||
nt_headers_offset = struct.unpack("<I", dos_header[0x3C:0x3C + 4])[0]
|
||||
nt_headers = ctypes.create_string_buffer(248)
|
||||
kernel32.ReadProcessMemory(process_handle,
|
||||
ctypes.c_void_p(base_address + nt_headers_offset), nt_headers, 248, None)
|
||||
number_of_sections = struct.unpack("<H", nt_headers[6:8])[0]
|
||||
optional_header_size = struct.unpack("<H", nt_headers[20:22])[0]
|
||||
section_headers_offset = nt_headers_offset + 24 + optional_header_size
|
||||
for i in range(number_of_sections):
|
||||
section_header = ctypes.create_string_buffer(40)
|
||||
section_address = base_address + section_headers_offset + i * 40
|
||||
kernel32.ReadProcessMemory(process_handle,
|
||||
ctypes.c_void_p(section_address), section_header, 40, None)
|
||||
section_name = section_header[:8].rstrip(b'\x00').decode('latin1')
|
||||
virtual_size = struct.unpack("<I", section_header[8:12])[0]
|
||||
virtual_address = struct.unpack("<I", section_header[12:16])[0]
|
||||
characteristics = struct.unpack("<I", section_header[36:40])[0]
|
||||
text_address = base_address + virtual_address
|
||||
buffer = ctypes.create_string_buffer(virtual_size)
|
||||
if kernel32.ReadProcessMemory(process_handle, ctypes.c_void_p(text_address), buffer,
|
||||
virtual_size, ctypes.byref(ctypes.c_size_t(0))) and characteristics & 0x00000020:
|
||||
if not any(shell in section_name.lower() for shell in self.model.shells):
|
||||
match_data[section_name] = buffer.raw
|
||||
kernel32.CloseHandle(process_handle)
|
||||
if self.start_scan(match_data):
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
+67
-52
@@ -1,5 +1,5 @@
|
||||
import os, io, sys, time, json, yara
|
||||
import numpy, onnxruntime
|
||||
import numpy, pefile, onnxruntime
|
||||
from PIL import Image, ImageShow
|
||||
|
||||
class YRScan:
|
||||
@@ -8,14 +8,17 @@ class YRScan:
|
||||
self.network = []
|
||||
|
||||
def load_rules(self, file_path):
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in [".yara", ".yar"]:
|
||||
self.rules[file_path] = yara.compile(file_path)
|
||||
elif ftype in [".yc", ".yrc"]:
|
||||
self.rules[file_path] = yara.load(file_path)
|
||||
elif ftype in [".ip", ".ips"]:
|
||||
with open(file_path, "r") as f:
|
||||
self.network += [l.strip() for l in f.readlines()]
|
||||
try:
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in [".yara", ".yar"]:
|
||||
self.rules[file_path] = yara.compile(file_path)
|
||||
elif ftype in [".yc", ".yrc"]:
|
||||
self.rules[file_path] = yara.load(file_path)
|
||||
elif ftype in [".ip", ".ips"]:
|
||||
with open(file_path, "r") as f:
|
||||
self.network += [l.strip() for l in f.readlines()]
|
||||
except:
|
||||
pass
|
||||
|
||||
def yr_scan(self, file_path):
|
||||
try:
|
||||
@@ -23,74 +26,86 @@ class YRScan:
|
||||
with open(file_path, "rb") as f:
|
||||
file_path = f.read()
|
||||
for name, rules in self.rules.items():
|
||||
if rules.match(data=file_path):
|
||||
return True
|
||||
return False
|
||||
matchs_rules = rules.match(data=file_path)
|
||||
if matchs_rules:
|
||||
return "Virus/Rules", matchs_rules
|
||||
return False, False
|
||||
except:
|
||||
return False
|
||||
return False, False
|
||||
|
||||
class DLScan:
|
||||
def __init__(self):
|
||||
self.models = {}
|
||||
self.detect = []
|
||||
self.values = 100
|
||||
self.shells = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!o',
|
||||
'cry', 'test', 'ace', 'yg', 'obr', 'tvm', 'dec', 'enc', 'b1_', 'base',
|
||||
'bss', 'clr_uef', 'cursors', 'trs_age', 'engine', 'enigma', 'protect',
|
||||
'nep', 'no_bbt', 'wpp_sf', 'retpol', 'rt', 'rwexec', 'rygs', 'poolmi',
|
||||
's:@', 'pgae', 'proxy', 'wisevec', 'segm', 'transit', 'vmp', 'extjmp',
|
||||
'upx', 'tracesup', 'res', 'lzma', 'malloc_h', 'miniex', 'ndr64', 'be',
|
||||
'mssmixer', 'wow', 'press', 'fio', 'pad', 'hexpthk', 'h~;', 'icapsec',
|
||||
'sanontcp', 'secur', 'asmstub', 'nsys_wr', 'orpc', 'pack', 'wow64svc',
|
||||
'uedbg', 'viahw', 'data', 'zk', 'fothk', 'qihoo']
|
||||
|
||||
def load_model(self, file_path):
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in [".json", ".txt"]:
|
||||
self.class_names = json.load(open(file_path, 'r'))
|
||||
self.values = self.class_names['Values']
|
||||
self.detect = self.class_names['Detect']
|
||||
available_providers = onnxruntime.get_available_providers()
|
||||
preferred_providers = [
|
||||
'CUDAExecutionProvider', 'ROCmExecutionProvider',
|
||||
'OpenVINOExecutionProvider', 'DirectMLExecutionProvider',
|
||||
'AzureExecutionProvider', 'CPUExecutionProvider']
|
||||
providers = [p for p in preferred_providers if p in available_providers]
|
||||
for model in self.class_names['Models']:
|
||||
try:
|
||||
model_path = os.path.join(os.path.dirname(file_path), model)
|
||||
try:
|
||||
self.models[model] = onnxruntime.InferenceSession(model_path, providers=providers)
|
||||
except Exception as e:
|
||||
providers = ['CPUExecutionProvider']
|
||||
self.models[model] = onnxruntime.InferenceSession(model_path, providers=providers)
|
||||
except:
|
||||
pass
|
||||
|
||||
def dl_scan(self, file_path):
|
||||
try:
|
||||
if isinstance(file_path, str):
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in self.class_names['Suffix']:
|
||||
with open(file_path, 'rb') as f:
|
||||
file_path = f.read()
|
||||
else:
|
||||
return False, False
|
||||
target_size, sim = tuple(self.class_names['Pixels']), {}
|
||||
image = self.preprocess_image(file_path, target_size)
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in [".json", ".txt"]:
|
||||
with open(file_path, 'r') as f:
|
||||
self.class_names = json.load(f)
|
||||
elif ftype in [".onnx"]:
|
||||
self.models[file_path] = onnxruntime.InferenceSession(file_path)
|
||||
self.labels = self.class_names['Labels']
|
||||
self.detect = self.class_names['Detect']
|
||||
self.pixels = self.class_names['Pixels']
|
||||
self.values = self.class_names['Values']
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def dl_scan(self, file_data):
|
||||
try:
|
||||
target_size, sim = tuple(self.pixels), {}
|
||||
image = self.preprocess_image(file_data, target_size)
|
||||
image_array = numpy.array(image).astype('float32') / 255.0
|
||||
image_expand = numpy.expand_dims(image_array, axis=0)
|
||||
for model_name, model in self.models.items():
|
||||
input_name = model.get_inputs()[0].name
|
||||
pre_answer = model.run(None, {input_name: image_expand})[0][0]
|
||||
number = numpy.argmax(pre_answer)
|
||||
label = self.class_names['Labels'][number].replace("\n", "")
|
||||
label = self.labels[number].replace("\n", "")
|
||||
sim[label] = sim.setdefault(label, 0) + pre_answer[number]
|
||||
for local_label, sim_sum in sim.items():
|
||||
if sim[local_label] > len(self.models) / 2:
|
||||
if sim_sum > len(self.models) / 2:
|
||||
local_level = sim_sum / len(self.models)
|
||||
print(local_label, local_level * 100)
|
||||
return local_label, local_level * 100
|
||||
return False, False
|
||||
except:
|
||||
except Exception as e:
|
||||
return False, False
|
||||
|
||||
def preprocess_image(self, file_data, target_size): # New
|
||||
def get_type(self, file_path):
|
||||
try:
|
||||
match_data = {}
|
||||
ftype = str(f".{file_path.split('.')[-1]}").lower()
|
||||
if ftype in [".exe", ".dll", ".sys", ".scr", ".com"]:
|
||||
with pefile.PE(file_path, fast_load=True) as pe:
|
||||
for section in pe.sections:
|
||||
section_name = section.Name.rstrip(b'\x00').decode('latin1')
|
||||
if (section.Characteristics & 0x00000020 and not
|
||||
any(shell in section_name.lower() for shell in self.shells)):
|
||||
match_data[section_name] = section.get_data()
|
||||
elif ftype in [".bat", ".vbs", ".ps1", ".cmd", ".js"]:
|
||||
with open(file_path, 'rb') as file:
|
||||
match_data[ftype] = file.read()
|
||||
return match_data
|
||||
except:
|
||||
return {}
|
||||
|
||||
def preprocess_image(self, file_data, target_size):
|
||||
file_data = numpy.frombuffer(file_data, dtype=numpy.uint8)
|
||||
data_count = len(file_data)
|
||||
wah = int(numpy.ceil(numpy.sqrt((data_count + 2) // 3)))
|
||||
image_array = numpy.zeros((wah * wah * 3,), dtype=numpy.uint8)
|
||||
image_array[:data_count] = file_data
|
||||
image_array = image_array.reshape((wah, wah, 3))
|
||||
image = Image.fromarray(image_array) #ImageShow.show(image)
|
||||
image = Image.fromarray(image_array)
|
||||
return image.resize(target_size, Image.Resampling.LANCZOS)
|
||||
+4
-3
@@ -1,7 +1,8 @@
|
||||
slist = [".exe",".dll",".com",".msi",".scr",
|
||||
".js",".bat",".cmd",".ps1",".vbs"]
|
||||
slist = [".exe",".dll",".sys",".com",".scr",
|
||||
".bat",".ps1",".vbs",".cmd",".js"]
|
||||
|
||||
alist = [".exe",".dll",".zip",".7z",".rar",
|
||||
alist = [".exe",".dll",".sys",".com",".scr",
|
||||
".zip",".7z",".rar",".tar",".gz",
|
||||
".js",".bat",".cmd",".ps1",".vbs",
|
||||
".ppt",".pptx",".wps",".txt",".rtf",
|
||||
".pdf",".xls",".xlsx",".doc",".docx",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import pyinstaller_versionfile
|
||||
|
||||
pyinstaller_versionfile.create_versionfile(
|
||||
output_file="versionfile.txt",
|
||||
version='3.1.7',
|
||||
version='3.2.1',
|
||||
company_name="PYAS Security",
|
||||
file_description="Python Antivirus Software",
|
||||
internal_name="PYAS",
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
## Requirements
|
||||
|
||||
```
|
||||
psutil==5.9.5
|
||||
pefile==2023.2.7
|
||||
requests==2.31.0
|
||||
pyperclip==1.8.2
|
||||
pywin32==306
|
||||
PyQt5==5.15.9
|
||||
pip install psutil==5.9.5
|
||||
pip install pefile==2023.2.7
|
||||
pip install requests==2.31.0
|
||||
pip install pyperclip==1.8.2
|
||||
pip install pywin32==306
|
||||
pip install PyQt5==5.15.9
|
||||
pip install yara-python==4.5.1
|
||||
pip install numpy==2.1.1
|
||||
pip install onnxruntime==1.18.1
|
||||
pip install pillow==10.4.0
|
||||
```
|
||||
|
||||
## File Information
|
||||
|
||||
+10
-6
@@ -5,12 +5,16 @@
|
||||
## 安装要求
|
||||
|
||||
```
|
||||
psutil==5.9.5
|
||||
pefile==2023.2.7
|
||||
requests==2.31.0
|
||||
pyperclip==1.8.2
|
||||
pywin32==306
|
||||
PyQt5==5.15.9
|
||||
pip install psutil==5.9.5
|
||||
pip install pefile==2023.2.7
|
||||
pip install requests==2.31.0
|
||||
pip install pyperclip==1.8.2
|
||||
pip install pywin32==306
|
||||
pip install PyQt5==5.15.9
|
||||
pip install yara-python==4.5.1
|
||||
pip install numpy==2.1.1
|
||||
pip install onnxruntime==1.18.1
|
||||
pip install pillow==10.4.0
|
||||
```
|
||||
|
||||
## 文件信息
|
||||
|
||||
+10
-6
@@ -5,12 +5,16 @@
|
||||
## 安裝要求
|
||||
|
||||
```
|
||||
psutil==5.9.5
|
||||
pefile==2023.2.7
|
||||
requests==2.31.0
|
||||
pyperclip==1.8.2
|
||||
pywin32==306
|
||||
PyQt5==5.15.9
|
||||
pip install psutil==5.9.5
|
||||
pip install pefile==2023.2.7
|
||||
pip install requests==2.31.0
|
||||
pip install pyperclip==1.8.2
|
||||
pip install pywin32==306
|
||||
pip install PyQt5==5.15.9
|
||||
pip install yara-python==4.5.1
|
||||
pip install numpy==2.1.1
|
||||
pip install onnxruntime==1.18.1
|
||||
pip install pillow==10.4.0
|
||||
```
|
||||
|
||||
## 檔案資訊
|
||||
|
||||
Reference in new issue
Block a user