發表文章

目前顯示的是 十一月, 2019的文章

[Windows] [Debug] 記憶體無痕鉤子 - 硬體斷點 (C++) 實作 Ring3 進程防殺

圖片
前言 其實三年前就土炮過調試器了,不過最近要做碩論(?)會用到動態路徑分析所以又重新回頭來玩一些以前寫外掛用到的技能,而翻了一下繁體中文的文獻好像對這部分沒什麼提及就寫了一篇做一個簡單整理(主要是方便我以後回頭拿來當工具用XD)
本文實作做一個標準調試器自動下硬體斷點、然後修改暫存器內容再恢復執行緒運作,藉此來達成記憶體程式碼不破損情況下做到修改程式邏輯,完成自我進程防殺(防止工作管理員殺除)
Debugger 在 Windows 進程權級分割下如果想除錯其他進程要先用 AdjustTokenPrivileges 拿取 SE_DEBUG 令牌,有了這張令牌就可以除錯其他進程(不過拿這張令牌要先過 UAC 就是)接著可以用 DebugActiveProcess 函數 attach 上對應你想動態除錯的進程、接著你除錯的進程就會被掛起成 DEBUG_MODE 接著執行緒會被排程跳到 DbgBreakPoint 上踩到 \xCC 然後就拋出一個異常可以讓 Debugger 接收負責接下來對應處理。 (所以一些殼在處理 anti-attach 主要就是在 DbgBreakPoint 上一個 hotpatch 去自殺)
而接下來 Debugger 負責做的處理就是一個無限迴圈:以 WaitForDebugEvent 向系統拿取當前被掛載進程的異常事件(這個概念有點像 Win32 視窗程式的 GetMessage 架構拿消息)當被掛載進程拋錯時候,WaitForDebugEvent 就可以拿到異常事件、Debugger 負責接手接下來的事情。
所以講到這邊原理就很淺而易見可以知道:如果外掛要修改邏輯(以除錯器模式實作)就會有很基礎的三種方式去讓程式執行到想攔截的函數時,就必須拋錯,主流方法就三種: int 3 讓 CPU 踩上去時候自動拋出異常記憶體改成不可執行的分頁區讓 DEP 防護拋出異常或者本文要講的硬體斷點手段
硬體斷點(DR0 → DR4)可以查閱 wiki 知道:wiki/X86_debug_register,總之 x86 CPU 提供了每個 Thread 有四個「當前正在除錯的地址」可以指示當 CPU 正在對某塊地址進行 讀/寫/執行 時「就必須拋錯」。那麼這四個地址就分別放在 DR0 ~ DR4(對,就把你想攔截的地址放上去就對了沒什麼技巧)
那麼怎麼讓 CPU 知道到…