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 | ||
|
|
3c2b018d49 | ||
|
|
e221a09709 | ||
|
|
26ff4bd843 | ||
|
|
d8e28f384a | ||
|
|
65e68c3cc4 | ||
|
|
7b76ab2a59 | ||
|
|
ae2a01b463 | ||
|
|
cda022a9f4 | ||
|
|
672e48c5f8 | ||
|
|
6fbdb1354f | ||
|
|
79bc7fd443 | ||
|
|
5578dd3339 | ||
|
|
0232dbd196 | ||
|
|
d44e192eaa | ||
|
|
4f12b19cf8 | ||
|
|
392ac1b1c7 | ||
|
|
8ad175aca3 | ||
|
|
6afa58c42b | ||
|
|
8be03cf232 | ||
|
|
23ea53d3ff | ||
|
|
294f40e7ac | ||
|
|
4f5f706ee5 |
No files matched your search
@@ -1,11 +0,0 @@
|
||||
[hollows_hunter]
|
||||
|
||||
https://github.com/hasherezade/hollows_hunter/releases
|
||||
|
||||
[pe_sieve]
|
||||
|
||||
https://github.com/hasherezade/pe-sieve/releases
|
||||
|
||||
[bitdefender]
|
||||
|
||||
https://github.com/87owo/bdc/tree/main/bitdefender
|
||||
@@ -1 +1,9 @@
|
||||
{"Unknown": [59361295766927921263572072001677546892988818127554310688483531901728654248638, 110146453841778647644166243240178520536267161301604245683743524756419353678059], "White": [37818885244835446256584092883046666135310645230383968345516924743398787357048, 10034220084157156036025657182253677958809969876761493145101084060869839222562, 30518116137695254451083185640456062095466770588446551409776635626107619414618, 32296846483328285395942578479721462990874016817205213442337788571183455371823, 7830743514133643609056906037298883461849915236781505447055526355864156291200, 66766369194849842633273514861399590319048611179974316399223444661664643713116, 18024800263813114636032380772014473234719112317372083568645028513107740333097, 74141606019826610219493597417961411759319222262715747781530975858236840023868, 74141606019826815907563358349687985248520689328534980167895213718026559231805, 84904953027467628079124577278247620589188804906104233927770018096001490752110, 8646406253524489099322407463506197113190436222475229989113834496391933123177, 14801368362037157341349744372212469879911751347796432685445396742546138510527, 15894490895528857350444326816435305421376809085313851765402083488609039987721, 37852894007605849489952583567731004955434986444474399453030571998864861533218, 16007569107674673947537681801726481062730991620317178346097127572834907239433, 102633388988062357389851477595292272698878804202828382582477913233599597957741, 17029311058216545115926699358460765117955315322529387410067408192737238368209, 39401039939065971500355367115014580663179206620663500436171381542235009920591, 39402615232602811526308130026613523510869149389568467968898508123483647642239, 57593384293411341144654776428448217689576185693893444758365608040444018144505, 63841662487000088869831851027369141702999289853288215195372474540672652085448, 100721919041136871706536474323993763361887751761059594887258624287814536108709, 12431907255329162502980182262719209577155616944639082427720737656418745431535, 16038275485812550557063681634389014806352822616164076985257408379680031643065, 68405324198120933521050931648638618947369327745692667495883448104257901548799, 3460329908515126754637554126738713109961637027606158804093048546688108127547, 16106981637946225230178918605857052277649628614369112854963742434861832205050, 8448811436767749824740074881636806461590780110247030409064405873065872770413, 62657160528879197025196349384429226461581551965396254612319502660762849907110, 37362668350600312578741767096565745429284532702326298726894669202918919902841, 97046915551360110482543666063995603342646642693483132604859660767038789191075, 37750578778823141127513876578977618263821979566798398805475475810686050547035, 8899077763068952446283397850676779377182951563966752995966724510608273388087, 1430788410790588948768223740715242946047023771808936478434300982280927461576, 43245632164876912500721802614250505089424972269458388051200703985150176517646, 26527792976855638931546424443043598748359981077520025569533358689339312846119, 10034220138179482424453837496189500567990928858614529504432172551818139334184, 75535532059353249758793259643426543087630044975480683666280772562494352167023, 12532294779822530931293583148085641907686342350743362041338935273017351016633, 8958249342307639770700867008480561646791855695021266630701977360245761685282, 75528466396530722925390012197706855368372892751585509291513494409511440650351, 9011044384631604789230921306476923910566615376824882388358022480957734033082, 45182323877874305146934038679574733861884144375370883472937974036860962247097, 23700234601492692370460015976854345996007097410933046970328742403104651126256, 56970414078810407267232512181524454646035403709151864648837102879926562472603, 59336812026319177033098081135706956314151111314270392143237555422332208264206, 36707091377963660336346311143415935299335610930952028052854530836452557240295, 10202126012237964170766432051989140199469409759127192355002576100131006440555, 72691028651131468636833670875287650881223005399741112439972503306595446550906, 7689046024044190685500958862986168840617876576117297404374223308117258686587, 9583067470336071575558967777508800030690386213881092335354663342137641199143, 15970718419268871463478468058858796238959885761999117728999272834817179322168, 37903470032839160921304992353748519593005839718701840574746932332397170697534, 10723799110029366222468551244518699011059498785302648324191607904247307866219, 1651465247876746049352538052494320238190633259932155654005236273442992146011, 37535310575907540138572260167287591050679295649847144262742970882242576643629, 107406046477759675380805009872206073473308094017534113788736360913659778137364, 8648260909849054742383860213694016683253742610217956634993385753930945566715, 91094487239729265765473251155982579898413742412111963107157224383047507474015, 45128834383092335423669974709008139367933699120247789381146368929605724538431, 21573189465171437665670533096295878202170520697880590329439115191190251349169, 776778Line truncated
|
||||
{
|
||||
"Labels": ["White/Pefile", "White/Script", "Virus/Pefile", "Virus/Script"],
|
||||
|
||||
"Detect": ["Virus/Pefile", "Virus/Script"],
|
||||
|
||||
"Pixels": [224, 224],
|
||||
|
||||
"Values": 95
|
||||
}
|
||||
Binary file not shown.
@@ -1,12 +1,10 @@
|
||||
import os, gc, sys, time, json, yara
|
||||
import pefile, socket, msvcrt, psutil
|
||||
import requests, pyperclip, win32file
|
||||
import win32gui, win32api, win32con
|
||||
from PYAS_Engine import ListSimHash
|
||||
import os, gc, sys, time, json, psutil
|
||||
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
|
||||
from PYAS_Interface import Ui_MainWindow
|
||||
from PYAS_Extension import ExtenRules
|
||||
from threading import Thread
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
@@ -15,25 +13,14 @@ from subprocess import *
|
||||
|
||||
class MainWindow_Controller(QMainWindow):
|
||||
def __init__(self):
|
||||
# init program window
|
||||
super(MainWindow_Controller, self).__init__()
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
self.setWindowFlags(Qt.FramelessWindowHint)
|
||||
|
||||
# get self program path
|
||||
self.pyas = sys.argv[0].replace("\\", "/")
|
||||
self.dir = os.path.dirname(self.pyas)
|
||||
exdir = os.path.join(self.dir, "Exten")
|
||||
self.exdir = exdir.replace("\\", "/")
|
||||
|
||||
# init self program version
|
||||
self.pyae_version = "Fusion Engine"
|
||||
self.pyas_version = "3.1.5"
|
||||
|
||||
# startup ui config
|
||||
self.pyae_version = "AI Engine"
|
||||
self.pyas_version = "3.2.1"
|
||||
self.first_startup = True
|
||||
|
||||
# init program config
|
||||
self.init_data_base()
|
||||
self.init_tray_icon()
|
||||
self.init_config_qtui()
|
||||
@@ -44,18 +31,14 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.init_startup()
|
||||
|
||||
def init_threads(self):
|
||||
# init protect thread
|
||||
self.protect_proc_init()
|
||||
self.protect_file_init()
|
||||
self.protect_sys_init()
|
||||
self.protect_drv_init()
|
||||
self.protect_net_init()
|
||||
|
||||
# init tools thread
|
||||
self.block_window_init()
|
||||
|
||||
def init_tray_icon(self):
|
||||
# init taskbar tray and icon
|
||||
self.tray_icon = QSystemTrayIcon(self)
|
||||
self.tray_icon.activated.connect(self.init_show_pyas)
|
||||
self.tray_icon.setIcon(QFileIconProvider().icon(QFileInfo(self.pyas)))
|
||||
@@ -63,70 +46,45 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def init_startup(self):
|
||||
try:
|
||||
# check startup ui args
|
||||
if len(sys.argv) > 1:
|
||||
param = sys.argv[1]
|
||||
if "h" not in param:
|
||||
self.init_show_pyas()
|
||||
elif len(sys.argv) <= 1:
|
||||
self.init_show_pyas()
|
||||
|
||||
# startup ui complete
|
||||
self.first_startup = False
|
||||
except:
|
||||
pass
|
||||
|
||||
def init_data_base(self):
|
||||
try:
|
||||
# init exten path ./Exten/* (from import)
|
||||
self.exten = ExtenRules()
|
||||
|
||||
# init model path ./Model/* (from import)
|
||||
self.model = ListSimHash()
|
||||
data_path = os.path.join(self.dir, "Model")
|
||||
self.model = DLScan()
|
||||
data_path = os.path.join(self.dir, "Model")
|
||||
for root, dirs, files in os.walk(data_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
if ftype in [".json",".txt"]:
|
||||
# SimHash model json file
|
||||
self.model.load_model(file_path)
|
||||
|
||||
# init yara path ./Rules/* (from import)
|
||||
self.rules = {}
|
||||
self.model.load_model(file_path)
|
||||
self.rules = YRScan()
|
||||
data_path = os.path.join(self.dir, "Rules")
|
||||
for root, dirs, files in os.walk(data_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
if ftype in [".yara", ".yar"]:
|
||||
# not compile yara rules
|
||||
rules = yara.compile(file_path)
|
||||
elif ftype in [".yc", ".yrc"]:
|
||||
# compiled yara rules
|
||||
rules = yara.load(file_path)
|
||||
self.rules[file_path] = rules
|
||||
self.rules.load_rules(file_path)
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
|
||||
def init_config_boot(self):
|
||||
try:
|
||||
# init read system boot
|
||||
with open(r"\\.\PhysicalDrive0", "r+b") as f:
|
||||
# backup system mbr value
|
||||
self.mbr_value = f.read(512)
|
||||
|
||||
# check if mbr is available
|
||||
if self.mbr_value[510:512] != b'\x55\xAA':
|
||||
self.mbr_value = False
|
||||
except Exception as e:
|
||||
# possible permission denied
|
||||
self.mbr_value = False
|
||||
self.bug_event(self.trans(f"引導防護錯誤: ")+str(e))
|
||||
|
||||
def write_config(self, config):
|
||||
try:
|
||||
# write json configs in ProgramData
|
||||
with open("C:/ProgramData/PYAS/PYAS.json", "w") as f:
|
||||
f.write(json.dumps(config, indent=4, ensure_ascii=False))
|
||||
except Exception as e:
|
||||
@@ -134,57 +92,42 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def init_config_read(self):
|
||||
try:
|
||||
# init check exist process
|
||||
self.track_proc = None
|
||||
self.exist_process = set()
|
||||
for p in psutil.process_iter():
|
||||
self.exist_process.add(p.pid)
|
||||
|
||||
# check config path exists
|
||||
if not os.path.exists("C:/ProgramData/PYAS"):
|
||||
os.makedirs("C:/ProgramData/PYAS")
|
||||
|
||||
# check config file exists
|
||||
if not os.path.exists("C:/ProgramData/PYAS/PYAS.json"):
|
||||
self.write_config({"language":"en_US","theme_color":"White",
|
||||
"high_sensitive":0,"extension_kits":0,"cloud_services":"None"})
|
||||
try:
|
||||
# read config json data
|
||||
with open("C:/ProgramData/PYAS/PYAS.json", "r") as f:
|
||||
self.json = json.load(f)
|
||||
except:
|
||||
self.json = {"language":"en_US","theme_color":"White",
|
||||
"high_sensitive":0,"extension_kits":0,"cloud_services":"None"}
|
||||
|
||||
# default json config
|
||||
self.json["language"] = self.json.get("language", "en_US")
|
||||
self.json["theme_color"] = self.json.get("theme_color", "White")
|
||||
self.json["high_sensitive"] = self.json.get("high_sensitive", 0)
|
||||
self.json["extension_kits"] = self.json.get("extension_kits", 0)
|
||||
self.json["cloud_services"] = self.json.get("cloud_services", "None")
|
||||
|
||||
# reflash high_sensitive ui text
|
||||
if self.json["high_sensitive"] == 1:
|
||||
self.ui.high_sensitivity_switch_Button.setText(self.trans("已開啟"))
|
||||
self.ui.high_sensitivity_switch_Button.setStyleSheet("""
|
||||
QPushButton{border:none;background-color:rgb(200, 250, 200);border-radius: 10px;}
|
||||
QPushButton:hover{background-color:rgb(210, 250, 210);}""")
|
||||
|
||||
if self.json["extension_kits"] == 1:
|
||||
self.ui.extension_kit_switch_Button.setText(self.trans("已開啟"))
|
||||
self.ui.extension_kit_switch_Button.setStyleSheet("""
|
||||
QPushButton{border:none;background-color:rgb(200, 250, 200);border-radius: 10px;}
|
||||
QPushButton:hover{background-color:rgb(210, 250, 210);}""")
|
||||
|
||||
# reflash language ui setChecked
|
||||
if self.json["language"] == "zh_TW":
|
||||
self.ui.Language_Traditional_Chinese.setChecked(True)
|
||||
elif self.json["language"] == "zh_CN":
|
||||
self.ui.Language_Simplified_Chinese.setChecked(True)
|
||||
elif self.json["language"] == "en_US":
|
||||
self.ui.Language_English.setChecked(True)
|
||||
|
||||
# reflash theme_color ui setChecked
|
||||
if self.json["theme_color"] == "White":
|
||||
self.ui.Theme_White.setChecked(True)
|
||||
elif self.json["theme_color"] == "Red":
|
||||
@@ -197,14 +140,10 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Theme_Blue.setChecked(True)
|
||||
elif os.path.exists(self.json["theme_color"]):
|
||||
self.ui.Theme_Customize.setChecked(True)
|
||||
|
||||
# read whitelist lines from ProgramData
|
||||
self.whitelist = []
|
||||
if os.path.exists("C:/ProgramData/PYAS/Whitelist.ini"):
|
||||
with open("C:/ProgramData/PYAS/Whitelist.ini", "r") as f:
|
||||
self.whitelist = [l.strip() for l in f.readlines()]
|
||||
|
||||
# read blocklist lines from ProgramData
|
||||
self.blocklist = []
|
||||
if os.path.exists("C:/ProgramData/PYAS/Blocklist.ini"):
|
||||
with open("C:/ProgramData/PYAS/Blocklist.ini", "r") as f:
|
||||
@@ -213,7 +152,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.bug_event(e)
|
||||
|
||||
def init_control(self):
|
||||
# connect main ui and function control
|
||||
self.ui.Close_Button.clicked.connect(self.close)
|
||||
self.ui.Minimize_Button.clicked.connect(self.showMinimized)
|
||||
self.ui.Menu_Button.clicked.connect(self.show_menu)
|
||||
@@ -221,8 +159,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Tools_Button.clicked.connect(self.change_tools_widget)
|
||||
self.ui.Virus_Scan_Button.clicked.connect(self.change_scan_widget)
|
||||
self.ui.Protection_Button.clicked.connect(self.change_protect_widget)
|
||||
|
||||
# connect scan ui and function control
|
||||
self.ui.Virus_Scan_output.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.ui.Virus_Scan_output.customContextMenuRequested.connect(self.Virus_Scan_output_menu)
|
||||
self.ui.Virus_Scan_Solve_Button.clicked.connect(self.virus_solve)
|
||||
@@ -231,8 +167,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.File_Scan_Button.clicked.connect(self.file_scan)
|
||||
self.ui.Path_Scan_Button.clicked.connect(self.path_scan)
|
||||
self.ui.Disk_Scan_Button.clicked.connect(self.disk_scan)
|
||||
|
||||
# connect tools ui and function control
|
||||
self.ui.System_Process_Manage_Button.clicked.connect(lambda:self.change_tools(self.ui.Process_widget))
|
||||
self.ui.Process_Tools_Back.clicked.connect(lambda:self.back_to_tools(self.ui.Process_widget))
|
||||
self.ui.Repair_System_Files_Button.clicked.connect(self.repair_system)
|
||||
@@ -243,15 +177,11 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Process_list.customContextMenuRequested.connect(self.process_list_menu)
|
||||
self.ui.About_Back.clicked.connect(self.ui.About_widget.hide)
|
||||
self.ui.Setting_Back.clicked.connect(self.setting_back)
|
||||
|
||||
# connect protect ui and function control
|
||||
self.ui.Protection_switch_Button.clicked.connect(self.protect_proc_init)
|
||||
self.ui.Protection_switch_Button_2.clicked.connect(self.protect_file_init)
|
||||
self.ui.Protection_switch_Button_3.clicked.connect(self.protect_sys_init)
|
||||
self.ui.Protection_switch_Button_4.clicked.connect(self.protect_drv_init)
|
||||
self.ui.Protection_switch_Button_5.clicked.connect(self.protect_net_init)
|
||||
|
||||
# connect settings ui and function control
|
||||
self.ui.high_sensitivity_switch_Button.clicked.connect(self.change_sensitive)
|
||||
self.ui.extension_kit_switch_Button.clicked.connect(self.extension_kit)
|
||||
self.ui.Add_White_list_Button.clicked.connect(self.add_white_list)
|
||||
@@ -266,20 +196,13 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Theme_Red.clicked.connect(self.init_theme_color)
|
||||
|
||||
def init_config_qtui(self):
|
||||
# connect ui and variable control
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
# init virus scan list
|
||||
self.virus_lock = {}
|
||||
self.virus_list = []
|
||||
self.virus_list_ui = []
|
||||
|
||||
# init process tools list
|
||||
self.Process_quantity = []
|
||||
self.Process_list_all_pid = []
|
||||
|
||||
# connect effect ui and variable
|
||||
self.Process_sim = QStringListModel()
|
||||
self.Process_Timer = QTimer()
|
||||
self.Process_Timer.timeout.connect(self.process_list)
|
||||
@@ -313,34 +236,27 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.About_widget.hide()
|
||||
self.ui.State_output.style().polish(self.ui.State_output.verticalScrollBar())
|
||||
self.ui.Virus_Scan_output.style().polish(self.ui.Virus_Scan_output.verticalScrollBar())
|
||||
|
||||
# PYAS License_terms
|
||||
self.ui.License_terms.setText('''Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''')
|
||||
|
||||
def init_change_lang(self):
|
||||
try:
|
||||
# change lang function with init or clicked
|
||||
if self.ui.Language_Traditional_Chinese.isChecked():
|
||||
self.json["language"] = "zh_TW"
|
||||
elif self.ui.Language_Simplified_Chinese.isChecked():
|
||||
self.json["language"] = "zh_CN"
|
||||
elif self.ui.Language_English.isChecked():
|
||||
self.json["language"] = "en_US"
|
||||
|
||||
# write lang config and set lang text
|
||||
self.write_config(self.json)
|
||||
self.init_lang_text()
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
|
||||
def trans(self, text):
|
||||
# from PYAS_Language import translate_dict
|
||||
for k, v in translate_dict.get(self.json["language"], translate_dict).items():
|
||||
text = text.replace(str(k), str(v))
|
||||
return text
|
||||
|
||||
def init_lang_text(self):
|
||||
# original init language "zh_TW"
|
||||
self.ui.State_title.setText(self.trans("此裝置已受到防護"))
|
||||
self.ui.Window_title.setText(self.trans(f"PYAS Security"))
|
||||
self.ui.PYAS_CopyRight.setText(self.trans(f"Copyright© 2020-{max(int(time.strftime('%Y')), 2020)} PYAS Security"))
|
||||
@@ -381,7 +297,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Window_Block_Button.setText(self.trans("軟體彈窗攔截"))
|
||||
self.ui.Repair_System_Network_Button.setText(self.trans("系統網路修復"))
|
||||
self.ui.About_Back.setText(self.trans("返回"))
|
||||
self.ui.PYAS_Version.setText(self.trans(f"PYAS V{self.pyas_version} ({self.pyae_version})"))
|
||||
self.ui.PYAS_Version.setText(self.trans(f"PYAS Security V{self.pyas_version} ({self.pyae_version})"))
|
||||
self.ui.GUI_Made_title.setText(self.trans("介面製作:"))
|
||||
self.ui.GUI_Made_Name.setText(self.trans("mtkiao"))
|
||||
self.ui.Core_Made_title.setText(self.trans("核心製作:"))
|
||||
@@ -415,7 +331,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def init_theme_color(self):
|
||||
try:
|
||||
# set theme color (Maybe it can be further optimized?)
|
||||
if self.ui.Theme_White.isChecked():
|
||||
self.json["theme_color"] = "White"
|
||||
self.ui.State_icon.setPixmap(QPixmap(":/icon/Check.png"))
|
||||
@@ -442,7 +357,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Window_widget.setStyleSheet("QWidget#Window_widget {background-color:rgb(250,250,230);}")
|
||||
self.ui.Navigation_Bar.setStyleSheet("QWidget#Navigation_Bar {background-color:rgb(250,250,220);}")
|
||||
elif self.ui.Theme_Customize.isChecked():
|
||||
# check customize theme config
|
||||
if not os.path.exists(os.path.join(self.json["theme_color"],"Color.ini")):
|
||||
path = str(QFileDialog.getExistingDirectory(self,self.trans("自定主題"),"C:/"))
|
||||
if path and os.path.exists(os.path.join(path,"Color.ini")):
|
||||
@@ -453,10 +367,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Navigation_Bar.setStyleSheet(self.themecolor[1])
|
||||
file = os.path.join(self.json["theme_color"],"Check.png")
|
||||
self.ui.State_icon.setPixmap(QPixmap(file))
|
||||
# write theme color config
|
||||
self.write_config(self.json)
|
||||
except:
|
||||
# set default theme color when error
|
||||
self.ui.Theme_White.setChecked(True)
|
||||
self.json["theme_color"] = "White"
|
||||
self.ui.State_icon.setPixmap(QPixmap(":/icon/Check.png"))
|
||||
@@ -464,7 +376,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ui.Navigation_Bar.setStyleSheet("QWidget#Navigation_Bar {background-color:rgb(230,230,230);}")
|
||||
|
||||
def change_animation(self,widget):
|
||||
# animation for widget
|
||||
x, y = 170, widget.pos().y()
|
||||
self.anim = QPropertyAnimation(widget, b"geometry")
|
||||
widget.setGeometry(QRect(x - 100,y, 671, 481))
|
||||
@@ -475,7 +386,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.anim.start()
|
||||
|
||||
def change_animation_2(self,nx,ny):
|
||||
# animation for scroll bar
|
||||
x, y = self.ui.label.pos().x(), self.ui.label.pos().y()
|
||||
self.anim2 = QPropertyAnimation(self.ui.label, b"geometry")
|
||||
if y > ny:
|
||||
@@ -495,7 +405,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.anim2.start()
|
||||
|
||||
def change_animation_3(self,widget,time):
|
||||
# animation for OpacityEffect
|
||||
self.opacity = QGraphicsOpacityEffect()
|
||||
self.opacity.setOpacity(0)
|
||||
self.opacity.i = self.opacity.opacity()
|
||||
@@ -737,18 +646,20 @@ 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
|
||||
|
||||
def send_notify(self, text):
|
||||
def send_notify(self, text, notify_bar=True):
|
||||
try:
|
||||
# send system notification
|
||||
now_time = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
print(f"[Notify] > [{now_time}] {text}")
|
||||
if self.first_startup != True:
|
||||
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)
|
||||
QMetaObject.invokeMethod(self.ui.State_output, "append", Qt.QueuedConnection, Q_ARG(str, f"[{now_time}] {text}"))
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -824,23 +735,6 @@ class MainWindow_Controller(QMainWindow):
|
||||
QPushButton:hover{background-color:rgb(210,250,210);}""")
|
||||
self.write_config(self.json)
|
||||
|
||||
def cloud_service(self):
|
||||
try:
|
||||
# cloud services config /ProgramData/PYAS.json
|
||||
if self.json["cloud_services"] != "None":
|
||||
# upload file cloud services
|
||||
file = str(QFileDialog.getOpenFileName(self,self.trans("上報雲端分析"),"C:/")[0]).replace("\\", "/")
|
||||
if file and self.question_event("您確定要上報雲端分析嗎?"):
|
||||
response = requests.post(self.json["cloud_services"], files={'file': open(file, 'rb')})
|
||||
if response.status_code == 200:
|
||||
self.info_event(f"成功上報雲端分析: "+file)
|
||||
else:
|
||||
self.bug_event(response.status_code)
|
||||
else:
|
||||
self.bug_event(self.trans("未選擇雲端服務網站"))
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
|
||||
def init_scan(self):
|
||||
try:
|
||||
self.ui.Virus_Scan_text.setText(self.trans("正在初始化中"))
|
||||
@@ -896,18 +790,23 @@ class MainWindow_Controller(QMainWindow):
|
||||
try:
|
||||
# delete file
|
||||
if self.ui.Virus_Scan_output.findItems(file, Qt.MatchContains)[0].checkState() == Qt.Checked:
|
||||
self.ui.Virus_Scan_title.setText(self.trans("正在刪除"))
|
||||
self.ui.Virus_Scan_text.setText(file)
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_title, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("正在刪除")))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_text, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, file))
|
||||
QApplication.processEvents()
|
||||
self.lock_file(file, False)
|
||||
self.ransom_counts = 0
|
||||
os.remove(file)
|
||||
else:
|
||||
self.lock_file(file, False)
|
||||
except:
|
||||
continue
|
||||
self.ui.Virus_Scan_output.clear()
|
||||
self.ui.Virus_Scan_title.setText(self.trans("病毒掃描"))
|
||||
self.ui.Virus_Scan_text.setText(self.trans("刪除成功"))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_title, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("病毒掃描")))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_text, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("刪除成功")))
|
||||
except Exception as e:
|
||||
self.bug_event(e)
|
||||
|
||||
@@ -927,7 +826,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def answer_scan(self):
|
||||
try:
|
||||
self.ui.Virus_Scan_title.setText(self.trans("病毒掃描"))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_title, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("病毒掃描")))
|
||||
if self.virus_list:
|
||||
self.ui.Virus_Scan_Solve_Button.show()
|
||||
self.ui.Virus_Scan_Break_Button.hide()
|
||||
@@ -937,7 +837,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.virus_scan_break()
|
||||
text = self.trans("當前未發現病毒")
|
||||
self.scan_thread.join()
|
||||
self.ui.Virus_Scan_text.setText(text)
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_text, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, text))
|
||||
self.send_notify(text)
|
||||
gc.collect()
|
||||
except Exception as e:
|
||||
@@ -947,8 +848,10 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.scan_file = False
|
||||
self.ui.Virus_Scan_Break_Button.hide()
|
||||
self.ui.Virus_Scan_choose_Button.show()
|
||||
self.ui.Virus_Scan_text.setText(self.trans("請選擇掃描方式"))
|
||||
self.ui.Virus_Scan_title.setText(self.trans("病毒掃描"))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_title, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("病毒掃描")))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_text, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("請選擇掃描方式")))
|
||||
|
||||
def virus_scan_menu(self):
|
||||
if self.ui.Virus_Scan_choose_widget.isHidden():
|
||||
@@ -962,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()
|
||||
@@ -1008,8 +912,10 @@ class MainWindow_Controller(QMainWindow):
|
||||
elif os.path.isdir(file):
|
||||
self.traverse_path(file)
|
||||
elif file != self.pyas and file not in self.whitelist:
|
||||
self.ui.Virus_Scan_title.setText(self.trans("正在掃描"))
|
||||
self.ui.Virus_Scan_text.setText(file)
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_title, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, self.trans("正在掃描")))
|
||||
QMetaObject.invokeMethod(self.ui.Virus_Scan_text, "setText",
|
||||
Qt.QueuedConnection, Q_ARG(str, file))
|
||||
self.write_scan(self.start_scan(file),file)
|
||||
gc.collect()
|
||||
except:
|
||||
@@ -1017,62 +923,19 @@ class MainWindow_Controller(QMainWindow):
|
||||
|
||||
def start_scan(self, file):
|
||||
try:
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
label, level = self.pe_scan(file)
|
||||
if label and "Unknown" == label:
|
||||
if self.rule_scan(file):
|
||||
return "Rules"
|
||||
elif label and "White" != label:
|
||||
if self.json["high_sensitive"]:
|
||||
return label
|
||||
elif level and level >= 1.0:
|
||||
return label
|
||||
elif self.rule_scan(file):
|
||||
return "Rules"
|
||||
elif not label and ftype in slist:
|
||||
if self.rule_scan(file):
|
||||
return "Rules"
|
||||
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.exten.bdc_scan(file):
|
||||
return "Exten"
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def pe_scan(self, file):
|
||||
try:
|
||||
fn = []
|
||||
with pefile.PE(file, fast_load=True) as pe:
|
||||
pe.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT']])
|
||||
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
for func in entry.imports:
|
||||
if func.name:
|
||||
try:
|
||||
fn.append(str(func.name, "utf-8"))
|
||||
except:
|
||||
pass
|
||||
if fn:
|
||||
QApplication.processEvents()
|
||||
return self.model.predict(fn)
|
||||
return False, False
|
||||
except:
|
||||
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 rule_scan(self, file):
|
||||
try:
|
||||
with open(file, "rb") as f:
|
||||
data = f.read()
|
||||
for name, rules in self.rules.items():
|
||||
QApplication.processEvents()
|
||||
if rules.match(data=data):
|
||||
return True
|
||||
return self.rules.yr_scan(file)[0]
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
@@ -1216,6 +1079,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.traverse_temp(file)
|
||||
else:
|
||||
file_size = os.path.getsize(file)
|
||||
self.ransom_counts = 0
|
||||
os.remove(file)
|
||||
self.total_deleted_size += file_size
|
||||
except:
|
||||
@@ -1244,8 +1108,8 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.block_window = False
|
||||
if self.question_event("請選擇要攔截的軟體彈窗"):
|
||||
while not self.block_window:
|
||||
window_name = str(win32gui.GetWindowText(win32gui.GetForegroundWindow()))
|
||||
QApplication.processEvents()
|
||||
window_name = str(win32gui.GetWindowText(win32gui.GetForegroundWindow()))
|
||||
if window_name not in ["","PYAS",self.trans("警告")]:
|
||||
if window_name not in self.blocklist:
|
||||
if self.question_event(f"您確定要攔截 {window_name} 嗎?"):
|
||||
@@ -1446,6 +1310,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
for pid in new_process - self.exist_process:
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
self.lock_process(p, True)
|
||||
self.handle_new_process(p)
|
||||
self.lock_process(p, False)
|
||||
gc.collect()
|
||||
@@ -1453,47 +1318,87 @@ class MainWindow_Controller(QMainWindow):
|
||||
pass
|
||||
self.exist_process = new_process
|
||||
if self.ui.Protection_switch_Button.text() == self.trans("已開啟"):
|
||||
self.send_notify(self.trans(f"竄改警告: self.proc_protect"))
|
||||
self.send_notify(self.trans(f"竄改警告: self.proc_protect"), False)
|
||||
|
||||
def handle_new_process(self, p):
|
||||
try:
|
||||
name, file, cmd = p.name(), p.exe().replace("\\", "/"), p.cmdline()
|
||||
if file != self.pyas and self.exdir not in file and file not in self.whitelist:
|
||||
self.lock_process(p, True)
|
||||
if file != self.pyas and file not in self.whitelist:
|
||||
if "powershell" in name:
|
||||
target = str(cmd[-1].split("'")[-2]).replace("\\", "/")
|
||||
if os.path.exists(target) and self.start_scan(target):
|
||||
self.kill_process("腳本攔截", p, target, False)
|
||||
elif os.path.exists(target) and ":/Windows" not in target:
|
||||
self.track_proc = p, target, True
|
||||
file = str(cmd[-1].split("'")[-2]).replace("\\", "/")
|
||||
elif "cmd.exe" in name:
|
||||
target = str(" ".join(cmd[2:])).replace("\\", "/")
|
||||
if os.path.exists(target) and self.start_scan(target):
|
||||
self.kill_process("腳本攔截", p, target, False)
|
||||
elif os.path.exists(target) and ":/Windows" not in target:
|
||||
self.track_proc = p, target, True
|
||||
file = str(" ".join(cmd[2:])).replace("\\", "/")
|
||||
elif ":/Windows" in file:
|
||||
target = str(cmd[-1]).replace("\\", "/")
|
||||
if os.path.exists(target) and self.start_scan(target):
|
||||
self.kill_process("鏈式攔截", p, target, False)
|
||||
elif ":/Windows" not in file:
|
||||
if os.path.exists(file) and self.start_scan(file):
|
||||
self.kill_process("進程攔截", p, file, False)
|
||||
elif self.json["extension_kits"] and self.exten.pe_sieve(p):
|
||||
self.kill_process("記憶體攔截", p, file, False)
|
||||
elif ":/Program" not in file and not self.load_scan(p):
|
||||
file = str(cmd[-1]).replace("\\", "/")
|
||||
if self.start_scan(file):
|
||||
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:
|
||||
ftype = str(f".{file.split('.')[-1]}").lower()
|
||||
if os.path.exists(file) and ftype in slist:
|
||||
self.track_proc = p, file, True
|
||||
self.lock_process(p, False)
|
||||
except:
|
||||
self.lock_process(p, False)
|
||||
pass
|
||||
|
||||
def load_scan(self, p):
|
||||
try:
|
||||
for entry in p.memory_maps():
|
||||
target = str(entry.path).replace("\\", "/")
|
||||
if ":/Windows" not in target and self.start_scan(target):
|
||||
self.kill_process("加載攔截", p, target, False)
|
||||
return True
|
||||
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()
|
||||
if ftype not in [".exe"] and self.start_scan(file):
|
||||
return True
|
||||
return False
|
||||
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:
|
||||
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
|
||||
@@ -1504,9 +1409,9 @@ class MainWindow_Controller(QMainWindow):
|
||||
else:
|
||||
p.resume()
|
||||
|
||||
def kill_process(self, info, p, target, relation=False):
|
||||
def kill_process(self, info, p, target, relation):
|
||||
try:
|
||||
target = target.replace("/", "\\")
|
||||
target = target.replace("\\", "/")
|
||||
if relation == False:
|
||||
p.kill()
|
||||
elif relation == True:
|
||||
@@ -1517,13 +1422,13 @@ class MainWindow_Controller(QMainWindow):
|
||||
file = str(cmd[-1].split("'")[-2])
|
||||
elif "cmd.exe" in name:
|
||||
file = str(" ".join(cmd[2:]))
|
||||
elif ":/Windows" in file:
|
||||
elif ":/Windows" in file.replace("\\", "/"):
|
||||
file = str(cmd[-1])
|
||||
if target == file.replace("\\", "/"):
|
||||
p.kill()
|
||||
except:
|
||||
pass
|
||||
self.send_notify(self.trans(f"{info}: ")+target)
|
||||
self.send_notify(self.trans(f"{info}: ")+target, True)
|
||||
self.track_proc = None
|
||||
except:
|
||||
self.track_proc = None
|
||||
@@ -1549,13 +1454,15 @@ class MainWindow_Controller(QMainWindow):
|
||||
self.ransom_counts += 1
|
||||
elif action == 4 and ftype in alist:
|
||||
self.ransom_counts += 1
|
||||
if action == 3 and ftype in slist and self.start_scan(fpath):
|
||||
os.remove(fpath)
|
||||
self.send_notify(self.trans("病毒刪除: ")+fpath)
|
||||
if ":/Windows" not in fpath and ftype in slist:
|
||||
if action == 3 and self.start_scan(fpath):
|
||||
self.ransom_counts = 0
|
||||
os.remove(fpath)
|
||||
self.send_notify(self.trans("病毒刪除: ")+fpath, True)
|
||||
except:
|
||||
pass
|
||||
if self.ui.Protection_switch_Button_2.text() == self.trans("已開啟"):
|
||||
self.send_notify(self.trans(f"竄改警告: self.file_protect"))
|
||||
self.send_notify(self.trans(f"竄改警告: self.file_protect"), False)
|
||||
|
||||
def protect_boot_thread(self):
|
||||
while self.sys_protect and self.mbr_value:
|
||||
@@ -1571,7 +1478,7 @@ class MainWindow_Controller(QMainWindow):
|
||||
except:
|
||||
self.kill_process("引導攔截", *self.track_proc)
|
||||
if self.ui.Protection_switch_Button_3.text() == self.trans("已開啟"):
|
||||
self.send_notify(self.trans(f"竄改警告: self.sys_protect (boot)"))
|
||||
self.send_notify(self.trans(f"竄改警告: self.sys_protect (boot)"), False)
|
||||
|
||||
def protect_reg_thread(self):
|
||||
while self.sys_protect:
|
||||
@@ -1584,21 +1491,19 @@ class MainWindow_Controller(QMainWindow):
|
||||
except:
|
||||
pass
|
||||
if self.ui.Protection_switch_Button_3.text() == self.trans("已開啟"):
|
||||
self.send_notify(self.trans(f"竄改警告: self.sys_protect (reg)"))
|
||||
self.send_notify(self.trans(f"竄改警告: self.sys_protect (reg)"), False)
|
||||
|
||||
def protect_net_thread(self):
|
||||
while self.net_protect:
|
||||
try:
|
||||
time.sleep(0.2)
|
||||
local = socket.gethostbyname(socket.gethostname())
|
||||
for conn in self.track_proc.connections():
|
||||
if ":/Windows" not in file and ":/Program" not in file:
|
||||
if conn.laddr.ip == local:
|
||||
self.kill_process("網路攔截", *self.track_proc)
|
||||
for conn in self.track_proc[0].connections(kind='inet'):
|
||||
if conn.raddr.ip in self.rules.network:
|
||||
self.kill_process("網路攔截", *self.track_proc)
|
||||
except:
|
||||
pass
|
||||
if self.ui.Protection_switch_Button_5.text() == self.trans("已開啟"):
|
||||
self.send_notify(self.trans(f"竄改警告: self.net_protect"))
|
||||
self.send_notify(self.trans(f"竄改警告: self.net_protect"), False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||
|
||||
+102
-76
@@ -1,85 +1,111 @@
|
||||
import time, json, hashlib, numpy
|
||||
import os, io, sys, time, json, yara
|
||||
import numpy, pefile, onnxruntime
|
||||
from PIL import Image, ImageShow
|
||||
|
||||
class ListSimHash:
|
||||
class YRScan:
|
||||
def __init__(self):
|
||||
self.model = {}
|
||||
self.rules = {}
|
||||
self.network = []
|
||||
|
||||
def save_model(self, file_name):
|
||||
with open(file_name, 'w') as f:
|
||||
json.dump(self.model, f)
|
||||
print(f"\nModel Is Saved In {file_name}")
|
||||
def load_rules(self, file_path):
|
||||
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 load_model(self, model_data):
|
||||
if isinstance(model_data, str):
|
||||
with open(model_data, 'r') as f:
|
||||
model_data = json.load(f)
|
||||
self.model = model_data
|
||||
def yr_scan(self, file_path):
|
||||
try:
|
||||
if isinstance(file_path, str):
|
||||
with open(file_path, "rb") as f:
|
||||
file_path = f.read()
|
||||
for name, rules in self.rules.items():
|
||||
matchs_rules = rules.match(data=file_path)
|
||||
if matchs_rules:
|
||||
return "Virus/Rules", matchs_rules
|
||||
return False, False
|
||||
except:
|
||||
return False, False
|
||||
|
||||
def get_model(self, label):
|
||||
return self.model[label]
|
||||
class DLScan:
|
||||
def __init__(self):
|
||||
self.models = {}
|
||||
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 train_model(self, label, data, batch_size=10000):
|
||||
start = time.time()
|
||||
print(f"Convert {label}")
|
||||
if label not in self.model:
|
||||
self.model[label] = []
|
||||
for i, x in enumerate(data, 1):
|
||||
build_text = self.build_text(x, batch_size)
|
||||
self.model[label].append(build_text)
|
||||
used = "{0:.2f}".format(time.time()-start)
|
||||
prefix, suffix = f'{i}/{len(data)}:', f'{used}s'
|
||||
self.progress_bar(i, len(data), prefix, suffix)
|
||||
def load_model(self, file_path):
|
||||
try:
|
||||
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 build_text(self, content, batch_size):
|
||||
sums, batch, count = [], [], {}
|
||||
for index, char in enumerate(content):
|
||||
count[char] = count.setdefault(char, 0) + 1
|
||||
combined_input = f"{count[char]}_{char}"
|
||||
hashes = hashlib.sha256(combined_input.encode('utf-8'))
|
||||
batch.append(hashes.digest())
|
||||
if len(batch) >= batch_size:
|
||||
sums.append(self.sum_hashes(batch))
|
||||
batch = []
|
||||
if batch:
|
||||
sums.append(self.sum_hashes(batch))
|
||||
combined_sums = numpy.sum(sums, 0) > len(content) / 2
|
||||
v = numpy.packbits(combined_sums).tobytes()
|
||||
return int.from_bytes(v, 'big')
|
||||
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.labels[number].replace("\n", "")
|
||||
sim[label] = sim.setdefault(label, 0) + pre_answer[number]
|
||||
for local_label, sim_sum in sim.items():
|
||||
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 Exception as e:
|
||||
return False, False
|
||||
|
||||
def sum_hashes(self, digests):
|
||||
bitarray = numpy.unpackbits(numpy.frombuffer(b''.join(digests), dtype='>B'))
|
||||
return numpy.sum(numpy.reshape(bitarray, (-1, 256)), 0)
|
||||
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 progress_bar(self, items, total, prefix='', suffix='', length=50, fill='█'):
|
||||
percent = min(100.0, max(0.0, 100 * (items / float(total))))
|
||||
end_char = '\n' if percent >= 100 else '\r'
|
||||
percent_string = "{0:.2f}".format(percent)
|
||||
filled_length = int(length * items // total)
|
||||
bar = fill * filled_length + ' ' * (length - filled_length)
|
||||
print(f'\r{prefix: <15} |{bar}| {percent_string}% {suffix}', end=end_char)
|
||||
|
||||
def predict_all(self, query, batch_size=10000):
|
||||
label_similarities = {}
|
||||
query_hash = self.build_text(query, batch_size)
|
||||
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, batch_size=10000):
|
||||
max_similarity, max_label = 0, None
|
||||
query_hash = self.build_text(query, batch_size)
|
||||
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')
|
||||
return 1 - hamming_distance / 256
|
||||
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)
|
||||
return image.resize(target_size, Image.Resampling.LANCZOS)
|
||||
@@ -1,46 +0,0 @@
|
||||
from subprocess import Popen, PIPE
|
||||
import os, re, sys
|
||||
|
||||
class ExtenRules:
|
||||
def __init__(self):
|
||||
self.pyas = sys.argv[0].replace("\\", "/")
|
||||
self.dir = os.path.dirname(self.pyas)
|
||||
self.exten = os.path.join(self.dir, "Exten")
|
||||
|
||||
def bdc_scan(self, file):
|
||||
try:
|
||||
check_file = file.replace("\\", "/")
|
||||
if ":/Windows" not in check_file and ":/Program" not in check_file:
|
||||
cmd = f'"{self.exten}\\bitdefender\\bdc.exe" "{file}"'
|
||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True).wait()
|
||||
for match in re.finditer(r'(?P<filename>[^\s]+)\s+infected:\s+(?P<virusname>.+)', p.communicate()[0]):
|
||||
return match.groupdict()
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def hollows_hunter(self, p):
|
||||
try:
|
||||
check_file = p.exe().replace("\\", "/")
|
||||
if ":/Windows" not in check_file and ":/Program" not in check_file:
|
||||
cmd = f'"{self.exten}\\hollows_hunter\\hollows_hunter.exe" /ofilter 2 /pid "{p.pid}"'
|
||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True).wait()
|
||||
return 'Detected' in p.communicate()[0]
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def pe_sieve(self, p):
|
||||
try:
|
||||
check_file = p.exe().replace("\\", "/")
|
||||
if ":/Windows" not in check_file and ":/Program" not in check_file:
|
||||
cmd = f'"{self.exten}\\pe_sieve\\pe_sieve.exe" /ofilter 2 /pid "{p.pid}"'
|
||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True).wait()
|
||||
output = p.communicate()[0]
|
||||
for match in re.finditer(r'(\d+)', output):
|
||||
line = output[:match.start()].split('\n')[-1].strip().replace(':', '')
|
||||
if line in ["Implanted shc", "Replaced", "IAT Hooks"] and int(match.group(1)) > 0:
|
||||
return line
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
+7
-6
@@ -16,14 +16,15 @@ translate_dict = {
|
||||
"綠":"绿","態":"态","務":"务","連":"连","檢":"检","測":"测","關":"关",
|
||||
"強":"强","驅":"驱","為":"为","腳":"脚","單":"单","開":"开","擴":"扩",
|
||||
"惡":"恶","據":"据","庫":"库","經":"经","敗":"败","謝":"谢","別":"别",
|
||||
"載":"载","誤":"误","報":"报","鏈":"链","竄":"窜","記憶體":"内存",},
|
||||
"載":"载","誤":"误","報":"报","鏈":"链","竄":"窜","蹤":"踪","記憶體":"内存",},
|
||||
"en_US": {"已開啟":"On","已關閉":"Off","已开启":"On","已关闭":"Off",",":", ",
|
||||
"立即刪除":"Delete Now","安全模式":"Safe Mode","官方網站":"Website ",
|
||||
"腳本":"Script ","鏈式":"Chain ","記憶體":"Memory ","加載":"Load ",
|
||||
"行為":"Behavior ","可疑":"Suspicious ","勒索":"Ransom ",
|
||||
"許可條款":"License Terms ","惡意":"Malicious","可疑":"Suspicious",
|
||||
"啟用":"Enable ","禁用":"Disable ","正在初始化中":"Initializing ",
|
||||
"正在掃描":"Scanning ","正在刪除":"Deleting ","最小化到":"Minimize To ",
|
||||
"正在掃描":"Scanning ","正在刪除":"Deleting ","正在追蹤":"Tracking ",
|
||||
"最小化到":"Minimize To ","靈敏度":"Sensitivity ","正在檢查":"Checking ",
|
||||
"確定要":"Sure Want To ","引擎靈敏度":"Sensitivity ","更新":"Update ",
|
||||
"白色主題":"White","黃色主題":"Yellow","紅色主題":"Red","語言":"Language ",
|
||||
"藍色主題":"Blue","綠色主題":"Green","自定主題":"Custom","最新":"Latest ",
|
||||
@@ -45,7 +46,7 @@ translate_dict = {
|
||||
"風險":"Risk ","介面":"GUI ","核心":"Core ","服務":"Services ",
|
||||
"管理":"Manage","所有":"All ","您":"You ","取消":"Cancel ","未":"Not ",
|
||||
"垃圾":"Junk ","位元":"byte ","本機":"Computer ","停止":"Stop ",
|
||||
"增加到":"Add To ","白名單":"White List ","軟體":"Software ","正在":"Start ",
|
||||
"增加到":"Add To ","白名單":"White List ","軟體":"Software ","正在":"",
|
||||
"增加":"Add ","移除":"Delete","項目":"Items ","生成":"Create ","稱":"",
|
||||
"複製":"Copy ","開啟":"Open ","此":"This ","並":"And ","全盤":"Full ",
|
||||
"已經在":"Already ","數據庫":"Database ","誤報":"False Positive ",
|
||||
@@ -53,7 +54,7 @@ translate_dict = {
|
||||
"日誌":"Log","已":"Has ","彈窗":"Window ","要":"To ","驅動":"Driver ",
|
||||
"的":"","顯示":"","個":"","嗎":"","中":"","了":"","行":"","立即":"",
|
||||
"密鑰":"Key ","檢測":"Detect ","製作":"Maker ","運行":"Running",
|
||||
"擴展":"Extension ","套件":"Kit ","自動":"Auto ","上報":"Report ","與":"With ",
|
||||
"擴展":"Extension ","套件":"Kit ","自動":"Auto ","上報":"Report ",
|
||||
"分析":"Analysis ","自身":"Self ","其他":"Other ","配置":"Config ",
|
||||
"丟失":"Lost ","網站":"Website ","不兼容":"Not Compatible ","追蹤":"Tracking ",
|
||||
"竄改":"Tamper ","靈敏度":"Sensitivity ","第三方":"Other "," ":" "}}
|
||||
"丟失":"Lost ","網站":"Website ","不兼容":"Not Compatible ",
|
||||
"竄改":"Tamper ","第三方":"Other ","與":"With "," ":" "}}
|
||||
+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.5',
|
||||
version='3.2.1',
|
||||
company_name="PYAS Security",
|
||||
file_description="Python Antivirus Software",
|
||||
internal_name="PYAS",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# PYAS (Python Antivirus Software)
|
||||
|
||||

|
||||

|
||||
|
||||
## Readme Language
|
||||
|
||||
@@ -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
|
||||
@@ -24,12 +28,7 @@ PyQt5==5.15.9
|
||||
```
|
||||
PYAS/
|
||||
├── Driver/
|
||||
│ ├── PYAS_Driver.sys -------> Extension Kit (self protection driver for pyas by 0sha0)
|
||||
│ └── ...
|
||||
│
|
||||
├── Exten/
|
||||
│ ├── bitdefender/ ----------> Extension Kit (bitdefender windows console scan engine)
|
||||
│ ├── pe_sieve/ -------------> Extension Kit (pe sieve windows console memory engine)
|
||||
│ ├── PYAS_Driver.sys -------> Driver Protect (self protection driver for pyas by 0sha0)
|
||||
│ └── ...
|
||||
│
|
||||
├── Model/
|
||||
@@ -41,10 +40,9 @@ PYAS/
|
||||
│ ├── Yara_Rules.yrc ---------> Compile Rules (yara rules in compiled format)
|
||||
│ └── ...
|
||||
│
|
||||
├── PYAS.* ---------------------> Main PYAS Program (including animation, scan, protect functions, ...)
|
||||
├── PYAS.py ---------------------> Main PYAS Program (including animation, scan, protect functions, ...)
|
||||
├── PYAS_Engine.py -------------> Conversion Database (used to transform profiles and forecast data)
|
||||
├── PYAS_Suffixes.py -----------> File Suffixes (including scanned file suffixes and common suffixes)
|
||||
├── PYAS_Extension.py ----------> Extension Kit (extension scanners developed by other developers)
|
||||
├── PYAS_Interface.py ----------> PyQt5 Interface (use QT designer, must be matched with the main program)
|
||||
├── PYAS_Resource.py -----------> PyQt5 Resource (status pictures, icon packages, button icons, ...)
|
||||
├── PYAS_Language.py -----------> Translate Dict (Traditional Chinese, Simplified Chinese, English)
|
||||
@@ -58,6 +56,10 @@ https://pyantivirus.wixsite.com/pyas
|
||||
|
||||
https://github.com/87owo/PYAS
|
||||
|
||||
## Microsoft Runtime
|
||||
|
||||
https://github.com/87owo/Microsoft_Runtime/releases
|
||||
|
||||
## PYAS Driver
|
||||
|
||||
https://github.com/0sha0/PYAS_Protection
|
||||
|
||||
+19
-17
@@ -1,16 +1,20 @@
|
||||
# PYAS (Python 杀毒软件)
|
||||
|
||||

|
||||

|
||||
|
||||
## 安装要求
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## 文件信息
|
||||
@@ -21,11 +25,6 @@ PYAS/
|
||||
│ ├── PYAS_Driver.sys -------> 驱动程序 (0sha0 为 pyas 提供的自我保护驱动程序)
|
||||
│ └── ...
|
||||
│
|
||||
├── Exten/
|
||||
│ ├── bitdefender/ ----------> 扩展套件 (bitdefender windows 控制台扫描引擎)
|
||||
│ ├── pe_sieve/ -------------> 扩展套件 (pe sieve windows 控制台内存引擎)
|
||||
│ └── ...
|
||||
│
|
||||
├── Model/
|
||||
│ ├── PYAS_Model.json -------> 病毒数据库 (数据库必须位于指定目录中)
|
||||
│ └── ...
|
||||
@@ -35,14 +34,13 @@ PYAS/
|
||||
│ ├── Yara_Rules.yrc ---------> 编译规则 (编译格式的 yara 规则)
|
||||
│ └── ...
|
||||
│
|
||||
├── PYAS.* ---------------------> PYAS主程序(包含动画、扫描、保护等功能...)
|
||||
├── PYAS.py ---------------------> PYAS主程序(包含动画、扫描、保护等功能...)
|
||||
├── PYAS_Engine.py -------------> 转换数据库(用于转换剖面图和预报数据)
|
||||
├── PYAS_Suffixes.py -----------> 文件后缀(包含扫描文件后缀和常用后缀)
|
||||
├── PYAS_Extension.py ----------> 扩展工具包(其他开发者开发的扩展扫描器)
|
||||
├── PYAS_Interface.py ----------> PyQt5界面(使用QT设计器,需与主程序搭配使用)
|
||||
├── PYAS_Resource.py -----------> PyQt5资源(状态图片、图标包、按钮图标...)
|
||||
├── PYAS_Language.py -----------> 翻译词典(繁体中文、简体中文、英文)
|
||||
├── PYAS_Version.py ------------> 安裝信息(文件信息、版本信息、原名,...)
|
||||
├── PYAS_Version.py ------------> 安裝信息(文件信息、版本信息、原名...)
|
||||
└── ...
|
||||
```
|
||||
|
||||
@@ -52,14 +50,18 @@ https://pyantivirus.wixsite.com/pyas
|
||||
|
||||
https://github.com/87owo/PYAS
|
||||
|
||||
## 开源协议
|
||||
## 微软运行库
|
||||
|
||||
https://github.com/87owo/PYAS/blob/main/LICENSE.md
|
||||
https://github.com/87owo/Microsoft_Runtime/releases
|
||||
|
||||
## 驱动程序
|
||||
|
||||
https://github.com/0sha0/PYAS_Protection
|
||||
|
||||
## 开源协议
|
||||
|
||||
https://github.com/87owo/PYAS/blob/main/LICENSE.md
|
||||
|
||||
## 支援系统
|
||||
|
||||
Windows 8.1, 10, 11 (64-bit), 内存 500MB, 存储 200MB 或更高
|
||||
|
||||
+19
-17
@@ -1,16 +1,20 @@
|
||||
# PYAS (Python 防毒軟體)
|
||||
|
||||

|
||||

|
||||
|
||||
## 安裝要求
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## 檔案資訊
|
||||
@@ -21,11 +25,6 @@ PYAS/
|
||||
│ ├── PYAS_Driver.sys -------> 驅動程式 (0sha0 為 pyas 提供的自我保護驅動程式)
|
||||
│ └── ...
|
||||
│
|
||||
├── Exten/
|
||||
│ ├── bitdefender/ ----------> 擴充套件 (bitdefender windows 控制台掃描引擎)
|
||||
│ ├── pe_sieve/ -------------> 擴充套件 (pe sieve windows 控制台記憶體引擎)
|
||||
│ └── ...
|
||||
│
|
||||
├── Model/
|
||||
│ ├── PYAS_Model.json -------> 病毒資料庫 (資料庫必須位於指定目錄)
|
||||
│ └── ...
|
||||
@@ -35,14 +34,13 @@ PYAS/
|
||||
│ ├── Yara_Rules.yrc ---------> 編譯規則 (編譯格式的 yara 規則)
|
||||
│ └── ...
|
||||
│
|
||||
├── PYAS.* ---------------------> PYAS主程式(包含動畫、掃描、保護等功能...)
|
||||
├── PYAS.py ---------------------> PYAS主程式(包含動畫、掃描、保護等功能...)
|
||||
├── PYAS_Engine.py -------------> 轉換資料庫(用於轉換剖面圖和預報資料)
|
||||
├── PYAS_Suffixes.py -----------> 文件後綴(包含掃描文件後綴和常用後綴)
|
||||
├── PYAS_Extension.py ----------> 擴充工具包(其他開發者開發的擴充掃描器)
|
||||
├── PYAS_Interface.py ----------> PyQt5介面(使用QT設計器,需與主程式搭配使用)
|
||||
├── PYAS_Resource.py -----------> PyQt5資源(狀態圖片、圖示包、按鈕圖示...)
|
||||
├── PYAS_Language.py -----------> 翻譯字典(繁體中文、簡體中文、英文)
|
||||
├── PYAS_Version.py ------------> 安裝資訊(檔案資訊、版本資訊、原名,...)
|
||||
├── PYAS_Version.py ------------> 安裝資訊(檔案資訊、版本資訊、原名...)
|
||||
└── ...
|
||||
```
|
||||
|
||||
@@ -52,14 +50,18 @@ https://pyantivirus.wixsite.com/pyas
|
||||
|
||||
https://github.com/87owo/PYAS
|
||||
|
||||
## 開源協議
|
||||
## 微軟運行庫
|
||||
|
||||
https://github.com/87owo/PYAS/blob/main/LICENSE.md
|
||||
https://github.com/87owo/Microsoft_Runtime/releases
|
||||
|
||||
## 驅動程式
|
||||
|
||||
https://github.com/0sha0/PYAS_Protection
|
||||
|
||||
## 開源協議
|
||||
|
||||
https://github.com/87owo/PYAS/blob/main/LICENSE.md
|
||||
|
||||
## 支援系統
|
||||
|
||||
Windows 8.1, 10, 11 (64-bit),記憶體 500MB, 磁碟容量 200MB 或更高
|
||||
|
||||
+256387
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user