Windows 反除錯技術——OpenProcess 許可權過濾
本週我有了休息時間,來回顧一下反除錯技術。目前,Bug Bounty平臺上有大量程式依賴於客戶端應用,而且許多安全產品和遊戲反作弊引擎都採用了這些反除錯技術來阻止你除錯核心模組。我想有必要來分享其中一項反除錯技術,以及如何繞過它。
本文所述的技術並不是一個安全漏洞,很明顯,如果攻擊者擁有了這個級別的系統訪問許可權,遊戲就已經結束了。他們只需要安裝一個 rookit 就夠了。
文中我將以 AVG 產品為例。儘管我儘量避免過多地討論這一款產品,然而其他的反病毒解決方案和安全產品使用了完全相同的技術,所以相同的原則也同樣適用這些產品。
面臨什麼問題?
如果你以前嘗試過開啟 x64dbg,並把它附加到一個 AV(譯者注:AntiVirus) 元件中,通常會看到如下介面:(下圖是GIF動圖1)
偵錯程式基本沒有附加成功,並停在了啟動頁。如果我們在偵錯程式內不採用附加的方式,而是直接啟動剛才的程式:(下圖是GIF動圖2)
還是不行,出現了相同的結果。當程式剛要啟動時,除錯程式被踢出了。最後,我們試試 WinDBG,得到了下面的錯誤資訊:
為了理解偵錯程式剛才做了什麼,同時發現哪裡出了問題,我們看一下 x64dbg 的原始碼(實際上,是 x64dbg 使用的除錯引擎 TitanEngine 的原始碼)。
__declspec(dllexport) bool TITCALL AttachDebugger(DWORD ProcessId, bool KillOnExit, LPVOID DebugInfo, LPVOID CallBack)
{
...
if(ProcessId != NULL && dbgProcessInformation.hProcess == NULL)
{
if(engineEnableDebugPrivilege)
{
EngineSetDebugPrivilege(GetCurrentProcess(), true);
DebugRemoveDebugPrivilege = true;
}
if(DebugActiveProcess(ProcessId))
{
...
}
}
}
從程式碼中發現,x64dbg 使用了一個 KernelBase.dll 提供的 Win32 函式 “DebugActiveProcess”。
DebugActiveProcess 的工作原理
DebugActiveProcess 函式用於在目標程式上開啟一個除錯會話。該函式的唯一引數是目標程式的PID。如果在 MSDN 上查閱該函式,可以看到如下的描述:
“The debugger must have appropriate access to the target process, and it must be able to open the process for PROCESS_ALL_ACCESS.
DebugActiveProcess can fail if the target process is created with a security descriptor that grants the debugger anything less than full access.
If the debugging process has the SE_DEBUG_NAME privilege granted and enabled, it can debug any process.”
這裡,我們發現了導致除錯會話失敗的端倪。
上述的程式碼片段中,偵錯程式呼叫了 EngineSetDebugPrivilege 函式。那麼,來看看這個函式。
DWORD EngineSetDebugPrivilege(HANDLE hProcess, bool bEnablePrivilege)
{
DWORD dwLastError;
HANDLE hToken = 0;
if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
...
}
...
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
...
}
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luid;
if(bEnablePrivilege)
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tokenPrivileges.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
...
}
從上述程式碼中可以看到,SE_DEBUG_NAME 許可權已經設定到程式令牌(process token)上。
這意味著,呼叫 DebugActiveProcess 函式的要求已經滿足(譯者注:要求指的是MSDN中描述的 SE_DEBUG_NAME許可權要求)。
接著檢查,是否擁有對於目標程式的 PROCESS_ALL_ACCESS 許可權。
深入 DebugActiveProcess 內部
DebugActiveProcess 接受唯一的引數是“程式ID”。在該函式內部,使用程式ID 呼叫 ProcessIdToHandle,開啟目標程式的控制程式碼:
進入 ProcessIdToHandle 函式內部,可以發現該函式僅僅是對 NtOpenProcess 的封裝:
NftOpenProcess函式中有一個形參叫做“Desired Access”,即所需的訪問權。該引數的實參是 C3Ah。通過微軟官方文件發現,這個值是以下值的組合:
PROCESS_CREATE_THREAD (譯者注:0x0002)
PROCESS_VM_OPERATION (0x0008)
PROCESS_VM_WRITE (0x0020)
PROCESS_VM_READ (0x0010)
PROCESS_SUSPEND_RESUME (0x0800)
PROCESS_QUERY_INFORMATION (0x0400)
於是,這次呼叫具備了除錯程式所需要的全部授權。
到這裡,偵錯程式具備了 SE_DEBUG_NAME 授權,DebugActiveProcess 呼叫也給自身賦予了正確的訪問目標程式的許可權。
那麼是什麼阻止了附加過程呢?
ObRegisterCallbacks 簡介
我是在一個遊戲模組社群(譯者注:即遊戲mod社群)中第一次知道 ObRegisterCallbacks 函式的。在繞過反作弊和 DRM 驅動時,該函式被用於阻止修改或注入遊戲功能。
按照微軟官方說法,ObRegisterCallbacks 是“這樣一個函式,它為執行緒、程式、桌面控制程式碼操作註冊了一系列回撥函式。”這是在作業系統核心態完成的。主要是給驅動程式開發者提供一種能力,用於在 OpenProcess 函式被呼叫時和返回時收到通知。
為什麼這個函式能夠用於阻止偵錯程式訪問 AV 程式呢?阻止 DebugActiveProcess 呼叫成功的其中一個方法就是,過濾掉 “呼叫NtOpenProcess“所需要的訪問許可權(譯者注:NtOpenProcess 函式有一個形參 DesiredAccess,這裡指的是,該引數對應的實參被過濾後,就不是所需要的值了)。通過移除偵錯程式“請求目標程式的 PROCESS_ALL_ACCESS 訪問權”的能力,我們就無法除錯一個程式。這也解釋了剛剛在 WinDBG看到的錯誤。
怎麼確認這就是問題所在呢?我們接著進入核心偵錯程式,觀察註冊的回撥函式是如何在 Ring-0 被處理的。(這裡不會詳細介紹如何使用核心偵錯程式,如果你需要一些資料,可以閱讀我之前的部落格)
深入 ObRegisterCallback 內部
當啟動核心除錯後,從 nt!ProcessType 開始分析:
kd> dt nt!_OBJECT_TYPE poi(nt!PsProcessType)
+0x000 TypeList : _LIST_ENTRY [ 0xffffcb82`dee6cf20 - 0xffffcb82`dee6cf20 ]
+0x010 Name : _UNICODE_STRING "Process"
+0x020 DefaultObject : (null)
+0x028 Index : 0x7 ''
+0x02c TotalNumberOfObjects : 0x26
+0x030 TotalNumberOfHandles : 0xe8
+0x034 HighWaterNumberOfObjects : 0x26
+0x038 HighWaterNumberOfHandles : 0xea
+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0b8 TypeLock : _EX_PUSH_LOCK
+0x0c0 Key : 0x636f7250
+0x0c8 CallbackList : _LIST_ENTRY [ 0xffffa002`d31bacd0 - 0xffffa002`d35d2450 ]
這個符號包含了一個指向 _OBJECT_TYPE 型別物件的指標,該物件定義了 “Process” 型別,幷包含了一個CallbackList屬性。
這個屬性值得我們注意。該屬性定義了一個回撥函式列表,其中儲存了由 ObRegisterCallbacks 註冊的函式。
之後,其中的每個函式都會在獲取程式控制程式碼時由核心呼叫。基於這個理解,我們將遍歷這個列表,找到阻止成功呼叫 OpenProcess 函式的回撥函式控制程式碼。
CallbackList 是一個 _LIST_ENTRY,指向 CALLBACK_ENTRY_ITEM 結構體。該結構體在微軟的文件中沒有說明,然而有一篇文章 “DOUGGEM’S GAME HACKING AND REVERSING NOTES” 給出了結構體的定義:
typedef struct _CALLBACK_ENTRY_ITEM {
LIST_ENTRY EntryItemList;
OB_OPERATION Operations;
CALLBACK_ENTRY* CallbackEntry;
POBJECT_TYPE ObjectType;
POB_PRE_OPERATION_CALLBACK PreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
__int64 unk;
}CALLBACK_ENTRY_ITEM, *PCALLBACK_ENTRY_ITEM;
結構體中的 PreOperation 引起了我們的注意。
通過如下 WinDBG 命令,遍歷 CALLBACK_ENTRY_ITEM 列表:
!list -x ".if (poi(@$extret+0x28) != 0) { u poi(@$extret+0x28); }" (poi(nt!PsProcessType)+0xc8)
在我的電腦上,有 4 個驅動程式通過 ObRegisterCallbacks 註冊了 PreOperation 回撥函式。
接著,我們通過 WinDBG 輸出驅動程式的名字:
!list -x ".if (poi(@$extret+0x28) != 0) { lmv a (poi(@$extret+0x28)) }" (poi(nt!PsProcessType)+0xc8)
這 4 個驅動程式中,其中一個立刻引起了我們關注,很可能它就是問題的關鍵:avgSP.sys。
可以判斷出:就是 “AVG self protection module” 模組在阻止我們將偵錯程式附加到程式中(更有可能的是,當反病毒引擎阻止惡意軟體時,產生了這樣的副作用)。接著,我們深入分析下這個驅動程式,找出其影響 OpenProcess 呼叫的痕跡。
首先,找到 ObRegisterCallbacks 函式,它註冊了一個函式控制程式碼:
我們如果檢查這個剛註冊的函式控制程式碼,可以發現:
在反彙編程式碼中,出現了一個幻數(Magic Number)A0121410。實際上,它表示以下許可權:
PROCESS_VM_READ (譯者注:0x0010)
PROCESS_QUERY_INFORMATION (0x0400)
PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
READ_CONTROL (0x00020000L)
SYNCHRONIZE (0x00100000L)
其實,如果只設定這些許可權的話,則沒有進一步的許可權檢查操作,OpenProcess 函式繼續執行。然而,如果請求上述許可權白名單以外的許可權,還要執行一系列的檢查操作,最終在函式返回前,所需要的許可權被過濾掉。
由於本文主要講解“識別和移除”這種鉤子的通用方法,所以我不打算深入驅動程式的細節了。
從上面的分析可知,我們發現有一個驅動程式在攔截和修改 OpenProcess 呼叫。
現在,已經找到問題根源,接下來就是從核心中拆下這個鉤子。
移除 OpenProcess 許可權過濾
為了移除 OpenProcess 的許可權過濾函式,首先需要找到過濾函式所在的 PreOperation 屬性的地址。輸入 WinDBG 命令:
!list -x ".if (poi(@$extret+0x28) != 0) { .echo handler at; ?? @$extret+0x28; u poi(@$extret+0x28); }" (poi(nt!PsProcessType)+0xc8)
一旦發現了正確的屬性地址,我們使用下面的命令將其置為 NULL,以此來禁止回撥控制程式碼:
eq 0xffffa002`d31bacf8 0
此時,再次將偵錯程式附加到被除錯程式,可以得到如下介面:
太棒了!看上去我們已經成功了。
嗯,幾乎是……我們稍加操作就可以發現大量錯誤,問題還沒有處理乾淨。
即使在上述介面,我們也可以看到暫存器的值都是0,並且出現了訪問衝突。這一定是漏掉了什麼。
記住還有執行緒
我們已經知道 ObRegisterCallbacks 函式可以給 OpenProcess 加上鉤子函式,還能做什麼呢?再次檢視官方文件發現,ObRegisterCallbacks 也可以給 OpenThread 加上鉤子。
慶幸的是,很多工作已經完成了,我們只需要找到執行緒的鉤子函式所在的位置即可。這個位置恰好定義在 nt!PsThreadType 中。
修改一下剛才輸入的命令,觀察驅動程式(譯者注:指的是 avgSP.sys)是否為 OpenThread 函式新增了鉤子:
1
!list -x ".if (poi(@$extret+0x28) != 0) { .echo handler at; ?? @$extret+0x28; u poi(@$extret+0x28); }" (poi(nt!PsThreadType)+0xc8)
真的有鉤子!和剛才的程式鉤子類似,我們使用 eq 命令移除鉤子:
eq 0xffffc581`89df32e8 0
再次附加偵錯程式到程式:(下圖是GIF動圖3)
大功告成!可以開始正常除錯了。
希望本文有助於你瞭解這項反除錯技術。如果感興趣,還有很多 Bug Bounty 程式可供學習,包括 BugCrowd 平臺上 AVG 的一個例子(點選這裡)、Cylance、Sophos等等。(儘管我沒有把這些作為安全漏洞,但是 DKOM 不在討論範圍)(譯者注:DKOM,全稱是 Direct kernel object manipulation)。
參考資料
TitanEngine
DOUGGEM'S GAME HACKING AND REVERSING NOTES
AVG Bug Bounty
x64Dbg GitHub
原文:https://blog.xpnsec.com/anti-debug-openprocess/
本文由 看雪翻譯小組 yezhang 編譯
相關文章
- 資料許可權技術驗證2018-08-28
- Windows許可權維持2020-12-28Windows
- [BUG反饋]許可權管理 -> 訪問授權 點選後報錯2019-05-11
- frida反除錯繞過2023-04-06除錯
- EXECUTE IMMEDIATE 儲存過程中 許可權不足及EXECUTE IMMEDIATE的除錯避坑2019-09-26儲存過程除錯
- 基於全流量許可權漏洞檢測技術2020-07-08
- 「Android6.0許可權適配| 掘金技術徵文 」2019-03-04Android
- [BUG反饋]許可權條目中缺少兩個公開方法的許可權設定2019-05-11
- blog.admin 查詢增加過濾器,新增、刪除增加資料審計、統一控制許可權操作2024-04-25過濾器
- 許可權之選單許可權2019-04-17
- linux 檔案許可權 s 許可權和 t 許可權解析2018-03-16Linux
- 如何用 Vue 實現前端許可權控制(路由許可權 + 檢視許可權 + 請求許可權)2018-04-12Vue前端路由
- android AVC錯誤修改許可權方法2024-03-29Android
- Windows許可證 即將過期2020-02-03Windows
- PostgreSQL技術大講堂 - Part 8:PG物件許可權管理2023-03-03SQL物件
- 許可權系統:一文搞懂功能許可權、資料許可權2024-11-10
- Android應用方法隱藏及反除錯技術淺析2020-08-19Android除錯
- windows server許可權對tomcat的影響2024-12-03WindowsServerTomcat
- PrintNightmare漏洞補丁再被繞過!新的手段可獲得Windows管理員許可權2021-08-03Windows
- Java安全之Filter許可權繞過2021-05-23JavaFilter
- 刪除Windows 10右鍵選單中的授予訪問許可權選項2024-04-02Windows訪問許可權
- 一次Android許可權刪除經歷2019-04-15Android
- 你需要提供管理員許可權才能刪除此資料夾win10 如何跳過管理員許可權刪除檔案2022-02-11Win10
- Nginx報錯:Permission denied,沒有許可權!2021-11-22Nginx
- 每過一天 laravel log 就會報沒許可權錯誤2023-12-05Laravel
- [仁潤雲技術團隊]許可權系統的設計2018-12-21
- Linux特殊許可權之suid、sgid、sbit許可權2022-03-17LinuxUI
- 許可權概念、許可權提升概念以及許可權提升的分類和目的 Windows 提權的基礎原理是瞭解作業系統的安全機制和許可權管理 Windows提權攻擊的進一步知識概念2024-03-12Windows作業系統
- win10 建資料夾許可權方法 如何設定windows10檔案許可權2020-09-29Win10Windows
- 超過40個Windows裝置驅動程式包含提升許可權的漏洞2019-08-12Windows
- 在Windows低許可權下利用服務進行提權2018-09-01Windows
- 7.4 透過API列舉程式許可權2023-09-23API
- mysql許可權2018-12-08MySql
- 許可權控制2019-10-30
- Linux許可權2024-09-27Linux
- mysql 新增、刪除使用者和許可權分配2021-09-09MySql
- android動態許可權到自定義許可權框架2018-10-15Android框架
- 選單許可權和按鈕許可權設定2024-07-12