Compare commits

...
23 Commits
Author SHA1 Message Date
PYDT 264dd50969 Add files via upload 2025-08-25 08:49:53 +08:00
PYDT 26d0ad1a6e Add files via upload 2025-08-24 22:06:31 +08:00
PYDT 90284018e5 Add files via upload 2025-08-24 22:06:02 +08:00
PYDT 46eeec16d4 Add files via upload 2025-08-24 22:05:30 +08:00
PYDT 083fb0dccc Add files via upload 2025-08-23 22:07:39 +08:00
PYDT d46f145806 Delete Plugins/Filter/ProtectReg.c 2025-08-23 22:04:35 +08:00
PYDT 868eddfd2b Add files via upload 2025-08-23 22:04:11 +08:00
PYDT 8295e6bb5b Add files via upload 2025-08-22 23:13:46 +08:00
PYDT 424914b842 Add files via upload 2025-08-22 22:16:20 +08:00
PYDT 8c5027df0f Delete Plugins/Filter/ProtectBoot.c 2025-08-22 21:16:55 +08:00
PYDT 0b7817d992 Add files via upload 2025-08-22 21:16:36 +08:00
PYDT ca6c9bfd05 Add files via upload 2025-08-22 05:31:46 +08:00
PYDT 0a1abd8040 Add files via upload 2025-08-22 05:27:25 +08:00
PYDT ed69a4fdf6 Add files via upload 2025-08-22 05:20:50 +08:00
PYDT 2ae19a6d4e Add files via upload 2025-08-22 05:08:52 +08:00
PYDT 404bc50dd4 Add files via upload 2025-08-22 04:56:09 +08:00
PYDT cada5eeeaf Add files via upload 2025-08-22 04:16:55 +08:00
PYDT 5e9bd40e8b Add files via upload 2025-08-22 03:22:40 +08:00
PYDT 0788bab0dd Add files via upload 2025-08-22 03:21:51 +08:00
PYDT 4e8e0dbea7 Add files via upload 2025-08-19 08:27:20 +08:00
PYDT b8c5279137 Add files via upload 2025-08-19 07:52:24 +08:00
PYDT a3255b1681 Add files via upload 2025-08-19 07:43:35 +08:00
PYDT f151379f8f Add files via upload 2025-08-18 22:49:35 +08:00
19 changed files with 1829 additions and 609 deletions

No files matched your search

+231 -102
View File
@@ -1,7 +1,7 @@
import os, gc, re, sys, time, json, base64
import os, gc, re, sys, time, json, shutil
import ctypes, ctypes.wintypes, threading
import requests, webbrowser, winreg, shutil
import traceback, hashlib, msvcrt, pyperclip
import requests, webbrowser, winreg, msvcrt
import traceback, hashlib
from PYAS_Config import *
from PYAS_Engine import *
@@ -89,6 +89,8 @@ class MainWindow_Controller(QMainWindow):
self.python = sys.executable
self.process_timer = QTimer(self)
self.sign = sign_scanner()
self.sign.init_windll(["wintrust"])
self.model = model_scanner()
self.model.load_path(self.path_models)
self.rule = rule_scanner()
@@ -112,7 +114,7 @@ class MainWindow_Controller(QMainWindow):
"traditional_switch", "simplified_switch", "english_switch",
]
self.pyas_default = {
"version": "3.3.4",
"version": "3.3.5",
"product": "00000-00000-00000-00000-00000",
"language": "english_switch",
"theme": "white_switch",
@@ -131,15 +133,17 @@ class MainWindow_Controller(QMainWindow):
{"exe": "explorer.exe", "class": "", "title": ""},
]
self.block_replace = {
"BOOT_BLOCK": "引導行為攔截",
"REG_BLOCK": "註冊表行為攔截",
"FILE_BLOCK": "檔案行為攔截",
"RANSOM_BLOCK": "勒索行為攔截",
"CLR_BLOCK": "托管行為攔截",
"SHELLCODE_BLOCK": "殼碼行為攔截",
"BOOT_BLOCK": "引導行為攔截",
"REG_BLOCK": "註冊表行為攔截",
"CLR_BLOCK": "執行環境攔截",
"SHELLCODE_BLOCK": "殼碼加載攔截",
"THREAD_BLOCK": "線程行為攔截",
"INJECT_BLOCK": "注入行為攔截",
"PROC_BLOCK": "進程行為攔截",
"REMOTE_BLOCK": "遠控行為攔截",
"SCREEN_BLOCK": "監控行為攔截",
}
####################################################################################################
@@ -266,6 +270,7 @@ class MainWindow_Controller(QMainWindow):
self.last_widget = self.widgets.get("home_window")
self.setup_theme_mapping()
self.setup_process_menu()
self.setup_scan_menu()
def create_shadow(self):
shadow = QGraphicsDropShadowEffect(self)
@@ -348,7 +353,7 @@ class MainWindow_Controller(QMainWindow):
elif self.install_system_driver():
self.start_daemon_thread(self.pipe_server_thread)
else:
self.send_message("驅動防護啟用失敗", "warn", True)
self.send_message("驅動防護啟用失敗,請重啟裝置來修復錯誤", "warn", True)
elif name == "network_switch":
if checked:
self.start_daemon_thread(self.protect_net_thread)
@@ -572,6 +577,8 @@ class MainWindow_Controller(QMainWindow):
self.pyas_config["system_switch"] = False
self.pyas_config["driver_switch"] = False
self.pyas_config["network_switch"] = False
self.stop_button()
self.stop_system_driver()
self.minimize_button()
@@ -618,7 +625,8 @@ class MainWindow_Controller(QMainWindow):
if not isinstance(message, str):
message = str(message)
if message and translate:
message = self.trans(self.pyas_config["language"], message)
lang = self.pyas_config.get("language", "english_switch")
message = self.trans(lang, message)
m = mode.lower()
if m == "quest":
@@ -639,7 +647,7 @@ class MainWindow_Controller(QMainWindow):
elif m == "save":
select = QFileDialog.getSaveFileName(self, message)[0]
select = select or False
select = select or None
now = time.strftime("%Y-%m-%d %H:%M:%S")
output = f"[{now}] | {mode} | {message} | {select}"
log_widget = self.widgets.get("log_text")
@@ -650,6 +658,8 @@ class MainWindow_Controller(QMainWindow):
traceback.print_exc()
return False
####################################################################################################
def invoke_method(self, obj, method, *args):
q_args = []
for arg in args:
@@ -661,14 +671,25 @@ class MainWindow_Controller(QMainWindow):
q_args.append(Q_ARG("QString", str(arg)))
QMetaObject.invokeMethod(obj, method, Qt.QueuedConnection, *q_args)
def norm_path(self, path):
if isinstance(path, (list, tuple, set)):
t = type(path)
return t(self.norm_path(p) for p in path)
def norm_path(self, path, must_exist=True):
if isinstance(path, list):
return [p for p in (self.norm_path(x, must_exist) for x in path) if p]
if isinstance(path, tuple):
return tuple(p for p in (self.norm_path(x, must_exist) for x in path) if p)
if isinstance(path, set):
return {p for p in (self.norm_path(x, must_exist) for x in path) if p}
if isinstance(path, str):
return os.path.normpath(os.path.abspath(path))
ap = os.path.normpath(os.path.abspath(path))
return ap if (not must_exist or os.path.exists(ap)) else None
return path
def path_equal(self, a, b):
pa = self.norm_path(a, must_exist=False)
pb = self.norm_path(b, must_exist=False)
if not pa or not pb:
return False
return os.path.normcase(pa) == os.path.normcase(pb)
####################################################################################################
@Slot()
@@ -696,9 +717,9 @@ class MainWindow_Controller(QMainWindow):
@Slot(str)
def slot_scan_result(self, msg):
self.widgets["progress_text"].setText(msg)
count = len(self.virus_results)
self.widgets["solve_button"].setVisible(count > 0)
self.widgets["progress_text"].setText(msg)
self.widgets["stop_button"].hide()
self.widgets["method_button"].show()
self.send_message(msg, "notify", True)
@@ -713,8 +734,9 @@ class MainWindow_Controller(QMainWindow):
self.scan_start = time.time()
self.last_widget = self.widgets.get("scan_window")
self.scan_reset_signal.emit()
self.progress_title_signal.emit(self.trans(self.pyas_config["language"], "正在掃描"))
self.scan_progress_signal.emit(self.trans(self.pyas_config["language"], "正在初始化中"))
lang = self.pyas_config.get("language", "english_switch")
self.scan_progress_signal.emit(self.trans(lang, "正在初始化中"))
except Exception as e:
self.send_message(e, "warn", False)
@@ -748,21 +770,27 @@ class MainWindow_Controller(QMainWindow):
if self.is_in_whitelist(norm_path):
continue
self.scan_count += 1
state = self.scan_engine(norm_path)
if state:
self.virus_results.append(norm_path)
self.scan_add_virus_signal.emit(f"[{state}] > {norm_path}")
lang = self.pyas_config.get("language", "english_switch")
self.progress_title_signal.emit(self.trans(lang, "正在掃描"))
self.scan_progress_signal.emit(norm_path)
gc.collect()
except Exception as e:
self.send_message(e, "warn", False)
finally:
elapsed = int(time.time() - self.scan_start)
count = len(self.virus_results)
elapsed = int(time.time() - self.scan_start)
result = (
f"發現 {count} 個病毒,共掃描 {self.scan_count} 檔案,耗時 {elapsed} 秒"
if count else f"未發現病毒,共掃描 {self.scan_count} 檔案,耗時 {elapsed} 秒")
self.progress_title_signal.emit(self.trans(self.pyas_config["language"], "病毒掃描"))
self.scan_result_signal.emit(self.trans(self.pyas_config["language"], result))
lang = self.pyas_config.get("language", "english_switch")
self.progress_title_signal.emit(self.trans(lang, "病毒掃描"))
self.scan_result_signal.emit(self.trans(lang, result))
def yield_files(self, targets):
if isinstance(targets, str):
@@ -778,6 +806,9 @@ class MainWindow_Controller(QMainWindow):
def scan_engine(self, file_path):
try:
if self.sign.sign_verify(file_path):
return False
label, level = self.model.model_scan(file_path)
if label and level >= self.pyas_config.get("sensitive", 95):
return f"{label}.{level}"
@@ -786,15 +817,15 @@ class MainWindow_Controller(QMainWindow):
label, level = self.rule.yara_scan(file_path)
if label and level:
return f"{label}.{level}"
return False
except Exception as e:
self.send_message(e, "warn", False)
return None
return None
####################################################################################################
def solve_button(self):
deleted = 0
started = False
virus_list = self.widgets["virus_list"]
start_ts = time.time()
@@ -802,40 +833,90 @@ class MainWindow_Controller(QMainWindow):
item = virus_list.item(i)
if item.checkState() == Qt.Checked:
file_path = self.norm_path(item.text().split(">")[1].strip())
if not started:
self.progress_title_signal.emit(self.trans(self.pyas_config["language"], "正在刪除"))
started = True
lang = self.pyas_config.get("language", "english_switch")
self.progress_title_signal.emit(self.trans(lang, "正在刪除"))
self.scan_progress_signal.emit(file_path)
try:
os.remove(file_path)
deleted += 1
virus_list.takeItem(i)
try:
self.virus_results.remove(file_path)
except ValueError:
pass
self.virus_results.remove(file_path)
except Exception as e:
self.send_message(e, "warn", False)
QApplication.processEvents()
remain = virus_list.count()
count = virus_list.count()
self.widgets["solve_button"].setVisible(count > 0)
elapsed = int(time.time() - start_ts)
self.widgets["solve_button"].setVisible(remain > 0)
self.progress_title_signal.emit(self.trans(self.pyas_config["language"], "病毒掃描"))
result = (
f"剩餘 {remain} 個病毒,共刪除 {deleted} 檔案,耗時 {elapsed} 秒"
if remain else f"未剩餘病毒,共刪除 {deleted} 檔案,耗時 {elapsed} 秒")
self.scan_result_signal.emit(self.trans(self.pyas_config["language"], result))
f"剩餘 {count} 個病毒,共刪除 {deleted} 檔案,耗時 {elapsed} 秒"
if count else f"未剩餘病毒,共刪除 {deleted} 檔案,耗時 {elapsed} 秒")
lang = self.pyas_config.get("language", "english_switch")
self.progress_title_signal.emit(self.trans(lang, "病毒掃描"))
self.scan_result_signal.emit(self.trans(lang, result))
def stop_button(self):
self.scan_running = False
self.widgets["stop_button"].hide()
####################################################################################################
def setup_scan_menu(self):
widget = self.widgets.get("virus_list")
if widget:
widget.setContextMenuPolicy(Qt.CustomContextMenu)
widget.customContextMenuRequested.connect(self.show_scan_menu)
def show_scan_menu(self, pos):
widget = self.widgets.get("virus_list")
if not widget:
return
item = widget.itemAt(pos)
if not item:
return
lang = self.pyas_config.get("language", "english_switch")
menu = QMenu()
copy_action = menu.addAction(self.trans(lang, "複製路徑"))
del_action = menu.addAction(self.trans(lang, "刪除檔案"))
white_action = menu.addAction(self.trans(lang, "增加白名單"))
act = menu.exec(widget.viewport().mapToGlobal(pos))
text = item.text()
if ">" in text:
path = text.split(">", 1)[1].strip()
else:
path = text.strip()
if act == copy_action:
QGuiApplication.clipboard().setText(str(path or "").replace("/", "\\"))
elif act == del_action:
file_path = self.norm_path(path)
if file_path and self.send_message("您確定要刪除檔案嗎?", "quest"):
try:
os.remove(file_path)
widget.takeItem(widget.row(item))
self.virus_results.remove(file_path)
except Exception as e:
self.send_message(e, "warn", False)
count = len(self.virus_results)
self.widgets["solve_button"].setVisible(count > 0)
elif act == white_action:
file_path = self.norm_path(path)
if file_path and self.send_message("您確定要增加到白名單嗎?", "quest"):
n = self.manage_named_list("white_list", [file_path], action="add", with_hash=True)
self.send_message(f"成功增加到白名單,共 {n} 個檔案", "info", True)
####################################################################################################
def list_process(self):
pe = self.get_process_entry()
snapshot = self.kernel32.CreateToolhelp32Snapshot(0x00000002, 0)
result, success = [], self.kernel32.Process32First(snapshot, ctypes.byref(pe))
while success:
pid = pe.th32ProcessID
name, file_path = (None, None)
@@ -848,6 +929,7 @@ class MainWindow_Controller(QMainWindow):
name = raw.decode("mbcs", errors="replace") or None
except Exception:
name = None
result.append((pid, name, file_path))
success = self.kernel32.Process32Next(snapshot, ctypes.byref(pe))
self.kernel32.CloseHandle(snapshot)
@@ -858,6 +940,7 @@ class MainWindow_Controller(QMainWindow):
self.proc_pid_map = [pid for pid, _, _ in procs]
widget = self.widgets.get("manage_list")
info_text = self.widgets.get("info_text")
if widget:
model = QStringListModel([f"{name or 'None'} | {pid} | {file_path or 'None'}" for pid, name, file_path in procs])
widget.setModel(model)
@@ -879,6 +962,7 @@ class MainWindow_Controller(QMainWindow):
def start_process_timer(self):
if hasattr(self, "process_timer") and self.process_timer.isActive():
return
self.process_timer = QTimer(self)
self.process_timer.timeout.connect(self.refresh_process)
self.process_timer.start(0)
@@ -900,19 +984,36 @@ class MainWindow_Controller(QMainWindow):
idx = widget.indexAt(pos)
if not idx.isValid() or idx.row() >= len(self.proc_pid_map):
return
pid = self.proc_pid_map[idx.row()]
lang = self.pyas_config.get("language", "english_switch")
menu = QMenu()
kill_action = menu.addAction("結束進程")
if menu.exec(widget.viewport().mapToGlobal(pos)) == kill_action:
copy_action = menu.addAction(self.trans(lang, "複製路徑"))
kill_action = menu.addAction(self.trans(lang, "結束進程"))
white_action = menu.addAction(self.trans(lang, "增加白名單"))
act = menu.exec(widget.viewport().mapToGlobal(pos))
pid = self.proc_pid_map[idx.row()]
name, file_path = self.get_exe_info(pid)
if act == copy_action:
QGuiApplication.clipboard().setText(str(file_path or "").replace("/", "\\"))
elif act == kill_action:
self.kill_process(pid)
elif act == white_action:
if file_path and self.send_message("您確定要增加到白名單嗎?", "quest"):
file_path = self.norm_path(file_path or "")
n = self.manage_named_list("white_list", [file_path], action="add", with_hash=True)
self.send_message(f"成功增加到白名單,共 {n} 個檔案", "info", True)
def kill_process(self, pid):
try:
h = self.kernel32.OpenProcess(0x1F0FFF, False, pid)
if h:
file_path = self.norm_path(self.get_process_file(h))
if hasattr(self, "file_pyas") and file_path == getattr(self, "file_pyas", None):
self.close()
if self.path_equal(file_path, self.file_pyas):
self.close_button()
else:
self.kernel32.TerminateProcess(h, 0)
self.kernel32.CloseHandle(h)
@@ -997,6 +1098,7 @@ class MainWindow_Controller(QMainWindow):
def repair_system_mbr(self):
if not hasattr(self, "mbr_backup") or not self.mbr_backup:
return
for drive, mbr_value in self.mbr_backup.items():
drive_path = rf"\\.\PhysicalDrive{drive}"
try:
@@ -1015,9 +1117,11 @@ class MainWindow_Controller(QMainWindow):
wallpaper = os.path.join(self.path_system, "web", "wallpaper", "Windows", "img0.jpg")
if not os.path.exists(wallpaper):
return
key = r"Control Panel\\Desktop"
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key, 0, winreg.KEY_SET_VALUE) as reg:
winreg.SetValueEx(reg, "Wallpaper", 0, winreg.REG_SZ, wallpaper)
theme_dir = os.path.join(self.path_appdata, "Microsoft", "Windows", "Themes")
for fname in ["TranscodedWallpaper", "TranscodedWallpaper.tmp"]:
fpath = os.path.join(theme_dir, fname)
@@ -1026,6 +1130,7 @@ class MainWindow_Controller(QMainWindow):
os.remove(fpath)
except Exception:
pass
cache_dir = os.path.join(theme_dir, "CachedFiles")
if os.path.exists(cache_dir):
try:
@@ -1135,11 +1240,12 @@ class MainWindow_Controller(QMainWindow):
if self.send_message("請選擇要攔截的軟體彈窗", "quest", True):
while True:
QApplication.processEvents()
title, class_name, process_name = self.get_window_info(self.user32.GetForegroundWindow())
if process_name and not any(self.window_rule_match(item, process_name, class_name, title) for item in self.pass_windows):
if self.send_message(f"您確定要攔截 {process_name} ({title}) 嗎?", "quest", True):
if self.add_window_rule(self.pyas_config["block_list"], process_name, class_name, title):
self.send_message(f"成功增加到彈窗攔截: {process_name} ({title})", "info", True)
title, class_name, proc_name = self.get_window_info(self.user32.GetForegroundWindow())
if proc_name and not any(self.window_rule_match(item, proc_name, class_name, title) for item in self.pass_windows):
if self.send_message(f"您確定要攔截 {proc_name} ({title}) 嗎?", "quest", True):
if self.add_window_rule(self.pyas_config["block_list"], proc_name, class_name, title):
self.send_message(f"成功增加到彈窗攔截: {proc_name} ({title})", "info", True)
else:
self.send_message("已存在彈窗攔截", "info", True)
break
@@ -1151,32 +1257,33 @@ class MainWindow_Controller(QMainWindow):
if self.send_message("請選擇要取消攔截的軟體彈窗", "quest", True):
while True:
QApplication.processEvents()
title, class_name, process_name = self.get_window_info(self.user32.GetForegroundWindow())
if process_name and not any(self.window_rule_match(item, process_name, class_name, title) for item in self.pass_windows):
if self.send_message(f"您確定要取消攔截 {process_name} ({title}) 嗎?", "quest", True):
if self.remove_window_rule(self.pyas_config["block_list"], process_name, class_name, title):
self.send_message(f"成功取消彈窗攔截: {process_name} ({title})", "info", True)
title, class_name, proc_name = self.get_window_info(self.user32.GetForegroundWindow())
if proc_name and not any(self.window_rule_match(item, proc_name, class_name, title) for item in self.pass_windows):
if self.send_message(f"您確定要取消攔截 {proc_name} ({title}) 嗎?", "quest", True):
if self.remove_window_rule(self.pyas_config["block_list"], proc_name, class_name, title):
self.send_message(f"成功取消彈窗攔截: {proc_name} ({title})", "info", True)
else:
self.send_message("未找到彈窗攔截", "info", True)
break
self.start_daemon_thread(self.popup_intercept_thread)
def window_rule_match(self, item, process_name, class_name, title):
for k, v in zip(["exe", "class", "title"], [process_name, class_name, title]):
def window_rule_match(self, item, proc_name, class_name, title):
for k, v in zip(["exe", "class", "title"], [proc_name, class_name, title]):
if item.get(k, "") and item.get(k, "") != v:
return False
return True
def add_window_rule(self, rule_list, process_name, class_name, title):
if not any(self.window_rule_match(item, process_name, class_name, title) for item in rule_list):
rule_list.append({"exe": process_name, "class": class_name, "title": title})
def add_window_rule(self, rule_list, proc_name, class_name, title):
if not any(self.window_rule_match(item, proc_name, class_name, title) for item in rule_list):
rule_list.append({"exe": proc_name, "class": class_name, "title": title})
self.save_config(self.file_config, self.pyas_config)
return True
return False
def remove_window_rule(self, rule_list, process_name, class_name, title):
def remove_window_rule(self, rule_list, proc_name, class_name, title):
before = len(rule_list)
rule_list[:] = [item for item in rule_list if not self.window_rule_match(item, process_name, class_name, title)]
rule_list[:] = [item for item in rule_list if not self.window_rule_match(item, proc_name, class_name, title)]
if len(rule_list) < before:
self.save_config(self.file_config, self.pyas_config)
return True
@@ -1190,12 +1297,26 @@ class MainWindow_Controller(QMainWindow):
rules = self.pyas_config.get("block_list", [])
if not rules:
continue
for hWnd in self.get_all_windows():
title, class_name, process_name = self.get_window_info(hWnd)
if (not any(self.window_rule_match(item, process_name, class_name, title) for item in self.pass_windows) and
any(self.window_rule_match(item, process_name, class_name, title) for item in rules)):
title, class_name, proc_name = self.get_window_info(hWnd)
if (not any(self.window_rule_match(item, proc_name, class_name, title) for item in self.pass_windows) and
any(self.window_rule_match(item, proc_name, class_name, title) for item in rules)):
closed = False
for msg in [0x0010, 0x0002, 0x0012, 0x0112]:
self.user32.SendMessageW(hWnd, msg, 0xF060, 0)
if self.user32.SendMessageW(hWnd, msg, 0xF060, 0) != 0:
closed = True
break
if not closed and proc_name:
pid = ctypes.c_ulong()
self.user32.GetWindowThreadProcessId(hWnd, ctypes.byref(pid))
if pid.value:
h = self.kernel32.OpenProcess(0x1F0FFF, False, pid.value)
if h:
self.kernel32.TerminateProcess(h, 0)
self.kernel32.CloseHandle(h)
except Exception as e:
self.send_message(e, "warn", False)
@@ -1219,73 +1340,79 @@ class MainWindow_Controller(QMainWindow):
self.user32.GetClassNameW(hWnd, class_name, 256)
pid = ctypes.c_ulong()
self.user32.GetWindowThreadProcessId(hWnd, ctypes.byref(pid))
process_name = ""
proc_name = ""
try:
process_name = self.get_process_name_by_pid(pid.value)
proc_name = self.get_process_name(pid.value)
except Exception:
pass
return str(title.value), str(class_name.value), process_name
return str(title.value), str(class_name.value), proc_name
def get_process_name_by_pid(self, pid):
def get_process_name(self, pid):
name, file_path = self.get_exe_info(pid)
if name:
return name
snapshot = self.kernel32.CreateToolhelp32Snapshot(0x00000002, 0)
entry = PROCESSENTRY32()
entry.dwSize = ctypes.sizeof(PROCESSENTRY32)
name = ""
result = ""
if self.kernel32.Process32First(snapshot, ctypes.byref(entry)):
while True:
if entry.th32ProcessID == pid:
name = entry.szExeFile.decode("mbcs").rstrip("\x00")
try:
result = entry.szExeFile.decode("mbcs").rstrip("\x00")
except Exception:
result = ""
break
if not self.kernel32.Process32Next(snapshot, ctypes.byref(entry)):
break
self.kernel32.CloseHandle(snapshot)
return name
return result
####################################################################################################
def whitelist_button(self):
self.config_list("white_list")
files = self.send_message("選擇檔案", "files", True)
if files:
if self.send_message("您確定要增加到白名單嗎?", "quest"):
n = self.manage_named_list("white_list", files, action="add", with_hash=True)
self.send_message(f"成功增加到白名單,共 {n} 個檔案", "info")
if files and self.send_message("您確定要增加到白名單嗎?", "quest"):
n = self.manage_named_list("white_list", files, action="add", with_hash=True)
self.send_message(f"成功增加到白名單,共 {n} 個檔案", "info")
def whitelist_button_2(self):
self.config_list("white_list")
files = self.send_message("選擇檔案", "files", True)
if files:
if self.send_message("您確定要移除白名單嗎?", "quest"):
n = self.manage_named_list("white_list", files, action="remove", with_hash=True)
self.send_message(f"成功移除白名單,共 {n} 個檔案", "info")
if files and self.send_message("您確定要移除白名單嗎?", "quest"):
n = self.manage_named_list("white_list", files, action="remove", with_hash=True)
self.send_message(f"成功移除白名單,共 {n} 個檔案", "info")
def quarantine_button(self):
self.config_list("quarantine")
files = self.send_message("選擇檔案", "files", True)
if files:
if self.send_message("您確定要增加到隔離區嗎?", "quest"):
n = self.manage_named_list("quarantine", files, action="add", with_hash=True, lock_func=self.lock_file)
if n > 0:
self.send_message(f"成功增加到隔離區,共 {n} 個檔案", "info")
if files and self.send_message("您確定要增加到隔離區嗎?", "quest"):
n = self.manage_named_list("quarantine", files, action="add", with_hash=True, lock_func=self.lock_file)
if n > 0:
self.send_message(f"成功增加到隔離區,共 {n} 個檔案", "info")
def quarantine_button_2(self):
self.config_list("quarantine")
quarantine_dir = os.path.join(self.path_config, "quarantine")
files = self.send_message("選擇檔案", "files", True)
if files:
if self.send_message("您確定要移除隔離區嗎?", "quest"):
n = self.manage_named_list("quarantine", files, action="remove", with_hash=True, lock_func=self.lock_file)
self.send_message(f"成功移除隔離區,共 {n} 個檔案", "info")
if files and self.send_message("您確定要移除隔離區嗎?", "quest"):
n = self.manage_named_list("quarantine", files, action="remove", with_hash=True, lock_func=self.lock_file)
self.send_message(f"成功移除隔離區,共 {n} 個檔案", "info")
def add_to_quarantine(self, files):
self.config_list("quarantine")
return self.manage_named_list("quarantine", files, action="add", with_hash=True, lock_func=self.lock_file)
def is_in_whitelist(self, file_path):
norm_path = self.norm_path(file_path)
file_hash = self.calc_file_hash(norm_path)
return any(item["file"] == norm_path and item["hash"] == file_hash
for item in self.pyas_config.get("white_list", []))
p = self.norm_path(file_path)
if not p:
return False
file_hash = self.calc_file_hash(p)
return any(os.path.normcase(item.get("file","")) == os.path.normcase(p) and
item.get("hash","") == file_hash for item in self.pyas_config.get("white_list", []))
def init_whitelist(self):
self.manage_named_list("white_list", [self.file_pyas], action="add", with_hash=True)
@@ -1295,9 +1422,9 @@ class MainWindow_Controller(QMainWindow):
def manage_named_list(self, list_key, files, action="add", with_hash=True, lock_func=None):
target_list = self.config_list(list_key)
files = files or []
norm_paths = self.norm_path(files)
norm_paths = self.norm_path(files, must_exist=True)
if isinstance(norm_paths, str):
norm_paths = [norm_paths]
norm_paths = [norm_paths] if norm_paths else []
n = 0
if action == "add":
@@ -1438,8 +1565,9 @@ class MainWindow_Controller(QMainWindow):
h = self.kernel32.OpenProcess(0x1F0FFF, False, pid)
if not h:
return
file_path = self.norm_path(self.get_process_file(h))
if file_path and os.path.exists(file_path) and not self.is_in_whitelist(file_path):
if file_path and not self.is_in_whitelist(file_path):
self.suspend_process(h, True)
state = self.scan_engine(file_path)
if state:
@@ -1562,17 +1690,17 @@ class MainWindow_Controller(QMainWindow):
def handle_new_connection(self, key):
pid, remote_addr, remote_port = key
try:
h_process = self.kernel32.OpenProcess(0x1F0FFF, False, pid)
if not h_process:
h = self.kernel32.OpenProcess(0x1F0FFF, False, pid)
if not h:
return
file_path = self.norm_path(self.get_process_file(h_process))
remote_ip = f"{remote_addr & 0xFF}.{(remote_addr >> 8) & 0xFF}.{(remote_addr >> 16) & 0xFF}.{(remote_addr >> 24) & 0xFF}"
if file_path and os.path.exists(file_path) and not self.is_in_whitelist(file_path):
file_path = self.norm_path(self.get_process_file(h))
if file_path and not self.is_in_whitelist(file_path):
if hasattr(self.rule, "network") and remote_ip in self.rule.network:
self.kernel32.TerminateProcess(h_process, 0)
self.kernel32.TerminateProcess(h, 0)
self.send_message(f"網路防護 | 規則列表攔截 | {pid} | {file_path} | {remote_ip}", "notify", True)
self.kernel32.CloseHandle(h_process)
self.kernel32.CloseHandle(h)
except Exception as e:
self.send_message(e, "warn", False)
@@ -1662,11 +1790,12 @@ class MainWindow_Controller(QMainWindow):
rules = rules.replace(old, new)
self.send_message(f"驅動防護 | {rules} | {pid} | {raw_path} | {target}", "notify", True)
if not self.is_in_whitelist(self.device_path_to_drive(raw_path)):
file_path = self.norm_path(self.device_path_to_drive(raw_path))
if not self.is_in_whitelist(file_path) and not self.sign.sign_verify(file_path):
try:
h = self.kernel32.OpenProcess(0x1F0FFF, False, int(pid.strip()))
if h:
self.kernel32.TerminateProcess(h, 0xC0000022)
self.kernel32.TerminateProcess(h, 0)
self.kernel32.CloseHandle(h)
except Exception as e:
self.send_message(e, "warn", False)
+3 -2
View File
@@ -71,9 +71,10 @@ translate_dict = {
"沙箱":"Sandbox ", "虛擬":"Virtual ", "隔離":"Quarantine ", "時":"",
"建立":"Create ","環境":"Environment ","沙箱":"Sandbox ","化":"", "表":"",
"達":"Reached ", "上限":"Limit ", "區":"", "金鑰":"Key ", "產品":"Product ",
"托管":"CLR ","殼碼":"Shellcode ","線程":"Thread ","注入":"Inject ",
"運行庫":".NET CLR ","殼碼":"Shellcode ","線程":"Thread ","注入":"Inject ",
"前往":"Go ","檢查":"Check ","可用":"Available ","靜態":"Static ",
"版本":"Version ","是":"","剩餘":"Remain "," ":" "},
"版本":"Version ","是":"","剩餘":"Remain ","遠控":"Remote ","監控":"Monitor ",
" ":" "},
"white_switch": {
"_white": "_black",},
+75 -9
View File
@@ -1,6 +1,72 @@
import os, yara, numpy, locale, pefile, onnxruntime
import os, yara, numpy, onnxruntime
import ctypes, ctypes.wintypes, pefile
from PIL import Image
####################################################################################################
class GUID(ctypes.Structure):
_fields_ = [
("Data1", ctypes.wintypes.DWORD),
("Data2", ctypes.wintypes.WORD),
("Data3", ctypes.wintypes.WORD),
("Data4", ctypes.c_ubyte * 8)]
class WINTRUST_FILE_INFO(ctypes.Structure):
_fields_ = [
("cbStruct", ctypes.wintypes.DWORD),
("pcwszFilePath", ctypes.wintypes.LPCWSTR),
("hFile", ctypes.wintypes.HANDLE),
("pgKnownSubject", ctypes.wintypes.LPVOID)]
class WINTRUST_DATA(ctypes.Structure):
_fields_ = [
("cbStruct", ctypes.wintypes.DWORD),
("pPolicyCallbackData", ctypes.wintypes.LPVOID),
("pSIPClientData", ctypes.wintypes.LPVOID),
("dwUIChoice", ctypes.wintypes.DWORD),
("fdwRevocationChecks", ctypes.wintypes.DWORD),
("dwUnionChoice", ctypes.wintypes.DWORD),
("pFile", ctypes.POINTER(WINTRUST_FILE_INFO)),
("dwStateAction", ctypes.wintypes.DWORD),
("hWVTStateData", ctypes.wintypes.HANDLE),
("pwszURLReference", ctypes.wintypes.LPCWSTR),
("dwProvFlags", ctypes.wintypes.DWORD),
("dwUIContext", ctypes.wintypes.DWORD),
("pSignatureSettings", ctypes.wintypes.LPVOID)]
####################################################################################################
class sign_scanner:
def __init__(self):
self.verify = GUID(0x00AAC56B, 0xCD44, 0x11D0, (0x8C, 0xC2, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xEE))
def init_windll(self, path):
for name in path:
try:
setattr(self, name.lower(), ctypes.WinDLL(name, use_last_error=True))
except Exception as e:
self.send_message(e, "warn", False)
self.WinVerifyTrust = self.wintrust.WinVerifyTrust
self.WinVerifyTrust.restype = ctypes.wintypes.LONG
self.WinVerifyTrust.argtypes = [ctypes.wintypes.HWND, ctypes.POINTER(GUID), ctypes.c_void_p]
def is_sign(self, file_path):
with pefile.PE(file, fast_load=True) as pe:
sec_dir = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']]
return sec_dir.VirtualAddress != 0 and sec_dir.Size > 0
def sign_verify(self, file_path):
fi = WINTRUST_FILE_INFO(ctypes.sizeof(WINTRUST_FILE_INFO), file_path, None, None)
data = WINTRUST_DATA(ctypes.sizeof(WINTRUST_DATA), None, None, 2, 0, 1,
ctypes.pointer(fi), 1, None, None, 0, 0, None)
s = self.WinVerifyTrust(None, ctypes.byref(self.verify), ctypes.byref(data))
data.dwStateAction = 2
self.WinVerifyTrust(None, ctypes.byref(self.verify), ctypes.byref(data))
return s == 0
####################################################################################################
class rule_scanner:
def __init__(self):
self.rules = {}
@@ -26,9 +92,8 @@ class rule_scanner:
def yara_scan(self, file_path):
try:
data = open(file_path, "rb").read() if isinstance(file_path, str) else file_path
for rules in self.rules.values():
matches = rules.match(data=data)
matches = rules.match(filepath=file_path)
if matches:
rule_name = str(matches[0])
label = rule_name.split("_")[0]
@@ -38,19 +103,18 @@ class rule_scanner:
except Exception:
return False, False
####################################################################################################
class model_scanner:
def __init__(self):
self.models = {}
self.suffix = {
".com", ".dll", ".drv", ".exe", ".ocx", ".scr", ".sys",
".bat", ".cmd", ".html", ".js", ".php", ".ps1", ".vbs", ".wsf", ".xml"
}
".bat", ".cmd", ".js", ".php", ".ps1", ".vbs", ".wsf"}
self.labels = [
"Pefile/White", "Script/White", "Pefile/General", "Script/General"
]
"Pefile/White", "Script/White", "Pefile/General", "Script/General"]
self.detect = {
"Pefile/General", "Script/General"
}
"Pefile/General", "Script/General"}
self.resize = (224, 224)
def load_path(self, path):
@@ -109,6 +173,7 @@ class model_scanner:
arr = numpy.frombuffer(file_data, dtype=numpy.uint8)
img = numpy.zeros(wah*wah*channels, dtype=numpy.uint8)
img[:len(file_data)] = arr
if channels == 1:
image = Image.fromarray(img.reshape((wah, wah)), 'L')
else:
@@ -136,6 +201,7 @@ class model_scanner:
name = section.Name.rstrip(b'\x00').decode('latin1').lower()
if section.Characteristics & 0x00000020:
match_data[name] = section.get_data()
except pefile.PEFormatError:
with open(file_path, 'rb') as f:
file_content = f.read()
+1 -1
View File
@@ -2,7 +2,7 @@ import pyinstaller_versionfile
pyinstaller_versionfile.create_versionfile(
output_file="versionfile.txt",
version='3.3.4',
version='3.3.5',
company_name="PYAS Security",
file_description="Python Antivirus Software",
internal_name="PYAS",
+98 -12
View File
@@ -13,6 +13,9 @@ BOOLEAN g_CmRegActive = FALSE;
EX_RUNDOWN_REF g_Rundown;
PDEVICE_OBJECT g_GuardDevice = NULL;
PDEVICE_OBJECT g_MbrFilterTargets[MAX_MBR_TARGETS] = { 0 };
ULONG g_MbrFilterCount = 0;
volatile LONG g_LogWorkCount = 0;
static UNICODE_STRING g_DeviceName;
static WCHAR g_DeviceNameBuf[64];
@@ -58,6 +61,7 @@ static NTSTATUS AttachDiskFilters(PDRIVER_OBJECT DriverObject)
UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Driver\\Disk");
UNICODE_STRING sym = RTL_CONSTANT_STRING(L"IoDriverObjectType");
POBJECT_TYPE* pType = (POBJECT_TYPE*)MmGetSystemRoutineAddress(&sym);
if (!pType || !*pType)
return STATUS_NOT_SUPPORTED;
@@ -109,22 +113,79 @@ static NTSTATUS AttachDiskFilters(PDRIVER_OBJECT DriverObject)
return STATUS_SUCCESS;
}
static NTSTATUS AttachFsFilters(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING symDev = RTL_CONSTANT_STRING(L"IoDeviceObjectType");
POBJECT_TYPE* pDevType = (POBJECT_TYPE*)MmGetSystemRoutineAddress(&symDev);
if (!pDevType || !*pDevType)
return STATUS_NOT_SUPPORTED;
NTSTATUS status = STATUS_SUCCESS;
for (ULONG i = 0; g_AttachDisk[i] && g_MbrFilterCount < MAX_MBR_TARGETS; ++i) {
UNICODE_STRING name;
RtlInitUnicodeString(&name, g_AttachDisk[i]);
PDEVICE_OBJECT fsCtl = NULL;
status = ObReferenceObjectByName(&name, OBJ_CASE_INSENSITIVE, NULL, 0, *pDevType, KernelMode, NULL, (PVOID*)&fsCtl);
if (!NT_SUCCESS(status) || !fsCtl)
continue;
PDRIVER_OBJECT fsDrv = fsCtl->DriverObject;
if (fsDrv) {
ULONG need = 0;
status = IoEnumerateDeviceObjectList(fsDrv, NULL, 0, &need);
if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_SUCCESS) {
PDEVICE_OBJECT* list = (PDEVICE_OBJECT*)ExAllocatePool2(POOL_FLAG_NON_PAGED, need * sizeof(PDEVICE_OBJECT), 'fsTA');
if (list) {
status = IoEnumerateDeviceObjectList(fsDrv, list, need * sizeof(PDEVICE_OBJECT), &need);
if (NT_SUCCESS(status)) {
for (ULONG j = 0; j < need && g_MbrFilterCount < MAX_MBR_TARGETS; ++j) {
PDEVICE_OBJECT lower = list[j], filter, attached = NULL;
NTSTATUS s2 = IoCreateDevice(DriverObject, 0, NULL, lower->DeviceType, lower->Characteristics, FALSE, &filter);
if (!NT_SUCCESS(s2))
continue;
filter->Flags |= (lower->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE));
s2 = IoAttachDeviceToDeviceStackSafe(filter, lower, &attached);
if (!NT_SUCCESS(s2) || !attached) {
IoDeleteDevice(filter);
continue;
}
filter->StackSize = lower->StackSize + 1;
filter->AlignmentRequirement = lower->AlignmentRequirement;
filter->DeviceExtension = attached;
filter->Flags &= ~DO_DEVICE_INITIALIZING;
g_MbrFilterTargets[g_MbrFilterCount++] = filter;
}
}
ExFreePool2(list, 'fsTA', NULL, 0);
}
}
}
ObDereferenceObject(fsCtl);
}
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);
KeInitializeSpinLock(&g_ProtectLock);
ExInitializeFastMutex(&HookMutex);
KeInitializeEvent(&g_LogDrainEvent, NotificationEvent, TRUE);
g_Unloading = FALSE;
g_CmRegActive = FALSE;
InterlockedExchange(&g_LogWorkCount, 0);
ExInitializeRundownProtection(&g_Rundown);
{
UNICODE_STRING guardName = RTL_CONSTANT_STRING(L"\\Device\\PYAS_Driver_Guard");
NTSTATUS gs = IoCreateDevice(DriverObject, 0, &guardName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_GuardDevice);
if (!NT_SUCCESS(gs))
if (!NT_SUCCESS(gs))
return STATUS_DEVICE_BUSY;
}
{
@@ -135,12 +196,15 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
g_DeviceName.Length = (USHORT)(wcslen(g_DeviceName.Buffer) * sizeof(WCHAR));
}
NTSTATUS status = IoCreateDevice(DriverObject, 0, &g_DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_ControlDeviceObject);
if (!NT_SUCCESS(status))
if (!NT_SUCCESS(status))
return status;
DriverObject->DriverUnload = DriverUnload;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
DriverObject->MajorFunction[i] = CombinedDispatch;
DriverObject->Flags |= 0x20;
g_ControlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
IoDeleteSymbolicLink(&g_SymLink);
{
@@ -149,6 +213,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
status = IoCreateSymbolicLink(&g_SymLink, &g_DeviceName);
if (NT_SUCCESS(status))
break;
LARGE_INTEGER d = { 0 };
d.QuadPart = -10LL * 1000LL * 10LL;
KeDelayExecutionThread(KernelMode, FALSE, &d);
@@ -157,10 +222,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
if (!NT_SUCCESS(status)) {
IoDeleteDevice(g_ControlDeviceObject);
g_ControlDeviceObject = NULL;
if (g_GuardDevice) {
IoDeleteDevice(g_GuardDevice);
g_GuardDevice = NULL;
}
if (g_GuardDevice) { IoDeleteDevice(g_GuardDevice); g_GuardDevice = NULL; }
return status;
}
}
@@ -171,12 +233,28 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
LARGE_INTEGER t = KeQueryPerformanceCounter(NULL);
RtlStringCchPrintfW(regAltBuf, RTL_NUMBER_OF(regAltBuf), L"385100.%I64x", t.QuadPart);
RtlInitUnicodeString(&regAlt, regAltBuf);
status = CmRegisterCallbackEx(RegistryProtectCallback, &regAlt, DriverObject, NULL, &g_CmRegHandle, NULL);
if (NT_SUCCESS(status))
if (NT_SUCCESS(status))
g_CmRegActive = TRUE;
}
InitImageProtect();
InitInjectProtect();
InitRemoteProtect();
InitScreenProtect();
{
NTSTATUS ps = InitProcessProtect();
if (!NT_SUCCESS(ps)) {
CHAR b[64] = { 0 };
RtlStringCchPrintfA(b, RTL_NUMBER_OF(b), "PROC_INIT | 0x%08X", ps);
SendPipeLog(b, strlen(b));
}
else {
static CHAR ok[] = "PROC_INIT | 0x00000000";
SendPipeLog(ok, sizeof(ok) - 1);
}
}
AttachFsFilters(DriverObject);
AttachDiskFilters(DriverObject);
return STATUS_SUCCESS;
}
@@ -184,6 +262,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
g_Unloading = TRUE;
if (g_SymLinkCreated) {
IoDeleteSymbolicLink(&g_SymLink);
@@ -195,7 +274,14 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject)
}
UninitInjectProtect();
UninitImageProtect();
UninitRemoteProtect();
UninitScreenProtect();
UninitProcessProtect();
ExWaitForRundownProtectionRelease(&g_Rundown);
if (InterlockedCompareExchange((volatile LONG*)&g_LogWorkCount, 0, 0) != 0) {
KeWaitForSingleObject(&g_LogDrainEvent, Executive, KernelMode, FALSE, NULL);
}
if (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) {
KeResetEvent(&g_LogDrainEvent);
while (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0)
@@ -221,4 +307,4 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject)
IoDeleteDevice(g_GuardDevice);
g_GuardDevice = NULL;
}
}
}
+40 -9
View File
@@ -2,13 +2,17 @@
#include <ntifs.h>
#include <ntstrsafe.h>
#include <ntdddisk.h>
#include <ntddscsi.h>
#define PIPE_NAME L"\\??\\pipe\\PYAS_Output_Pipe"
#define MAX_MBR_TARGETS 52
#define MAX_MBR_TARGETS 256
#ifndef POOL_FLAG_NON_PAGED
#define POOL_FLAG_NON_PAGED 0x00000001
#endif
#ifndef PROCESS_TERMINATE
#define PROCESS_TERMINATE 0x0001
#endif
#ifndef PROCESS_CREATE_THREAD
#define PROCESS_CREATE_THREAD 0x0002
#endif
@@ -42,16 +46,35 @@
#ifndef PROCESS_SET_LIMITED_INFORMATION
#define PROCESS_SET_LIMITED_INFORMATION 0x2000
#endif
#ifndef THREAD_TERMINATE
#define THREAD_TERMINATE 0x0001
#endif
#ifndef THREAD_SUSPEND_RESUME
#define THREAD_SUSPEND_RESUME 0x0002
#endif
#ifndef THREAD_SET_CONTEXT
#define THREAD_SET_CONTEXT 0x0010
#endif
#ifndef THREAD_IMPERSONATE
#define THREAD_IMPERSONATE 0x0100
#endif
#ifndef THREAD_DIRECT_IMPERSONATION
#define THREAD_DIRECT_IMPERSONATION 0x0200
#endif
#ifndef JOB_OBJECT_ASSIGN_PROCESS
#define JOB_OBJECT_ASSIGN_PROCESS 0x0001
#endif
#ifndef JOB_OBJECT_TERMINATE
#define JOB_OBJECT_TERMINATE 0x0008
#endif
#ifndef FILE_DISPOSITION_DELETE
#define FILE_DISPOSITION_DELETE 0x00000001
#endif
#ifndef UINT
typedef unsigned int UINT;
#endif
extern POBJECT_TYPE* PsJobType;
extern volatile LONG g_LogWorkCount;
extern BOOLEAN g_Unloading;
extern KEVENT g_LogDrainEvent;
@@ -60,6 +83,7 @@ extern ULONG g_MbrFilterCount;
extern KSPIN_LOCK g_ProtectLock;
extern LARGE_INTEGER g_CmRegHandle;
extern POBJECT_TYPE* IoDriverObjectType;
extern POBJECT_TYPE* IoFileObjectType;
extern FAST_MUTEX HookMutex;
extern PDRIVER_OBJECT DiskDrvObj;
extern PCSTR PsGetProcessImageFileName(PEPROCESS Process);
@@ -74,14 +98,14 @@ typedef VOID(NTAPI* _pyas_ExFreePoolWithTag)(PVOID, ULONG);
static __forceinline PVOID PYAS_ExAllocatePool2(ULONG f, SIZE_T s, ULONG t) {
static _pyas_ExAllocatePool2 p2 = 0;
if (!p2) {
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePool2");
p2 = (_pyas_ExAllocatePool2)MmGetSystemRoutineAddress(&n);
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePool2");
p2 = (_pyas_ExAllocatePool2)MmGetSystemRoutineAddress(&n);
}
if (p2)
return p2(f, s, t);
static _pyas_ExAllocatePoolWithTag p1 = 0;
if (!p1) {
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePoolWithTag");
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePoolWithTag");
p1 = (_pyas_ExAllocatePoolWithTag)MmGetSystemRoutineAddress(&n);
}
if (p1)
@@ -92,9 +116,10 @@ static __forceinline PVOID PYAS_ExAllocatePool2(ULONG f, SIZE_T s, ULONG t) {
static __forceinline VOID PYAS_ExFreePool2(PVOID a, ULONG t, PVOID h, ULONG f) {
UNREFERENCED_PARAMETER(h);
UNREFERENCED_PARAMETER(f);
static _pyas_ExFreePool2 p2 = 0;
if (!p2) {
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExFreePool2");
if (!p2) {
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExFreePool2");
p2 = (_pyas_ExFreePool2)MmGetSystemRoutineAddress(&n);
}
if (p2) {
@@ -102,13 +127,13 @@ static __forceinline VOID PYAS_ExFreePool2(PVOID a, ULONG t, PVOID h, ULONG f) {
return;
}
static _pyas_ExFreePoolWithTag p1 = 0;
if (!p1) {
if (!p1) {
UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExFreePoolWithTag");
p1 = (_pyas_ExFreePoolWithTag)MmGetSystemRoutineAddress(&n);
}
if (p1) {
if (p1) {
p1(a, t);
return;
return;
}
}
@@ -119,6 +144,9 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject);
VOID SendPipeLog(PCSTR msg, SIZE_T len);
VOID UninitImageProtect(VOID);
VOID UninitInjectProtect(VOID);
VOID UninitRemoteProtect(VOID);
VOID UninitScreenProtect(VOID);
VOID UninitProcessProtect(VOID);
NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess(
_In_ HANDLE ProcessHandle,
@@ -143,5 +171,8 @@ NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2);
NTSTATUS InitImageProtect(VOID);
NTSTATUS InitInjectProtect(VOID);
NTSTATUS InitRemoteProtect(VOID);
NTSTATUS InitScreenProtect(VOID);
NTSTATUS InitProcessProtect(VOID);
BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath);
+5 -6
View File
@@ -17,19 +17,20 @@ static VOID PipeLogWork(PDEVICE_OBJECT DeviceObject, PVOID Context)
UNICODE_STRING name;
OBJECT_ATTRIBUTES oa = { 0 };
IO_STATUS_BLOCK iosb;
RtlInitUnicodeString(&name, PIPE_NAME);
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
if (NT_SUCCESS(ZwCreateFile(&h, FILE_GENERIC_WRITE, &oa, &iosb, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0)))
{
if (NT_SUCCESS(ZwCreateFile(&h, FILE_GENERIC_WRITE, &oa, &iosb, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0))) {
ZwWriteFile(h, NULL, NULL, NULL, &iosb, ctx->Buf, (ULONG)(ctx->Len > 0xFFFFFFFF ? 0xFFFFFFFF : ctx->Len), NULL, NULL);
ZwClose(h);
}
IoFreeWorkItem(ctx->Item);
ExFreePool2(ctx->Buf, 'golP', NULL, 0);
ExFreePool2(ctx, 'golP', NULL, 0);
if (InterlockedDecrement(&g_LogWorkCount) == 0 && g_Unloading)
if (InterlockedDecrement(&g_LogWorkCount) == 0) {
KeSetEvent(&g_LogDrainEvent, IO_NO_INCREMENT, FALSE);
}
}
VOID SendPipeLog(PCSTR msg, SIZE_T len)
@@ -40,11 +41,9 @@ VOID SendPipeLog(PCSTR msg, SIZE_T len)
return;
if (g_Unloading)
return;
PPIPE_LOG_CTX ctx = (PPIPE_LOG_CTX)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(PIPE_LOG_CTX), 'golP');
if (!ctx)
return;
ctx->Len = len;
ctx->Buf = (PCHAR)ExAllocatePool2(POOL_FLAG_NON_PAGED, ctx->Len, 'golP');
if (!ctx->Buf) {
-123
View File
@@ -1,123 +0,0 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectRules.h"
PDEVICE_OBJECT g_MbrFilterTargets[MAX_MBR_TARGETS] = { 0 };
ULONG g_MbrFilterCount = 0;
NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PDEVICE_OBJECT lower = (PDEVICE_OBJECT)DeviceObject->DeviceExtension;
if (!lower) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
if (!ExAcquireRundownProtection(&g_Rundown)) {
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(lower, Irp);
}
if (g_Unloading) {
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS st = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return st;
}
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
if (stack->MajorFunction == IRP_MJ_POWER) {
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS st = PoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return st;
}
HANDLE pid = PsGetCurrentProcessId();
ULONG currentPid = (ULONG)(ULONG_PTR)pid;
if (currentPid == 0 || currentPid == 4) {
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS st = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return st;
}
BOOLEAN blocked = FALSE, is_white = FALSE;
CHAR logbuf[1024] = { 0 };
WCHAR exeBuf[512] = { 0 };
UNICODE_STRING exeName = { 0 };
exeName.Buffer = exeBuf;
exeName.MaximumLength = sizeof(exeBuf);
exeName.Length = 0;
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
if (GetProcessImagePathByPid(pid, &exeName))
is_white = IsWhitelist(&exeName);
else {
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++)
exeBuf[i] = (WCHAR)n[i];
exeBuf[l] = 0;
exeName.Length = (USHORT)(l * sizeof(WCHAR));
}
}
if (!is_white) {
UCHAR mj = stack->MajorFunction;
BOOLEAN isDisk = (DeviceObject->DeviceType == FILE_DEVICE_DISK);
if (!isDisk) {
PDEVICE_OBJECT tdo = IoGetAttachedDeviceReference(lower);
if (tdo) {
isDisk = (tdo->DeviceType == FILE_DEVICE_DISK || tdo->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM);
ObDereferenceObject(tdo);
}
}
if (isDisk) {
if (mj == IRP_MJ_WRITE || mj == IRP_MJ_SET_INFORMATION || mj == IRP_MJ_DEVICE_CONTROL || mj == IRP_MJ_INTERNAL_DEVICE_CONTROL) blocked = TRUE;
}
}
if (blocked) {
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
CHAR target[64] = "None";
ULONG ret = 0;
POBJECT_NAME_INFORMATION oni = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, 1024, 'nOmD');
if (oni && NT_SUCCESS(ObQueryNameString(lower, oni, 1024, &ret)) && oni->Name.Buffer && oni->Name.Length >= sizeof(WCHAR) * 2) {
USHORT len = oni->Name.Length / sizeof(WCHAR);
ULONG dr = 0;
BOOLEAN hasDr = FALSE;
for (USHORT i = 0; i + 2 < len; i++) {
if (oni->Name.Buffer[i] == L'D' && oni->Name.Buffer[i + 1] == L'R') {
USHORT j = i + 2;
ULONG x = 0;
while (j < len && oni->Name.Buffer[j] >= L'0' && oni->Name.Buffer[j] <= L'9') {
x = x * 10 + (oni->Name.Buffer[j] - L'0');
j++;
}
dr = x;
hasDr = TRUE;
break;
}
}
if (hasDr)
RtlStringCchPrintfA(target, sizeof(target), "Disk\\Device\\DR%u", dr);
}
if (oni)
ExFreePool2(oni, 'nOmD', NULL, 0);
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "BOOT_BLOCK | %u | %wZ | %s", currentPid, &exeName, target);
SendPipeLog(logbuf, strlen(logbuf));
}
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ExReleaseRundownProtection(&g_Rundown);
return STATUS_ACCESS_DENIED;
}
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS st = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return st;
}
+323
View File
@@ -0,0 +1,323 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectMatch.h"
static BOOLEAN GetFilePathFromFileObject(PFILE_OBJECT fo, PUNICODE_STRING out)
{
if (!fo || !out || !out->Buffer || out->MaximumLength == 0)
return FALSE;
out->Length = 0;
if (fo->DeviceObject && fo->FileName.Buffer && fo->FileName.Length) {
ULONG need = 0;
NTSTATUS s = ObQueryNameString(fo->DeviceObject, NULL, 0, &need);
if (s == STATUS_INFO_LENGTH_MISMATCH && need > 0) {
POBJECT_NAME_INFORMATION oni = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, need, 'nOmD');
if (oni) {
if (NT_SUCCESS(ObQueryNameString(fo->DeviceObject, oni, need, &need)) && oni->Name.Buffer && oni->Name.Length) {
ULONG total = oni->Name.Length + fo->FileName.Length;
if (total + sizeof(WCHAR) <= out->MaximumLength) {
RtlCopyMemory(out->Buffer, oni->Name.Buffer, oni->Name.Length);
RtlCopyMemory((PUCHAR)out->Buffer + oni->Name.Length, fo->FileName.Buffer, fo->FileName.Length);
out->Length = (USHORT)total;
out->Buffer[total / sizeof(WCHAR)] = 0;
ExFreePool2(oni, 'nOmD', NULL, 0);
return TRUE;
}
}
ExFreePool2(oni, 'nOmD', NULL, 0);
}
}
}
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES oa = { 0 };
IO_STATUS_BLOCK iosb;
InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
if (!NT_SUCCESS(ObOpenObjectByPointer(fo, OBJ_KERNEL_HANDLE, NULL, FILE_READ_ATTRIBUTES, *IoFileObjectType, KernelMode, &hFile)))
return FALSE;
ULONG buflen = sizeof(FILE_NAME_INFORMATION) + 2048 * sizeof(WCHAR);
PFILE_NAME_INFORMATION pfi = (PFILE_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, buflen, 'nIIF');
if (!pfi) {
ZwClose(hFile);
return FALSE;
}
RtlZeroMemory(pfi, buflen);
NTSTATUS st = ZwQueryInformationFile(hFile, &iosb, pfi, buflen, FileNormalizedNameInformation);
if (NT_SUCCESS(st) && pfi->FileNameLength > 0 && pfi->FileNameLength + sizeof(WCHAR) <= out->MaximumLength) {
RtlCopyMemory(out->Buffer, pfi->FileName, pfi->FileNameLength);
out->Length = (USHORT)pfi->FileNameLength;
out->Buffer[out->Length / sizeof(WCHAR)] = 0;
ExFreePool2(pfi, 'nIIF', NULL, 0);
ZwClose(hFile);
return TRUE;
}
ExFreePool2(pfi, 'nIIF', NULL, 0);
ZwClose(hFile);
return FALSE;
}
static BOOLEAN WantDelete(PIRP Irp, PIO_STACK_LOCATION s)
{
if (s->MajorFunction != IRP_MJ_SET_INFORMATION)
return FALSE;
FILE_INFORMATION_CLASS c = s->Parameters.SetFile.FileInformationClass;
if (c == FileDispositionInformation) {
PFILE_DISPOSITION_INFORMATION di = (PFILE_DISPOSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
return di && di->DeleteFile;
}
if (c == FileDispositionInformationEx) {
PFILE_DISPOSITION_INFORMATION_EX dx = (PFILE_DISPOSITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
return dx && (dx->Flags & FILE_DISPOSITION_DELETE);
}
return FALSE;
}
static BOOLEAN WantRename(PIRP Irp, PIO_STACK_LOCATION s)
{
if (s->MajorFunction != IRP_MJ_SET_INFORMATION)
return FALSE;
FILE_INFORMATION_CLASS c = s->Parameters.SetFile.FileInformationClass;
if (c == FileRenameInformation || c == FileRenameInformationEx)
return Irp->AssociatedIrp.SystemBuffer != NULL;
return FALSE;
}
static VOID GetExeNameForLog(HANDLE pid, PUNICODE_STRING exe)
{
if (!exe || !exe->Buffer || exe->MaximumLength == 0)
return;
exe->Length = 0;
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
if (GetProcessImagePathByPid(pid, exe))
return;
}
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < (exe->MaximumLength / sizeof(WCHAR)) - 1; i++)
exe->Buffer[i] = (WCHAR)n[i];
exe->Buffer[l] = 0;
exe->Length = (USHORT)(l * sizeof(WCHAR));
}
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
static BOOLEAN QueryDevName(PDEVICE_OBJECT dev, PUNICODE_STRING out)
{
if (!dev || !out || !out->Buffer || out->MaximumLength == 0)
return FALSE;
ULONG need = 0;
NTSTATUS s = ObQueryNameString(dev, NULL, 0, &need);
if (s != STATUS_INFO_LENGTH_MISMATCH || need == 0)
return FALSE;
POBJECT_NAME_INFORMATION oni = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, need, 'nOmD');
if (!oni)
return FALSE;
BOOLEAN ok = FALSE;
s = ObQueryNameString(dev, oni, need, &need);
if (NT_SUCCESS(s) && oni->Name.Buffer && oni->Name.Length && oni->Name.Length < out->MaximumLength) {
RtlCopyMemory(out->Buffer, oni->Name.Buffer, oni->Name.Length);
out->Length = (USHORT)oni->Name.Length;
out->Buffer[out->Length / sizeof(WCHAR)] = 0;
ok = TRUE;
}
ExFreePool2(oni, 'nOmD', NULL, 0);
return ok;
}
static BOOLEAN IsDASDRoot(PFILE_OBJECT fo)
{
if (!fo)
return TRUE;
if (fo->FileName.Length == 0 && fo->RelatedFileObject == NULL)
return TRUE;
return FALSE;
}
static BOOLEAN IsDangerousDiskIo(PIO_STACK_LOCATION s)
{
if (!s)
return FALSE;
if (s->MajorFunction == IRP_MJ_DEVICE_CONTROL || s->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
ULONG code = s->Parameters.DeviceIoControl.IoControlCode;
if (code == IOCTL_SCSI_PASS_THROUGH || code == IOCTL_SCSI_PASS_THROUGH_DIRECT)
return TRUE;
if (code == IOCTL_DISK_SET_DRIVE_LAYOUT || code == IOCTL_DISK_SET_DRIVE_LAYOUT_EX)
return TRUE;
if (code == IOCTL_DISK_DELETE_DRIVE_LAYOUT)
return TRUE;
if (code == IOCTL_DISK_FORMAT_TRACKS || code == IOCTL_DISK_FORMAT_TRACKS_EX)
return TRUE;
if (code == IOCTL_DISK_SET_PARTITION_INFO || code == IOCTL_DISK_SET_PARTITION_INFO_EX)
return TRUE;
return FALSE;
}
if (s->MajorFunction == IRP_MJ_SCSI)
return TRUE;
if (s->MajorFunction == IRP_MJ_WRITE || s->MajorFunction == IRP_MJ_FLUSH_BUFFERS)
return TRUE;
return FALSE;
}
NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PDEVICE_OBJECT lower = (PDEVICE_OBJECT)DeviceObject->DeviceExtension;
if (!lower) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
if (!ExAcquireRundownProtection(&g_Rundown)) {
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(lower, Irp);
}
if (g_Unloading) {
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS rs = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return rs;
}
PIO_STACK_LOCATION s = IoGetCurrentIrpStackLocation(Irp);
if (s->MajorFunction == IRP_MJ_POWER) {
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS ps = PoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return ps;
}
HANDLE pid = PsGetCurrentProcessId();
ULONG upid = (ULONG)(ULONG_PTR)pid;
if (upid == 0 || upid == 4) {
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS ns = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return ns;
}
BOOLEAN blocked = FALSE;
BOOLEAN isWrite = (s->MajorFunction == IRP_MJ_WRITE);
BOOLEAN isDeleteReq = WantDelete(Irp, s);
BOOLEAN isRenameReq = WantRename(Irp, s);
BOOLEAN canQuery = (KeGetCurrentIrql() == PASSIVE_LEVEL);
WCHAR eb[512] = { 0 };
UNICODE_STRING exe = { 0 };
exe.Buffer = eb;
exe.MaximumLength = sizeof(eb);
if (canQuery) {
GetExeNameForLog(pid, &exe);
if (IsWhitelist(&exe)) {
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS ns2 = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return ns2;
}
}
if (lower->DeviceType == FILE_DEVICE_DISK) {
if (IsDangerousDiskIo(s)) {
BOOLEAN hit = FALSE;
WCHAR db[512] = { 0 };
UNICODE_STRING dev = { 0 };
dev.Buffer = db;
dev.MaximumLength = sizeof(db);
if (canQuery && QueryDevName(lower, &dev)) {
if (MatchBlockFile(&dev))
hit = TRUE;
}
else {
hit = TRUE;
}
if (!hit && s->FileObject && canQuery) {
WCHAR nb[512] = { 0 };
UNICODE_STRING n2 = { 0 };
n2.Buffer = nb;
n2.MaximumLength = sizeof(nb);
if (QueryDevName(s->FileObject->DeviceObject, &n2)) {
if (MatchBlockFile(&n2))
hit = TRUE;
}
}
if (!hit && s->MajorFunction == IRP_MJ_WRITE && s->FileObject && IsDASDRoot(s->FileObject))
hit = TRUE;
if (hit) {
blocked = TRUE;
if (canQuery) {
if (dev.Length == 0)
QueryDevName(lower, &dev);
LogAnsi3("BOOT_BLOCK", upid, &exe, dev.Length ? &dev : &exe);
}
}
}
}
if (!blocked && (isWrite || isDeleteReq || isRenameReq) && s->FileObject && canQuery) {
WCHAR pb[1024] = { 0 };
UNICODE_STRING path = { 0 };
path.Buffer = pb;
path.MaximumLength = sizeof(pb);
if (GetFilePathFromFileObject(s->FileObject, &path)) {
BOOLEAN hitFile = MatchBlockFile(&path);
BOOLEAN hitRansom = MatchBlockRansom(&path) && HasBlockedSuffix(&path);
if (hitFile || hitRansom) {
blocked = TRUE;
LogAnsi3(hitFile && !hitRansom ? "FILE_BLOCK" : "RANSOM_BLOCK", upid, &exe, &path);
}
}
else {
ULONG need = 0;
POBJECT_NAME_INFORMATION dev = NULL;
NTSTATUS qs2 = ObQueryNameString(s->FileObject->DeviceObject, NULL, 0, &need);
if (qs2 == STATUS_INFO_LENGTH_MISMATCH && need > 0) {
dev = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, need, 'dOnF');
if (dev && NT_SUCCESS(ObQueryNameString(s->FileObject->DeviceObject, dev, need, &need)) && dev->Name.Buffer && dev->Name.Length) {
if (MatchBlockFile(&dev->Name)) {
blocked = TRUE;
UNICODE_STRING rule = { 0 };
rule.Buffer = GetMatchedBlockFileRule(&dev->Name);
rule.Length = rule.Buffer ? (USHORT)(wcslen(rule.Buffer) * sizeof(WCHAR)) : 0;
rule.MaximumLength = rule.Length;
LogAnsi3("FILE_BLOCK", upid, &exe, rule.Buffer ? &rule : &dev->Name);
}
}
if (dev)
ExFreePool2(dev, 'dOnF', NULL, 0);
}
}
}
if (blocked) {
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ExReleaseRundownProtection(&g_Rundown);
return STATUS_ACCESS_DENIED;
}
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS rs2 = IoCallDriver(lower, Irp);
ExReleaseRundownProtection(&g_Rundown);
return rs2;
}
+56 -78
View File
@@ -1,39 +1,15 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectRules.h"
#include "ProtectMatch.h"
static BOOLEAN g_ImageNotifyEnabled = FALSE;
static BOOLEAN StrStrI(const wchar_t* s, const wchar_t* sub) {
if (!s || !sub)
return FALSE;
size_t n = wcslen(s), m = wcslen(sub);
if (m == 0 || n < m)
return FALSE;
for (size_t i = 0; i + m <= n; i++) {
size_t j = 0;
for (; j < m; j++) {
WCHAR a = s[i + j], b = sub[j];
if (a >= L'A' && a <= L'Z')
a += 32;
if (b >= L'A' && b <= L'Z')
b += 32;
if (a != b)
break;
}
if (j == m)
return TRUE;
}
return FALSE;
}
static BOOLEAN CheckStackVAD(PVOID a) {
static BOOLEAN CheckVadExec(PVOID a)
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
SIZE_T ret = 0;
NTSTATUS s = ZwQueryVirtualMemory(NtCurrentProcess(), a, MemoryBasicInformation, &mbi, sizeof(mbi), &ret);
if (!NT_SUCCESS(s))
return FALSE;
if (mbi.State != MEM_COMMIT)
@@ -45,7 +21,8 @@ static BOOLEAN CheckStackVAD(PVOID a) {
return (mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
}
static BOOLEAN CheckShellcodeWalkStack(ULONG h) {
static BOOLEAN WalkForShellcode(ULONG h)
{
#define MAXWALK 20
PVOID frames[MAXWALK] = { 0 };
ULONG c = RtlWalkFrameChain(frames, MAXWALK, 1);
@@ -58,99 +35,100 @@ static BOOLEAN CheckShellcodeWalkStack(ULONG h) {
for (ULONG i = 0; i < d; i++) {
PVOID p = frames[i];
if (p && CheckStackVAD(p))
if (p && CheckVadExec(p))
return TRUE;
}
for (ULONG i = 0; i < d; i++) {
ULONG idx = count - 1 - i;
if (idx >= d) {
PVOID p = frames[idx];
if (p && CheckStackVAD(p))
if (p && CheckVadExec(p))
return TRUE;
}
}
return FALSE;
}
static BOOLEAN IsFrameworkClrPath(const wchar_t* s) {
if (!s)
return FALSE;
if (!StrStrI(s, L"\\Windows\\Microsoft.NET\\"))
return FALSE;
if (!StrStrI(s, L"\\Framework\\") && !StrStrI(s, L"\\Framework64\\"))
return FALSE;
if (StrStrI(s, L"\\clr.dll") || StrStrI(s, L"\\mscorwks.dll"))
return TRUE;
return FALSE;
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
static VOID ImageLoadNotify(IN PUNICODE_STRING FullImageName, IN HANDLE ProcessId, IN PIMAGE_INFO ImageInfo)
{
UNREFERENCED_PARAMETER(ImageInfo);
if (g_Unloading)
if (g_Unloading)
return;
if (ProcessId == (HANDLE)0 || ProcessId == (HANDLE)4)
if (ProcessId == (HANDLE)0 || ProcessId == (HANDLE)4)
return;
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
return;
if (!ExAcquireRundownProtection(&g_Rundown))
return;
WCHAR exeBuf[512] = { 0 };
UNICODE_STRING exeName = { 0 };
exeName.Buffer = exeBuf;
exeName.MaximumLength = sizeof(exeBuf);
exeName.Length = 0;
if (!GetProcessImagePathByPid(ProcessId, &exeName)) {
WCHAR eb[512] = { 0 };
UNICODE_STRING exe = { 0 };
exe.Buffer = eb;
exe.MaximumLength = sizeof(eb);
exe.Length = 0;
if (!GetProcessImagePathByPid(ProcessId, &exe)) {
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++)
exeBuf[i] = (WCHAR)n[i];
exeBuf[l] = 0;
exeName.Length = (USHORT)(l * sizeof(WCHAR));
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(eb) - 1; i++)
eb[i] = (WCHAR)n[i];
eb[l] = 0;
exe.Length = (USHORT)(l * sizeof(WCHAR));
}
if (exeName.Length & 1) exeName.Length--;
if (exe.Length & 1) exe.Length--;
{
size_t elen = exeName.Length / sizeof(WCHAR);
if ((elen >= 14 && _wcsnicmp(exeName.Buffer + elen - 14, L"powershell.exe", 14) == 0) ||
(elen >= 8 && _wcsnicmp(exeName.Buffer + elen - 8, L"pwsh.exe", 8) == 0)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
}
if (IsWhitelist(&exeName)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
CHAR logbuf[1024] = { 0 };
if (FullImageName && FullImageName->Buffer) {
if ((StrStrI(FullImageName->Buffer, L"clr.dll") || StrStrI(FullImageName->Buffer, L"mscorwks.dll")) && !IsFrameworkClrPath(FullImageName->Buffer)) {
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "CLR_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)ProcessId, &exeName, FullImageName);
SendPipeLog(logbuf, strlen(logbuf));
size_t elen = exe.Length / sizeof(WCHAR);
if ((elen >= 14 && _wcsnicmp(exe.Buffer + elen - 14, L"powershell.exe", 14) == 0) ||
(elen >= 8 && _wcsnicmp(exe.Buffer + elen - 8, L"pwsh.exe", 8) == 0)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
}
if (CheckShellcodeWalkStack(8)) {
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "SHELLCODE_BLOCK | %u | %wZ | None", (ULONG)(ULONG_PTR)ProcessId, &exeName);
SendPipeLog(logbuf, strlen(logbuf));
if (IsWhitelist(&exe)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
if (FullImageName && FullImageName->Buffer) {
if (MatchClrFromNonFramework(FullImageName)) {
LogAnsi3("CLR_BLOCK", (ULONG)(ULONG_PTR)ProcessId, &exe, FullImageName);
ExReleaseRundownProtection(&g_Rundown);
return;
}
}
if (WalkForShellcode(8)) {
UNICODE_STRING none = RTL_CONSTANT_STRING(L"None");
LogAnsi3("SHELLCODE_BLOCK", (ULONG)(ULONG_PTR)ProcessId, &exe, &none);
ExReleaseRundownProtection(&g_Rundown);
return;
}
ExReleaseRundownProtection(&g_Rundown);
}
NTSTATUS InitImageProtect(VOID) {
NTSTATUS InitImageProtect(VOID)
{
NTSTATUS s = PsSetLoadImageNotifyRoutine(ImageLoadNotify);
if (NT_SUCCESS(s))
g_ImageNotifyEnabled = TRUE;
return s;
}
VOID UninitImageProtect(VOID) {
VOID UninitImageProtect(VOID)
{
if (g_ImageNotifyEnabled) {
PsRemoveLoadImageNotifyRoutine(ImageLoadNotify);
g_ImageNotifyEnabled = FALSE;
+51 -48
View File
@@ -1,32 +1,45 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectRules.h"
#include "ProtectMatch.h"
static PVOID g_ObRegHandle = NULL;
static POB_OPERATION_REGISTRATION g_ObOps = NULL;
static OB_CALLBACK_REGISTRATION g_ObReg = { 0 };
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info)
{
UNREFERENCED_PARAMETER(RegistrationContext);
if (g_Unloading)
return OB_PREOP_SUCCESS;
if (!Info || Info->KernelHandle)
if (!Info || Info->KernelHandle)
return OB_PREOP_SUCCESS;
if (!Info->Object)
return OB_PREOP_SUCCESS;
if (Info->Operation != OB_OPERATION_HANDLE_CREATE && Info->Operation != OB_OPERATION_HANDLE_DUPLICATE)
return OB_PREOP_SUCCESS;
if (!ExAcquireRundownProtection(&g_Rundown))
if (!ExAcquireRundownProtection(&g_Rundown))
return OB_PREOP_SUCCESS;
HANDLE cur = PsGetCurrentProcessId();
if (cur == (HANDLE)0 || cur == (HANDLE)4) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
return OB_PREOP_SUCCESS;
}
HANDLE target = PsGetProcessId((PEPROCESS)Info->Object);
if (target == cur) {
if (target == cur) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
@@ -35,9 +48,9 @@ static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, PO
PCSTR tn = PsGetProcessImageFileName((PEPROCESS)Info->Object);
if (tn && (_stricmp(tn, "lsass.exe") == 0))
mask |= PROCESS_VM_READ;
if ((*desired & mask) == 0) {
ExReleaseRundownProtection(&g_Rundown);
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
BOOLEAN logok = (KeGetCurrentIrql() == PASSIVE_LEVEL);
@@ -45,31 +58,27 @@ static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, PO
UNICODE_STRING cexe = { 0 }, texe = { 0 };
cexe.Buffer = cbuf; cexe.MaximumLength = sizeof(cbuf);
texe.Buffer = tbuf; texe.MaximumLength = sizeof(tbuf);
if (logok)
if (logok)
GetProcessImagePathByPid(cur, &cexe);
if (logok && IsWhitelist(&cexe)) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
if (logok && IsWhitelist(&cexe)) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
ACCESS_MASK old = *desired;
*desired &= ~mask;
if ((*desired) != old && logok) {
GetProcessImagePathByPid(target, &texe);
if (cexe.Length == 0) {
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++)
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++)
cbuf[i] = (WCHAR)n[i];
cbuf[l] = 0;
cexe.Length = (USHORT)(l * sizeof(WCHAR));
}
CHAR logbuf[1024] = { 0 };
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "INJECT_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)cur, &cexe, &texe);
SendPipeLog(logbuf, strlen(logbuf));
LogAnsi3("INJECT_BLOCK", (ULONG)(ULONG_PTR)cur, &cexe, &texe);
}
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
@@ -78,29 +87,29 @@ static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, PO
static OB_PREOP_CALLBACK_STATUS PreThreadCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info)
{
UNREFERENCED_PARAMETER(RegistrationContext);
if (!Info || Info->KernelHandle)
if (!Info || Info->KernelHandle)
return OB_PREOP_SUCCESS;
if (Info->Object == NULL)
if (Info->Object == NULL)
return OB_PREOP_SUCCESS;
if (Info->Operation != OB_OPERATION_HANDLE_CREATE && Info->Operation != OB_OPERATION_HANDLE_DUPLICATE)
return OB_PREOP_SUCCESS;
if (!ExAcquireRundownProtection(&g_Rundown))
if (!ExAcquireRundownProtection(&g_Rundown))
return OB_PREOP_SUCCESS;
HANDLE cur = PsGetCurrentProcessId();
if (cur == (HANDLE)0 || cur == (HANDLE)4) {
if (cur == (HANDLE)0 || cur == (HANDLE)4) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
return OB_PREOP_SUCCESS;
}
HANDLE owner = PsGetThreadProcessId((PETHREAD)Info->Object);
if (owner == cur) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
if (owner == cur) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
ACCESS_MASK tmask = THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_IMPERSONATE | THREAD_DIRECT_IMPERSONATION;
ACCESS_MASK* desired = (Info->Operation == OB_OPERATION_HANDLE_CREATE) ? &Info->Parameters->CreateHandleInformation.DesiredAccess : &Info->Parameters->DuplicateHandleInformation.DesiredAccess;
if ((*desired & tmask) == 0) {
ExReleaseRundownProtection(&g_Rundown);
if ((*desired & tmask) == 0) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
BOOLEAN logok = (KeGetCurrentIrql() == PASSIVE_LEVEL);
@@ -108,47 +117,41 @@ static OB_PREOP_CALLBACK_STATUS PreThreadCallback(PVOID RegistrationContext, POB
UNICODE_STRING cexe = { 0 };
cexe.Buffer = cbuf;
cexe.MaximumLength = sizeof(cbuf);
if (logok)
if (logok)
GetProcessImagePathByPid(cur, &cexe);
if (logok && IsWhitelist(&cexe)) {
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
return OB_PREOP_SUCCESS;
}
ACCESS_MASK old = *desired;
*desired &= ~tmask;
if ((*desired) != old && logok) {
CHAR logbuf[1024] = { 0 };
if (cexe.Length == 0) {
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++)
cbuf[i] = (WCHAR)n[i];
cbuf[l] = 0;
cexe.Length = (USHORT)(l * sizeof(WCHAR));
}
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "THREAD_BLOCK | %u | %wZ | %u", (ULONG)(ULONG_PTR)cur, &cexe, (ULONG)(ULONG_PTR)owner);
SendPipeLog(logbuf, strlen(logbuf));
UNICODE_STRING tnone = RTL_CONSTANT_STRING(L"None");
LogAnsi3("THREAD_BLOCK", (ULONG)(ULONG_PTR)cur, &cexe, &tnone);
}
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
NTSTATUS InitInjectProtect(VOID)
NTSTATUS InitInjectProtect(VOID)
{
static WCHAR obAltBuf[32];
static UNICODE_STRING obAlt;
LARGE_INTEGER t = KeQueryPerformanceCounter(NULL);
RtlStringCchPrintfW(obAltBuf, RTL_NUMBER_OF(obAltBuf), L"385000.%I64x", t.QuadPart);
RtlInitUnicodeString(&obAlt, obAltBuf);
RtlInitUnicodeString(&obAlt, L"385000");
g_ObOps = (POB_OPERATION_REGISTRATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(OB_OPERATION_REGISTRATION) * 2, 'bOpr');
if (!g_ObOps)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(g_ObOps, sizeof(OB_OPERATION_REGISTRATION) * 2);
g_ObOps[0].ObjectType = PsProcessType;
g_ObOps[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
@@ -156,14 +159,14 @@ NTSTATUS InitInjectProtect(VOID)
g_ObOps[1].ObjectType = PsThreadType;
g_ObOps[1].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
g_ObOps[1].PreOperation = PreThreadCallback;
RtlZeroMemory(&g_ObReg, sizeof(g_ObReg));
g_ObReg.Version = OB_FLT_REGISTRATION_VERSION;
g_ObReg.OperationRegistrationCount = 2;
g_ObReg.Altitude = obAlt;
g_ObReg.RegistrationContext = NULL;
g_ObReg.OperationRegistration = g_ObOps;
NTSTATUS s = ObRegisterCallbacks(&g_ObReg, &g_ObRegHandle);
if (!NT_SUCCESS(s)) {
ExFreePool2(g_ObOps, 'bOpr', NULL, 0);
@@ -175,7 +178,7 @@ NTSTATUS InitInjectProtect(VOID)
VOID UninitInjectProtect(VOID)
{
if (g_ObRegHandle) {
if (g_ObRegHandle) {
ObUnRegisterCallbacks(g_ObRegHandle);
g_ObRegHandle = NULL;
}
+372
View File
@@ -0,0 +1,372 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectRules.h"
#include "ProtectMatch.h"
static BOOLEAN WildMatchN(const wchar_t* str, SIZE_T n, const wchar_t* pat)
{
if (*pat == 0)
return n == 0;
if (*pat == L'*') {
if (pat[1] == L'*') {
for (SIZE_T i = 0; i <= n; ++i)
if (WildMatchN(str + i, n - i, pat + 2))
return TRUE;
return FALSE;
}
SIZE_T i = 0;
for (; i < n && str[i] != L'\\'; ++i)
if (WildMatchN(str + i, n - i, pat + 1))
return TRUE;
return WildMatchN(str + i, n - i, pat + 1);
}
if (*pat == L'?')
return n > 0 && str[0] != L'\\' && WildMatchN(str + 1, n - 1, pat + 1);
if (n == 0)
return FALSE;
WCHAR sc = str[0], pc = *pat;
if (sc >= L'A' && sc <= L'Z')
sc += 32;
if (pc >= L'A' && pc <= L'Z')
pc += 32;
return sc == pc && WildMatchN(str + 1, n - 1, pat + 1);
}
static BOOLEAN MatchList(PUNICODE_STRING s, wchar_t** list)
{
if (!s || !s->Buffer || s->Length == 0)
return FALSE;
size_t s_len = s->Length / sizeof(WCHAR);
for (SIZE_T i = 0; list[i]; ++i) {
wchar_t* pat = list[i];
size_t pat_len = wcslen(pat);
if (wcschr(pat, L'*') || wcschr(pat, L'?')) {
if (WildMatchN(s->Buffer, s_len, pat))
return TRUE;
}
else {
if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return TRUE;
if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0)
return TRUE;
if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return TRUE;
}
}
return FALSE;
}
static wchar_t* MatchListGetRule(PUNICODE_STRING s, wchar_t** list)
{
if (!s || !s->Buffer || s->Length == 0)
return 0;
size_t s_len = s->Length / sizeof(WCHAR);
for (SIZE_T i = 0; list[i]; ++i) {
wchar_t* pat = list[i];
size_t pat_len = wcslen(pat);
if (wcschr(pat, L'*') || wcschr(pat, L'?')) {
if (WildMatchN(s->Buffer, s_len, pat))
return pat;
}
else {
if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return pat;
if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0)
return pat;
if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return pat;
}
}
return 0;
}
static __forceinline BOOLEAN USOK(PUNICODE_STRING s)
{
return s && s->Buffer && s->Length;
}
static BOOLEAN StrStrIW(const wchar_t* s, const wchar_t* sub)
{
if (!s || !sub)
return FALSE;
SIZE_T n = wcslen(s), m = wcslen(sub);
if (m == 0 || n < m)
return FALSE;
for (SIZE_T i = 0; i + m <= n; i++) {
SIZE_T j = 0;
for (; j < m; j++) {
WCHAR a = s[i + j], b = sub[j];
if (a >= L'A' && a <= L'Z') a += 32;
if (b >= L'A' && b <= L'Z') b += 32;
if (a != b) break;
}
if (j == m)
return TRUE;
}
return FALSE;
}
static BOOLEAN EndsWithNameUS(PUNICODE_STRING s, const wchar_t* name)
{
if (!USOK(s) || !name)
return FALSE;
SIZE_T n = s->Length / sizeof(WCHAR);
SIZE_T m = wcslen(name);
if (n < m)
return FALSE;
return _wcsnicmp(s->Buffer + (n - m), name, m) == 0;
}
BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe)
{
if (USOK(key)) {
size_t klen0 = key->Length / sizeof(WCHAR);
if (WildMatchN(key->Buffer, klen0, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Services\\**"))
return FALSE;
}
if (USOK(exe)) {
if (IsWhitelist(exe))
return FALSE;
}
if (USOK(exe) && USOK(key)) {
size_t elen = exe->Length / sizeof(WCHAR);
size_t klen = key->Length / sizeof(WCHAR);
if (((elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"services.exe", 12) == 0) ||
(elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"svchost.exe", 11) == 0) ||
(elen >= 6 && _wcsnicmp(exe->Buffer + elen - 6, L"sc.exe", 6) == 0))) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**"))
return FALSE;
}
if ((elen >= 14 && _wcsnicmp(exe->Buffer + elen - 14, L"powershell.exe", 14) == 0) ||
(elen >= 8 && _wcsnicmp(exe->Buffer + elen - 8, L"pwsh.exe", 8) == 0)) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap\\**") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data\\**"))
return FALSE;
}
if ((elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"msiexec.exe", 11) == 0) ||
(elen >= 20 && _wcsnicmp(exe->Buffer + elen - 20, L"TrustedInstaller.exe", 20) == 0)) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Installer\\**") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Uninstall\\**") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**"))
return FALSE;
}
if (elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"schtasks.exe", 12) == 0) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\**"))
return FALSE;
}
}
if (USOK(key)) {
if (MatchBlockReg(key))
return TRUE;
}
if (USOK(valueName)) {
SIZE_T n = valueName->Length / sizeof(WCHAR);
for (SIZE_T i = 0; i < (SIZE_T)-1 && g_BlockReg[i]; ++i) {
wchar_t* pat = g_BlockReg[i];
if (wcschr(pat, L'\\') || wcschr(pat, L'*') || wcschr(pat, L'?'))
continue;
size_t m = wcslen(pat);
if (n == m && _wcsnicmp(valueName->Buffer, pat, m) == 0)
return TRUE;
}
}
return FALSE;
}
BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath)
{
PEPROCESS process = NULL;
NTSTATUS status = PsLookupProcessByProcessId(pid, &process);
if (!NT_SUCCESS(status))
return FALSE;
HANDLE h = NULL;
status = ObOpenObjectByPointer(process, OBJ_KERNEL_HANDLE, NULL, PROCESS_QUERY_LIMITED_INFORMATION, *PsProcessType, KernelMode, &h);
if (!NT_SUCCESS(status)) {
ObDereferenceObject(process);
return FALSE;
}
ULONG len = 0;
status = ZwQueryInformationProcess(h, ProcessImageFileName, NULL, 0, &len);
if (status != STATUS_INFO_LENGTH_MISMATCH || len == 0) {
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
PVOID buf = ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'iPgN');
if (!buf) {
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
status = ZwQueryInformationProcess(h, ProcessImageFileName, buf, len, &len);
if (NT_SUCCESS(status)) {
PUNICODE_STRING image = (PUNICODE_STRING)buf;
if (image->Buffer && image->Length > 0 && ProcessImagePath->MaximumLength >= image->Length + sizeof(WCHAR)) {
RtlCopyMemory(ProcessImagePath->Buffer, image->Buffer, image->Length);
ProcessImagePath->Length = image->Length;
ProcessImagePath->Buffer[image->Length / sizeof(WCHAR)] = 0;
ExFreePool2(buf, 'iPgN', NULL, 0);
ZwClose(h);
ObDereferenceObject(process);
return TRUE;
}
}
ExFreePool2(buf, 'iPgN', NULL, 0);
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
BOOLEAN IsWhitelist(PUNICODE_STRING s)
{
if (MatchList(s, g_WhitelistExcept))
return FALSE;
return MatchList(s, g_Whitelist);
}
BOOLEAN MatchBlockReg(PUNICODE_STRING s)
{
return MatchList(s, g_BlockReg);
}
wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s)
{
return MatchListGetRule(s, g_BlockReg);
}
BOOLEAN MatchBlockFile(PUNICODE_STRING s)
{
return MatchList(s, g_BlockFile);
}
BOOLEAN MatchBlockRansom(PUNICODE_STRING s)
{
return MatchList(s, g_BlockRansom);
}
wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s)
{
return MatchListGetRule(s, g_BlockFile);
}
BOOLEAN HasBlockedSuffix(PUNICODE_STRING s)
{
if (!USOK(s))
return FALSE;
SIZE_T n = s->Length / sizeof(WCHAR);
for (SIZE_T i = 0; g_Blocksuffix[i]; ++i) {
wchar_t* ext = g_Blocksuffix[i];
SIZE_T m = wcslen(ext);
if (n >= m && _wcsnicmp(s->Buffer + (n - m), ext, m) == 0)
return TRUE;
}
return FALSE;
}
BOOLEAN MatchRemoteSuspectBin(PUNICODE_STRING img)
{
for (SIZE_T i = 0; g_RemoteSuspectBins[i]; ++i)
if (EndsWithNameUS(img, g_RemoteSuspectBins[i]))
return TRUE;
return FALSE;
}
BOOLEAN MatchRemoteCommand(PUNICODE_STRING cmd, PUNICODE_STRING img)
{
if (!USOK(cmd))
return FALSE;
const wchar_t* s = cmd->Buffer;
for (SIZE_T i = 0; g_RemoteCmdIndicatorsHttp[i]; ++i)
if (StrStrIW(s, g_RemoteCmdIndicatorsHttp[i]))
return TRUE;
for (SIZE_T i = 0; g_RemoteCmdIndicatorsGeneric[i]; ++i)
if (StrStrIW(s, g_RemoteCmdIndicatorsGeneric[i]))
return TRUE;
if (USOK(img) && EndsWithNameUS(img, L"cmd.exe")) {
for (SIZE_T i = 0; g_RemoteCmdFromCmdExe[i]; ++i)
if (StrStrIW(s, g_RemoteCmdFromCmdExe[i]))
return TRUE;
}
if (USOK(img) && EndsWithNameUS(img, L"rundll32.exe")) {
for (SIZE_T i = 0; g_RemoteCmdFromRundll32Exe[i]; ++i)
if (StrStrIW(s, g_RemoteCmdFromRundll32Exe[i]))
return TRUE;
}
if (USOK(img) && EndsWithNameUS(img, L"regsvr32.exe")) {
BOOLEAN need = FALSE, http = FALSE;
for (SIZE_T i = 0; g_RemoteCmdRegsvr32Need[i]; ++i)
if (StrStrIW(s, g_RemoteCmdRegsvr32Need[i])) {
need = TRUE;
break;
}
for (SIZE_T i = 0; g_RemoteCmdIndicatorsHttp[i]; ++i)
if (StrStrIW(s, g_RemoteCmdIndicatorsHttp[i])) {
http = TRUE;
break;
}
if (need && http)
return TRUE;
}
if (USOK(img) && EndsWithNameUS(img, L"mshta.exe")) {
for (SIZE_T i = 0; g_RemoteCmdFromMshtaExe[i]; ++i)
if (StrStrIW(s, g_RemoteCmdFromMshtaExe[i]))
return TRUE;
}
return FALSE;
}
BOOLEAN MatchScreenCapModule(PUNICODE_STRING mod)
{
for (SIZE_T i = 0; g_ScreenCapModules[i]; ++i)
if (EndsWithNameUS(mod, g_ScreenCapModules[i]))
return TRUE;
return FALSE;
}
BOOLEAN MatchSuspiciousProcPath(PUNICODE_STRING img)
{
if (!USOK(img))
return FALSE;
const wchar_t* s = img->Buffer;
if (StrStrIW(s, L"\\Users\\")) {
for (SIZE_T i = 0; g_ScreenUserSubdirs[i]; ++i)
if (StrStrIW(s, g_ScreenUserSubdirs[i]))
return TRUE;
}
for (SIZE_T i = 0; g_ScreenOtherProcNeedles[i]; ++i)
if (StrStrIW(s, g_ScreenOtherProcNeedles[i]))
return TRUE;
return FALSE;
}
BOOLEAN MatchClrFromNonFramework(PUNICODE_STRING fullImageName)
{
if (!USOK(fullImageName))
return FALSE;
const wchar_t* s = fullImageName->Buffer;
BOOLEAN isClr = StrStrIW(s, L"\\clr.dll") || StrStrIW(s, L"\\mscorwks.dll");
if (!isClr)
return FALSE;
if (!StrStrIW(s, L"\\Windows\\Microsoft.NET\\"))
return TRUE;
if (!StrStrIW(s, L"\\Framework\\") && !StrStrIW(s, L"\\Framework64\\"))
return TRUE;
return FALSE;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <ntifs.h>
wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s);
wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s);
BOOLEAN IsWhitelist(PUNICODE_STRING s);
BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath);
BOOLEAN MatchBlockReg(PUNICODE_STRING s);
BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe);
BOOLEAN MatchBlockFile(PUNICODE_STRING s);
BOOLEAN MatchBlockRansom(PUNICODE_STRING s);
BOOLEAN HasBlockedSuffix(PUNICODE_STRING s);
BOOLEAN MatchRemoteSuspectBin(PUNICODE_STRING img);
BOOLEAN MatchRemoteCommand(PUNICODE_STRING cmd, PUNICODE_STRING img);
BOOLEAN MatchScreenCapModule(PUNICODE_STRING mod);
BOOLEAN MatchSuspiciousProcPath(PUNICODE_STRING img);
BOOLEAN MatchClrFromNonFramework(PUNICODE_STRING fullImageName);
+224
View File
@@ -0,0 +1,224 @@
#include <ntifs.h>
#include "DriverEntry.h"
typedef union _PS_PROTECTION {
UCHAR Level;
struct {
UCHAR Type : 3;
UCHAR Audit : 1;
UCHAR Signer : 4;
}Flags;
}PS_PROTECTION, * PPS_PROTECTION;
typedef struct _OBCTX {
POBJECT_TYPE ProcessType;
POBJECT_TYPE ThreadType;
}OBCTX, * POBCTX;
static PVOID g_PsSetProcessProtection = NULL;
static BOOLEAN g_ProcNotifyEnabled = FALSE;
static PVOID g_ObCookie = NULL;
static OBCTX g_ObCtx = { 0 };
static HANDLE g_ProtectedPid = NULL;
static PWCH g_ObAltitudeBuf = NULL;
static BOOLEAN IsProcNameEq(PEPROCESS p, PCSTR name)
{
PCSTR img = PsGetProcessImageFileName(p);
if (!img || !name)
return FALSE;
ANSI_STRING a = { 0 }, b = { 0 };
RtlInitAnsiString(&a, img);
RtlInitAnsiString(&b, name);
return RtlEqualString(&a, &b, TRUE) ? TRUE : FALSE;
}
static NTSTATUS SetPPL31(PEPROCESS p)
{
if (!g_PsSetProcessProtection)
return STATUS_PROCEDURE_NOT_FOUND;
PS_PROTECTION pr = { 0 };
pr.Level = 0x31;
((VOID(NTAPI*)(PEPROCESS, PS_PROTECTION))g_PsSetProcessProtection)(p, pr);
return STATUS_SUCCESS;
}
static VOID LogSet(HANDLE pid, NTSTATUS st)
{
CHAR b[128] = { 0 };
RtlStringCchPrintfA(b, RTL_NUMBER_OF(b), "PROC_PPL_SET | %u | 0x31 | 0x%08X", (ULONG)(ULONG_PTR)pid, st);
SendPipeLog(b, strlen(b));
}
static VOID UpdateProtectedPid(HANDLE pid)
{
InterlockedExchangePointer((PVOID*)&g_ProtectedPid, pid);
}
static VOID BootstrapExisting(VOID)
{
typedef PEPROCESS(NTAPI* PFN_PsGetNextProcess)(PEPROCESS);
UNICODE_STRING n = RTL_CONSTANT_STRING(L"PsGetNextProcess");
PFN_PsGetNextProcess fp = (PFN_PsGetNextProcess)MmGetSystemRoutineAddress(&n);
if (!fp)
return;
PEPROCESS p = fp(NULL);
while (p) {
if (IsProcNameEq(p, "PYAS.exe")) {
HANDLE pid = PsGetProcessId(p);
NTSTATUS s = SetPPL31(p);
UpdateProtectedPid(pid);
LogSet(pid, s);
}
PEPROCESS nx = fp(p);
ObDereferenceObject(p);
p = nx;
}
}
static VOID StripProcessAccess(POB_PRE_OPERATION_INFORMATION Info)
{
ACCESS_MASK d = PROCESS_TERMINATE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_SET_INFORMATION | PROCESS_SET_LIMITED_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_DUP_HANDLE;
if (Info->Operation == OB_OPERATION_HANDLE_CREATE) {
Info->Parameters->CreateHandleInformation.DesiredAccess &= ~d;
}
else {
Info->Parameters->DuplicateHandleInformation.DesiredAccess &= ~d;
}
}
static VOID StripThreadAccess(POB_PRE_OPERATION_INFORMATION Info)
{
ACCESS_MASK d = THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT | THREAD_IMPERSONATE | THREAD_DIRECT_IMPERSONATION;
if (Info->Operation == OB_OPERATION_HANDLE_CREATE) {
Info->Parameters->CreateHandleInformation.DesiredAccess &= ~d;
}
else {
Info->Parameters->DuplicateHandleInformation.DesiredAccess &= ~d;
}
}
static OB_PREOP_CALLBACK_STATUS ObPreOperation(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info)
{
UNREFERENCED_PARAMETER(RegistrationContext);
if (g_Unloading)
return OB_PREOP_SUCCESS;
if (!Info || Info->KernelHandle)
return OB_PREOP_SUCCESS;
if (!ExAcquireRundownProtection(&g_Rundown))
return OB_PREOP_SUCCESS;
if (Info->ObjectType == g_ObCtx.ProcessType) {
PEPROCESS pe = (PEPROCESS)Info->Object;
HANDLE tpid = PsGetProcessId(pe);
if (g_ProtectedPid && tpid == g_ProtectedPid) {
if (PsGetCurrentProcessId() != g_ProtectedPid) StripProcessAccess(Info);
}
}
else if (Info->ObjectType == g_ObCtx.ThreadType) {
PETHREAD th = (PETHREAD)Info->Object;
HANDLE owner = PsGetThreadProcessId(th);
if (g_ProtectedPid && owner == g_ProtectedPid) {
if (PsGetCurrentProcessId() != g_ProtectedPid) StripThreadAccess(Info);
}
}
ExReleaseRundownProtection(&g_Rundown);
return OB_PREOP_SUCCESS;
}
static NTSTATUS InitObCallbacks(VOID)
{
g_ObCtx.ProcessType = *PsProcessType;
g_ObCtx.ThreadType = *PsThreadType;
static OB_OPERATION_REGISTRATION ops[2];
RtlZeroMemory(ops, sizeof(ops));
ops[0].ObjectType = PsProcessType;
ops[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ops[0].PreOperation = ObPreOperation;
ops[1].ObjectType = PsThreadType;
ops[1].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ops[1].PreOperation = ObPreOperation;
const WCHAR* altStatic = L"321000";
USHORT alen = (USHORT)(wcslen(altStatic) * sizeof(WCHAR));
g_ObAltitudeBuf = (PWCH)ExAllocatePool2(POOL_FLAG_NON_PAGED, alen + sizeof(WCHAR), 'tlaO');
if (!g_ObAltitudeBuf)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(g_ObAltitudeBuf, altStatic, alen);
g_ObAltitudeBuf[alen / sizeof(WCHAR)] = 0;
UNICODE_STRING alt = { 0 };
alt.Buffer = g_ObAltitudeBuf;
alt.Length = alen;
alt.MaximumLength = alen;
OB_CALLBACK_REGISTRATION reg = { 0 };
reg.Version = OB_FLT_REGISTRATION_VERSION;
reg.OperationRegistrationCount = 2;
reg.RegistrationContext = g_ObAltitudeBuf;
reg.Altitude = alt;
reg.OperationRegistration = ops;
NTSTATUS s = ObRegisterCallbacks(&reg, &g_ObCookie);
if (!NT_SUCCESS(s)) {
ExFreePool2(g_ObAltitudeBuf, 'tlaO', NULL, 0);
g_ObAltitudeBuf = NULL;
}
return s;
}
static VOID ProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
{
if (g_Unloading)
return;
if (!ExAcquireRundownProtection(&g_Rundown))
return;
if (CreateInfo) {
if (IsProcNameEq(Process, "PYAS.exe")) {
NTSTATUS s = SetPPL31(Process);
UpdateProtectedPid(ProcessId);
LogSet(ProcessId, s);
}
}
else {
if (g_ProtectedPid && ProcessId == g_ProtectedPid) UpdateProtectedPid(NULL);
}
ExReleaseRundownProtection(&g_Rundown);
}
NTSTATUS InitProcessProtect(VOID)
{
UNICODE_STRING n = RTL_CONSTANT_STRING(L"PsSetProcessProtection");
g_PsSetProcessProtection = MmGetSystemRoutineAddress(&n);
NTSTATUS s = InitObCallbacks();
if (!NT_SUCCESS(s))
return s;
s = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, FALSE);
if (NT_SUCCESS(s))
g_ProcNotifyEnabled = TRUE;
BootstrapExisting();
return STATUS_SUCCESS;
}
VOID UninitProcessProtect(VOID)
{
if (g_ProcNotifyEnabled) {
PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, TRUE);
g_ProcNotifyEnabled = FALSE;
}
if (g_ObCookie) {
ObUnRegisterCallbacks(g_ObCookie);
g_ObCookie = NULL;
}
if (g_ObAltitudeBuf) {
ExFreePool2(g_ObAltitudeBuf, 'tlaO', NULL, 0);
g_ObAltitudeBuf = NULL;
}
}
@@ -1,6 +1,6 @@
#include <ntifs.h>
#include "ProtectRules.h"
#include "DriverEntry.h"
#include "ProtectMatch.h"
static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath, POBJECT_NAME_INFORMATION* OutInfo)
{
@@ -8,11 +8,11 @@ static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath,
NTSTATUS s = ObQueryNameString(KeyObject, NULL, 0, &len);
if (s != STATUS_INFO_LENGTH_MISMATCH)
return FALSE;
POBJECT_NAME_INFORMATION p = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'rgeR');
if (!p)
return FALSE;
s = ObQueryNameString(KeyObject, p, len, &len);
if (!NT_SUCCESS(s) || !p->Name.Buffer || p->Name.Length == 0) {
ExFreePool2(p, 'rgeR', NULL, 0);
@@ -25,39 +25,51 @@ static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath,
return TRUE;
}
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
{
UNREFERENCED_PARAMETER(ctx);
if (g_Unloading)
if (g_Unloading)
return STATUS_SUCCESS;
if (!ExAcquireRundownProtection(&g_Rundown))
if (!ExAcquireRundownProtection(&g_Rundown))
return STATUS_SUCCESS;
REG_NOTIFY_CLASS type = (REG_NOTIFY_CLASS)(ULONG_PTR)arg1;
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING checkReg = { 0 };
POBJECT_NAME_INFORMATION nameInfo = NULL;
UNICODE_STRING exe = { 0 };
WCHAR exeBuf[260] = { 0 };
exe.Buffer = exeBuf;
exe.MaximumLength = sizeof(exeBuf);
exe.Length = 0;
HANDLE pid = PsGetCurrentProcessId();
if (pid == (HANDLE)0 || pid == (HANDLE)4) {
ExReleaseRundownProtection(&g_Rundown);
return STATUS_SUCCESS;
if (pid == (HANDLE)0 || pid == (HANDLE)4) {
ExReleaseRundownProtection(&g_Rundown);
return STATUS_SUCCESS;
}
PUNICODE_STRING valueName = NULL;
BOOLEAN need_log = FALSE;
CHAR logbuf[1024] = { 0 };
BOOLEAN canQuery = (KeGetCurrentIrql() == PASSIVE_LEVEL);
if (type == RegNtPreSetValueKey) {
PREG_SET_VALUE_KEY_INFORMATION s = (PREG_SET_VALUE_KEY_INFORMATION)arg2;
valueName = s->ValueName;
if (canQuery)
if (canQuery)
QueryRegPathFromObject(s->Object, &checkReg, &nameInfo);
}
else if (type == RegNtPreDeleteValueKey) {
@@ -68,7 +80,7 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
}
else if (type == RegNtPreDeleteKey) {
PREG_DELETE_KEY_INFORMATION d = (PREG_DELETE_KEY_INFORMATION)arg2;
if (canQuery)
if (canQuery)
QueryRegPathFromObject(d->Object, &checkReg, &nameInfo);
}
else if (type == RegNtPreRenameKey) {
@@ -78,12 +90,12 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
}
else if (type == RegNtPreCreateKeyEx) {
PREG_CREATE_KEY_INFORMATION c = (PREG_CREATE_KEY_INFORMATION)arg2;
if (c->CompleteName)
if (c->CompleteName)
checkReg = *c->CompleteName;
}
else if (type == RegNtPreReplaceKey) {
PREG_REPLACE_KEY_INFORMATION rk = (PREG_REPLACE_KEY_INFORMATION)arg2;
if (canQuery)
if (canQuery)
QueryRegPathFromObject(rk->Object, &checkReg, &nameInfo);
}
else if (type == RegNtPreSaveKey) {
@@ -93,7 +105,7 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
}
else if (type == RegNtPreRestoreKey) {
PREG_RESTORE_KEY_INFORMATION res = (PREG_RESTORE_KEY_INFORMATION)arg2;
if (canQuery)
if (canQuery)
QueryRegPathFromObject(res->Object, &checkReg, &nameInfo);
}
else if (type == RegNtPreLoadKey) {
@@ -101,11 +113,11 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
if (lk->KeyName)
checkReg = *lk->KeyName;
}
if (checkReg.Buffer || (valueName && valueName->Buffer)) {
GetProcessImagePathByPid(pid, &exe);
if (canQuery)
GetProcessImagePathByPid(pid, &exe);
if (IsRegistryBlock(&checkReg, valueName, &exe)) {
RtlStringCchPrintfA(logbuf, sizeof(logbuf), "REG_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)pid, &exe, &checkReg);
need_log = TRUE;
status = STATUS_ACCESS_DENIED;
}
@@ -113,7 +125,7 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2)
if (nameInfo)
ExFreePool2(nameInfo, 'rgeR', NULL, 0);
if (need_log)
SendPipeLog(logbuf, strlen(logbuf));
LogAnsi3("REG_BLOCK", (ULONG)(ULONG_PTR)pid, &exe, &checkReg);
ExReleaseRundownProtection(&g_Rundown);
return status;
}
+96
View File
@@ -0,0 +1,96 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectMatch.h"
static BOOLEAN g_RemoteNotifyEnabled = FALSE;
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
static VOID ProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
{
UNREFERENCED_PARAMETER(Process);
UNREFERENCED_PARAMETER(ProcessId);
if (!CreateInfo)
return;
if (g_Unloading)
return;
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
return;
if (!ExAcquireRundownProtection(&g_Rundown))
return;
HANDLE ppid = CreateInfo->CreatingThreadId.UniqueProcess;
if (ppid == (HANDLE)0 || ppid == (HANDLE)4) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
UNICODE_STRING parent = { 0 };
WCHAR pbuf[512] = { 0 };
parent.Buffer = pbuf;
parent.MaximumLength = sizeof(pbuf);
if (!GetProcessImagePathByPid(ppid, &parent)) {
PEPROCESS eproc = PsGetCurrentProcess();
PCSTR n = PsGetProcessImageFileName(eproc);
size_t l = n ? strlen(n) : 0;
for (size_t i = 0; i < l && i < RTL_NUMBER_OF(pbuf) - 1; i++)
pbuf[i] = (WCHAR)n[i];
pbuf[l] = 0;
parent.Length = (USHORT)(l * sizeof(WCHAR));
}
if (IsWhitelist(&parent)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
UNICODE_STRING img = { 0 };
if (CreateInfo->ImageFileName)
img = *CreateInfo->ImageFileName;
UNICODE_STRING cmd = { 0 };
if (CreateInfo->CommandLine)
cmd = *CreateInfo->CommandLine;
BOOLEAN suspect = FALSE;
if (MatchRemoteSuspectBin(&img) && MatchRemoteCommand(&cmd, &img))
suspect = TRUE;
if (suspect) {
CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
if (cmd.Buffer && cmd.Length)
LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &cmd);
else if (img.Buffer && img.Length)
LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &img);
else {
UNICODE_STRING none = RTL_CONSTANT_STRING(L"None");
LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &none);
}
}
ExReleaseRundownProtection(&g_Rundown);
}
NTSTATUS InitRemoteProtect(VOID)
{
NTSTATUS s = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, FALSE);
if (NT_SUCCESS(s))
g_RemoteNotifyEnabled = TRUE;
return s;
}
VOID UninitRemoteProtect(VOID)
{
if (g_RemoteNotifyEnabled) {
PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, TRUE);
g_RemoteNotifyEnabled = FALSE;
}
}
+96 -192
View File
@@ -1,6 +1,5 @@
#include <ntifs.h>
#include "ProtectRules.h"
#include "DriverEntry.h"
wchar_t* g_Whitelist[] = {
L"\\Device\\HarddiskVolume*\\Windows\\**",
@@ -47,7 +46,7 @@ wchar_t* g_AttachDisk[] = {
};
wchar_t* g_BlockFile[] = {
L"\\DosDevices\\**",
L"\\Device\\Harddisk*\\DR*",
L"\\Device\\Harddisk*\\Partition\\**",
L"\\Device\\HarddiskVolume*\\Boot\\**",
L"\\Device\\HarddiskVolume*\\EFI\\**",
@@ -55,8 +54,9 @@ wchar_t* g_BlockFile[] = {
L"\\Device\\HarddiskVolume*\\Recovery\\**",
L"\\Device\\HarddiskVolume*\\System Volume Information\\**",
L"\\Device\\HarddiskVolume*\\Windows\\**",
L"\\Device\\HarddiskVolume*\\ProgramData\\PYAS\\**",
L"\\Device\\HarddiskVolume*\\$*\\**",
L"\\Device\\HarddiskVolume*\\ProgramData\\PYAS\\**",
L"**\\PYAS.exe",
L"**\\CON**",
L"**\\PRN**",
@@ -79,14 +79,27 @@ wchar_t* g_BlockRansom[] = {
NULL
};
wchar_t* g_Blocksuffix[] = {
L".exe", L".dll", L".sys", L".com", L".scr",
L".zip", L".7z", L".rar", L".tar", L".gz",
L".js", L".bat", L".cmd", L".ps1", L".vbs",
L".ppt", L".pptx", L".wps", L".txt", L".rtf",
L".pdf", L".xls", L".xlsx", L".doc", L".docx",
L".jpg", L".jpeg", L".png", L".webp", L".gif",
L".mp3", L".wav", L".aac", L".ogg", L".flac",
L".mp4", L".avi", L".mov", L".wmv", L".mkv",
L".aux", L".cur", L".mui", L".ttf", L".efi",
NULL
};
wchar_t* g_BlockReg[] = {
L"\\REGISTRY\\MACHINE\\BCD00000000\\**",
L"\\REGISTRY\\MACHINE\\SAM\\**",
L"\\REGISTRY\\MACHINE\\SECURITY\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\*ControlSet*\\Control\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\*ControlSet*\\Enum\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\*ControlSet*\\Services\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\MountedDevices\\**",
L"\\REGISTRY\\MACHINE\\SYSTEM\\Setup\\**",
@@ -94,6 +107,7 @@ wchar_t* g_BlockReg[] = {
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Policies\\Microsoft\\MMC\\**",
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\**",
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\**",
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid",
L"\\REGISTRY\\MACHINE\\**\\Microsoft\\Windows Defender\\**",
L"\\REGISTRY\\**\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\*\\StubPath",
@@ -106,7 +120,6 @@ wchar_t* g_BlockReg[] = {
L"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\Remcos*\\**",
L"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\DC3_FEXEC\\**",
L"DisableAntiSpyware",
L"DisableWindowsUpdateAccess",
L"EnableLUA",
@@ -195,197 +208,88 @@ wchar_t* g_BlockReg[] = {
NULL
};
static BOOLEAN WildMatchN(const wchar_t* str, SIZE_T n, const wchar_t* pat)
{
if (*pat == 0)
return n == 0;
if (*pat == L'*') {
if (pat[1] == L'*') {
for (SIZE_T i = 0; i <= n; ++i)
if (WildMatchN(str + i, n - i, pat + 2))
return TRUE;
return FALSE;
}
SIZE_T i = 0;
for (; i < n && str[i] != L'\\'; ++i)
if (WildMatchN(str + i, n - i, pat + 1))
return TRUE;
return WildMatchN(str + i, n - i, pat + 1);
}
if (*pat == L'?')
return n > 0 && str[0] != L'\\' && WildMatchN(str + 1, n - 1, pat + 1);
if (n == 0)
return FALSE;
WCHAR sc = str[0], pc = *pat;
if (sc >= L'A' && sc <= L'Z')
sc += 32;
if (pc >= L'A' && pc <= L'Z')
pc += 32;
return sc == pc && WildMatchN(str + 1, n - 1, pat + 1);
}
wchar_t* g_RemoteSuspectBins[] = {
L"powershell.exe",
L"pwsh.exe",
L"wscript.exe",
L"cscript.exe",
L"mshta.exe",
L"rundll32.exe",
L"regsvr32.exe",
L"cmd.exe",
L"bitsadmin.exe",
L"msbuild.exe",
L"installutil.exe",
L"wmic.exe",
NULL
};
static BOOLEAN MatchList(PUNICODE_STRING s, wchar_t** list)
{
if (!s || !s->Buffer || s->Length == 0)
return FALSE;
size_t s_len = s->Length / sizeof(WCHAR);
for (SIZE_T i = 0; list[i]; ++i) {
wchar_t* pat = list[i];
size_t pat_len = wcslen(pat);
if (wcschr(pat, L'*') || wcschr(pat, L'?')) {
if (WildMatchN(s->Buffer, s_len, pat))
return TRUE;
}
else {
if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return TRUE;
if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0)
return TRUE;
if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return TRUE;
}
}
return FALSE;
}
wchar_t* g_RemoteCmdIndicatorsHttp[] = {
L"http://",
L"https://",
NULL
};
static wchar_t* MatchListGetRule(PUNICODE_STRING s, wchar_t** list)
{
if (!s || !s->Buffer || s->Length == 0)
return 0;
size_t s_len = s->Length / sizeof(WCHAR);
for (SIZE_T i = 0; list[i]; ++i) {
wchar_t* pat = list[i];
size_t pat_len = wcslen(pat);
if (wcschr(pat, L'*') || wcschr(pat, L'?')) {
if (WildMatchN(s->Buffer, s_len, pat))
return pat;
}
else {
if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return pat;
if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0)
return pat;
if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0)
return pat;
}
}
return 0;
}
wchar_t* g_RemoteCmdIndicatorsGeneric[] = {
L"-enc",
L" -e ",
L"-encodedcommand",
L"frombase64string(",
L"iex(",
L"downloadstring(",
NULL
};
static __forceinline BOOLEAN USOK(PUNICODE_STRING s)
{
return s && s->Buffer && s->Length;
}
wchar_t* g_RemoteCmdFromCmdExe[] = {
L"powershell",
L"pwsh",
L"mshta",
L"rundll32",
L"wscript",
L"cscript",
NULL
};
BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe)
{
if (USOK(exe)) {
if (IsWhitelist(exe))
return FALSE;
}
if (USOK(exe) && USOK(key)) {
size_t elen = exe->Length / sizeof(WCHAR);
size_t klen = key->Length / sizeof(WCHAR);
if (((elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"services.exe", 12) == 0) ||
(elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"svchost.exe", 11) == 0) ||
(elen >= 6 && _wcsnicmp(exe->Buffer + elen - 6, L"sc.exe", 6) == 0))) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**"))
return FALSE;
}
if ((elen >= 14 && _wcsnicmp(exe->Buffer + elen - 14, L"powershell.exe", 14) == 0) ||
(elen >= 8 && _wcsnicmp(exe->Buffer + elen - 8, L"pwsh.exe", 8) == 0)) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap\\**"))
return FALSE;
}
if ((elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"msiexec.exe", 11) == 0) ||
(elen >= 20 && _wcsnicmp(exe->Buffer + elen - 20, L"TrustedInstaller.exe", 20) == 0)) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Installer\\**") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Uninstall\\**") ||
WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**"))
return FALSE;
}
if (elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"schtasks.exe", 12) == 0) {
if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\**"))
return FALSE;
}
}
if (USOK(key)) {
if (MatchBlockReg(key))
return TRUE;
}
if (USOK(valueName)) {
SIZE_T n = valueName->Length / sizeof(WCHAR);
for (SIZE_T i = 0; g_BlockReg[i]; ++i) {
wchar_t* pat = g_BlockReg[i];
if (wcschr(pat, L'\\') || wcschr(pat, L'*') || wcschr(pat, L'?'))
continue;
size_t m = wcslen(pat);
if (n == m && _wcsnicmp(valueName->Buffer, pat, m) == 0)
return TRUE;
}
}
return FALSE;
}
wchar_t* g_RemoteCmdFromRundll32Exe[] = {
L".dll,",
L"javascript:",
L"http",
NULL
};
BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath)
{
PEPROCESS process = NULL;
NTSTATUS status = PsLookupProcessByProcessId(pid, &process);
if (!NT_SUCCESS(status))
return FALSE;
wchar_t* g_RemoteCmdRegsvr32Need[] = {
L"/i:",
NULL
};
HANDLE h = NULL;
status = ObOpenObjectByPointer(process, OBJ_KERNEL_HANDLE, NULL, PROCESS_QUERY_LIMITED_INFORMATION, *PsProcessType, KernelMode, &h);
if (!NT_SUCCESS(status)) {
ObDereferenceObject(process);
return FALSE;
}
ULONG len = 0;
status = ZwQueryInformationProcess(h, ProcessImageFileName, NULL, 0, &len);
if (status != STATUS_INFO_LENGTH_MISMATCH || len == 0) {
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
PVOID buf = ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'iPgN');
if (!buf) {
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
status = ZwQueryInformationProcess(h, ProcessImageFileName, buf, len, &len);
if (NT_SUCCESS(status)) {
PUNICODE_STRING image = (PUNICODE_STRING)buf;
if (image->Buffer && image->Length > 0 && ProcessImagePath->MaximumLength >= image->Length + sizeof(WCHAR)) {
RtlCopyMemory(ProcessImagePath->Buffer, image->Buffer, image->Length);
ProcessImagePath->Length = image->Length;
ProcessImagePath->Buffer[image->Length / sizeof(WCHAR)] = 0;
ExFreePool2(buf, 'iPgN', NULL, 0);
ZwClose(h);
ObDereferenceObject(process);
return TRUE;
}
}
ExFreePool2(buf, 'iPgN', NULL, 0);
ZwClose(h);
ObDereferenceObject(process);
return FALSE;
}
wchar_t* g_RemoteCmdFromMshtaExe[] = {
L"http://",
L"https://",
NULL
};
BOOLEAN IsWhitelist(PUNICODE_STRING s)
{
if (MatchList(s, g_WhitelistExcept))
return FALSE;
return MatchList(s, g_Whitelist);
}
wchar_t* g_ScreenCapModules[] = {
L"windows.graphics.capture.dll",
L"dxgi.dll",
L"d3d11.dll",
L"dwmapi.dll",
L"dcomp.dll",
L"mfreadwrite.dll",
L"mfplat.dll",
L"opengl32.dll",
L"gdi32full.dll",
L"win32u.dll",
NULL
};
BOOLEAN MatchBlockReg(PUNICODE_STRING s)
{
return MatchList(s, g_BlockReg);
}
wchar_t* g_ScreenUserSubdirs[] = {
L"\\AppData\\",
L"\\Temp\\",
L"\\Downloads\\",
NULL
};
wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s)
{
return MatchListGetRule(s, g_BlockReg);
}
wchar_t* g_ScreenOtherProcNeedles[] = {
L"\\ProgramData\\",
NULL
};
+22 -5
View File
@@ -1,8 +1,25 @@
#pragma once
#include <ntifs.h>
wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s);
BOOLEAN MatchBlockReg(PUNICODE_STRING s);
BOOLEAN IsWhitelist(PUNICODE_STRING s);
BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath);
BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe);
extern wchar_t* g_Whitelist[];
extern wchar_t* g_WhitelistExcept[];
extern wchar_t* g_AttachDisk[];
extern wchar_t* g_BlockFile[];
extern wchar_t* g_BlockRansom[];
extern wchar_t* g_Blocksuffix[];
extern wchar_t* g_BlockReg[];
extern wchar_t* g_RemoteSuspectBins[];
extern wchar_t* g_RemoteCmdIndicatorsHttp[];
extern wchar_t* g_RemoteCmdIndicatorsGeneric[];
extern wchar_t* g_RemoteCmdFromCmdExe[];
extern wchar_t* g_RemoteCmdFromRundll32Exe[];
extern wchar_t* g_RemoteCmdRegsvr32Need[];
extern wchar_t* g_RemoteCmdFromMshtaExe[];
extern wchar_t* g_ScreenCapModules[];
extern wchar_t* g_ScreenUserSubdirs[];
extern wchar_t* g_ScreenOtherProcNeedles[];
+80
View File
@@ -0,0 +1,80 @@
#include <ntifs.h>
#include "DriverEntry.h"
#include "ProtectMatch.h"
static BOOLEAN g_ScreenImgCb = FALSE;
static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2)
{
ANSI_STRING a1 = { 0 }, a2 = { 0 };
CHAR buf[1024] = { 0 };
RtlUnicodeStringToAnsiString(&a1, s1, TRUE);
if (s2)
RtlUnicodeStringToAnsiString(&a2, s2, TRUE);
RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : "");
SendPipeLog(buf, strlen(buf));
RtlFreeAnsiString(&a1);
RtlFreeAnsiString(&a2);
}
static VOID ImageLoadNotify(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo)
{
UNREFERENCED_PARAMETER(ImageInfo);
if (g_Unloading)
return;
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
return;
if (!ExAcquireRundownProtection(&g_Rundown))
return;
if (!FullImageName || !FullImageName->Buffer || FullImageName->Length == 0) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
UNICODE_STRING proc = { 0 };
WCHAR pbuf[512] = { 0 };
proc.Buffer = pbuf;
proc.MaximumLength = sizeof(pbuf);
if (!GetProcessImagePathByPid(ProcessId, &proc)) {
PEPROCESS eproc = NULL;
if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &eproc))) {
PCSTR n = PsGetProcessImageFileName(eproc);
SIZE_T l = n ? strlen(n) : 0;
for (SIZE_T i = 0; i < l && i < RTL_NUMBER_OF(pbuf) - 1; i++)
pbuf[i] = (WCHAR)n[i];
pbuf[l] = 0;
proc.Length = (USHORT)(l * sizeof(WCHAR));
ObDereferenceObject(eproc);
}
}
if (proc.Length == 0) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
if (IsWhitelist(&proc)) {
ExReleaseRundownProtection(&g_Rundown);
return;
}
BOOLEAN suspicious = MatchSuspiciousProcPath(&proc);
if (suspicious && MatchScreenCapModule(FullImageName))
LogAnsi3("SCREEN_BLOCK", (ULONG)(ULONG_PTR)ProcessId, &proc, FullImageName);
ExReleaseRundownProtection(&g_Rundown);
}
NTSTATUS InitScreenProtect(VOID)
{
NTSTATUS s = PsSetLoadImageNotifyRoutine(ImageLoadNotify);
if (NT_SUCCESS(s)) g_ScreenImgCb = TRUE;
return s;
}
VOID UninitScreenProtect(VOID)
{
if (g_ScreenImgCb) {
PsRemoveLoadImageNotifyRoutine(ImageLoadNotify);
g_ScreenImgCb = FALSE;
}
}