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