通過構造系統服務分發實現攔截&過濾 (仿360遊戲保險箱)

Ox9A82發表於2016-03-03

想寫這個程式主要是因為看了KSSD的一篇帖子,http://bbs.pediy.com/showthread.php?t=108378

講 的是360保險箱保護遊戲賬號的原理,實際上就是對各種請求的攔截。這個帖子是大約6年前的了,我簡單的看了一下現在的360保險箱應該不再採用這種方法了。

這裡主要的思路就是HOOK住系統服務的分發,這已經不是什麼新鮮的手法了。比方說,很多外掛作者都使用了核心過載來突破遊戲保護的重重HOOK,核心過載也是劫持KiFastCallEntry來實現劫持服務分發的。這篇文章只是寫來做一個練習。

基本流程是

1.應用層:

負責安裝驅動模組並與驅動通訊,由使用者選擇是否要放行指定操作

2.核心層:

(1)設定SSDT HOOK並呼叫HOOK 函式,進行棧回溯獲取KiFastCallEntry()基址
(2)利用KiFastCallEntry()基址暴力搜尋找到HOOK點位置並設定Inline Hook
(3)判斷服務請求是否合法,合法則放行,不合法則傳遞訊息給使用者層,由使用者決定是否放行

其實以上三步就是360保險箱的做法,程式裡的有些內容因為不知道該怎麼寫,所以直接由那篇帖子的彙編分析逆寫出來了。

 

 

其實網上有很多HOOK KiFastCallEntry的程式碼,但是我沒有找到有劫持ebx來劫持服務分發的例子,所以我寫的就是

sub esp, ecx

shr ecx, 2

mov ebx,FuncAddress

結果一直藍屏,調了整整兩天也沒找到哪裡的問題

後來在群裡問到要把順序改成這樣

mov ebx,FuncAddress

sub esp, ecx

shr ecx, 2

 

結果真的不會觸發BSOD了,不知道原理是什麼,因為我覺得兩種應該沒有本質的區別(無論是暫存器還是堆疊我都沒有改掉),可是第一種就是不行。

本來應該生成一個裝置物件與應用層通訊的,結果被藍屏弄的實在搞不下去,就以後再說吧,核心的程式就是這些了。

想法就是根據SSDT索引得知是什麼函式,然後再用在核心棧中索引出SSDT函式的引數(因為在call ebx時引數肯定已經入棧了),最後根據情況用IRP與使用者層通訊詢問是否放行。

 

 

  1 #include "ntddk.h"   //環境:WDK 7.1 WIN XP SP3 測試通過
  2 #include <ntdef.h>  //注意我分發函式中是故意留空白的,不要直接拿來編譯
  3 
  4 #define NtSetEventID 219
  5 
  6 typedef struct ServiceDescriptorEntry {
  7     unsigned int *ServiceTableBase;
  8     unsigned int *ServiceCounterTableBase;
  9     unsigned int NumberOfServices;
 10     unsigned char *ParamTableBase;
 11 } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
 12 
 13 __declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
 14 
 15 NTSTATUS ZwSetEvent(__in HANDLE  EventHandle,__out_opt PLONG  PreviousState);
 16 
 17 PVOID AddressOfFuncAddress;
 18 HANDLE HandleTemp = (HANDLE)0x288C58F1;
 19 ULONG NtSetEventAddress, TheHookAddress,KiFastCallEntryAddress;
 20 ULONG YesOrNo=0;
 21 ULONG AddressOffset = 0;
 22 ULONG TempDword,Test;
 23 ULONG ProcessPID = 0;
 24 ULONG pid, DispatchAddress, TempBufferCopy;
 25 PULONG DwordAddress = 0;
 26 INT8 i;
 27 INT8 *PbyteAddress;
 28 KSPIN_LOCK MySpinLock1;
 29 KSPIN_LOCK MySpinLock2;
 30 KSPIN_LOCK MySpinLock3;
 31 KIRQL TempKirql1;
 32 KIRQL TempKirql2;
 33 ULONG DebugAddress = 0,FuncAddress;
 34 //設定SSDT HOOK 用來棧回溯得到KiFastCallEntry地址
 35 Check()
 36 NTSTATUS HookSSDT(PVOID FuncAdress)
 37 {
 38     ULONG OutTemp = 0;
 39     NtSetEventAddress = (ULONG)KeServiceDescriptorTable.ServiceTableBase[NtSetEventID];
 40     DebugAddress=(ULONG)&KeServiceDescriptorTable.ServiceTableBase[NtSetEventID];
 41     KeInitializeSpinLock(&MySpinLock1);
 42     KeAcquireSpinLock(&MySpinLock1,&TempKirql1);
 43     _asm {    
 44             cli
 45             push eax
 46             mov  eax, cr0
 47             and  eax, not 10000h
 48             mov  cr0, eax
 49             pop eax
 50     }
 51     KeServiceDescriptorTable.ServiceTableBase[NtSetEventID] = (ULONG)FuncAdress;
 52     __asm {
 53             push eax
 54             mov  eax, cr0
 55             or eax, 10000h
 56             mov  cr0, eax
 57             pop eax
 58             sti
 59     }
 60     KeReleaseSpinLock(&MySpinLock1,&TempKirql1);
 61     ZwSetEvent(HandleTemp,
 62         &OutTemp);
 63     return STATUS_SUCCESS;
 64 }
 65 //解除SSDT HOOK
 66 void UnhookSSDTHook()
 67 {
 68     KeInitializeSpinLock(&MySpinLock2);
 69     KeAcquireSpinLock(&MySpinLock2,&TempKirql1);
 70     _asm {
 71             cli
 72             push eax
 73             mov  eax, cr0
 74             and  eax, not 10000h
 75             mov  cr0, eax
 76             pop eax
 77     };
 78     KeServiceDescriptorTable.ServiceTableBase[NtSetEventID] = NtSetEventAddress;
 79 
 80     _asm {
 81             push eax
 82             mov  eax, cr0
 83             or eax, 10000h
 84             mov  cr0, eax
 85             pop eax
 86             sti
 87     };
 88     KeReleaseSpinLock(&MySpinLock2,&TempKirql1);
 89     return;
 90 }
 91 ULONG TheDispatchFunc(ULONG arg1, ULONG arg2, ULONG arg3)
 92 {    
 93     if (arg3== (ULONG)KeServiceDescriptorTable.ServiceTableBase)
 94     {
 95         //這裡可以根據棧中引數進行做判斷
 96     }
 97     return arg2;
 98 
 99 }
100 //被掛載在KiFastCallEntry中(作為一箇中轉函式)
101 __declspec(naked) void InlineFunc()
102 {
103     
104     
105     _asm {
106             pushad
107             pushfd
108 
109             push edi//服務表基址
110             push ebx//服務地址
111             push eax//服務序號
112             call TheDispatchFunc
113             mov FuncAddress,eax
114             
115             popfd
116             popad
117             //補全被覆蓋的函式
118             mov ebx, FuncAddress
119             sub esp, ecx
120             shr ecx, 2
121             
122 
123             jmp TempBufferCopy
124             
125     };
126 
127 }
128 //被掛載在SSDT的函式,需判斷偽控制程式碼
129 //並且要進行Inline HOOK
130 __declspec(naked) void SSDTFunc()
131 {
132     _asm {
133             push eax
134             mov eax, [esp + 8]
135             mov TempDword, eax
136             pop eax
137     }
138 
139     if (TempDword == HandleTemp)
140     {
141         _asm {
142             push eax
143             mov eax, [esp + 4]
144             mov KiFastCallEntryAddress, eax
145             pop eax
146             };
147         UnhookSSDTHook();
148     }
149     else
150     {    
151         //_asm {int 3};
152         _asm {
153             jmp NtSetEventAddress
154         };
155     }
156     for (i = 0; i < 200; i++)
157     {
158         
159         if (*((PULONG)KiFastCallEntryAddress)==0xe9c1e12b)
160         {
161             TheHookAddress = KiFastCallEntryAddress;
162             YesOrNo = 1;
163             break;
164         }
165         KiFastCallEntryAddress--;
166     }
167     if (YesOrNo)
168     {    
169         AddressOffset = (ULONG)InlineFunc - 5 - (ULONG)TheHookAddress;
170         PbyteAddress = (INT8 *)TheHookAddress;
171         *PbyteAddress = 0xe9;
172         DwordAddress = (PULONG)((ULONG)TheHookAddress + 1);
173         *DwordAddress = AddressOffset;
174         TempBufferCopy = (ULONG)PbyteAddress + 5;
175     }
176     //_asm {int 3};
177     _asm{retn 0x8 }
178 }
179 NTSTATUS UnloadFunc(PDRIVER_OBJECT MyDriver, PUNICODE_STRING RegPath)
180 {
181     //清理必要資源
182     return STATUS_SUCCESS;
183 }
184 NTSTATUS DriverEntry(PDRIVER_OBJECT MyDriver, PUNICODE_STRING RegPath)
185 {
186     NTSTATUS Status = 0;
187     AddressOfFuncAddress=ExAllocatePool(NonPagedPool, 4);
188     MyDriver->DriverUnload = UnloadFunc;
189     Status = HookSSDT((PVOID)SSDTFunc);
190     if (!NT_SUCCESS(Status))
191     {
192         return 1;
193     }
194     return STATUS_SUCCESS;
195 }

 

相關文章