通过构造系统服务分发实现拦截&过滤 (仿360游戏保险箱)

发布者:Ox9A82
发布于:2016-03-03 00:07

想写这个程序主要是因为看了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 }

 


声明:该文观点仅代表作者本人,转载请注明来自看雪