这两天模拟江民的进程保护。。。。 inline hook KeInsertQueueApc , 写个笔记。。。
内核中的游戏太有意思了。。。出招 。。拆招。。。。。。各种想法。。。。各种技巧。。无所不用其极。。。。。就看谁的内功更nb 。。。。继续。。。
最郁闷code标签。。每次都把偶的代码弄的乱糟糟。。。。。。。
Code
1 #include <ntddk.h>
2 #include <windef.h>
3
4 /************************************************************************/
5 /* inline hook的框架, 今天好好的做下笔记。。 */
6 /*1. 查找到native api的地址。 */
7 /*2. 保存native api的前五个字节 */
8 /*3. 写一个hook函数 */
9 /*4. 修改native api的前五个字节,使其执行时跳到我们的函数中 */
10 /*5. 执行完成后跳回原函数 */
11 /* */
12 /* */
13 /************************************************************************/
14
15 #define HOOK_FUNCTION_NAME L"KeInsertQueueApc"
16 #define HOOK_LENGTH 5
17
18 UCHAR g_origcode [5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
19 UCHAR g_hook_code[5] = { 0xe9/*short jmp*/, 0x00, 0x00, 0x00, 0x00 };
20 UCHAR g_back_code[7] = { 0xea/*long jmp*/, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 };
21
22
23 ULONG g_cr0;
24 ULONG g_function_address;
25
26
27
28 ULONG get_function_address( IN PCWSTR _pname );
29
30 NTSTATUS hook_native_api( );
31
32 NTSTATUS un_hook_native_api( );
33
34 void fake_my_native_api(PKAPC Apc, KPRIORITY Increment );
35
36 void fake_proxy_my_native_api(PKAPC Apc, KPRIORITY Increment );
37
38
39 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
40 // author: herso date: 2009/04/18
41 --------------------------------------------------------------------------------------------
42 // 说明: 内核数据的页属性都是只读的,不能更改。内核模式也没有提供类似应用层的VirtualProtectEx()
43 等函数来修改页面属性,所以我们可以通过修改cr0寄存器的的写保护位来使得内核页面可写。
44
45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
46 void WPOFF()
47 {
48 ULONG uAttr;
49
50 _asm
51 {
52 push eax;
53 mov eax, cr0;
54 mov uAttr, eax;
55 and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
56 mov cr0, eax;
57 pop eax;
58 cli
59 };
60 g_cr0 = uAttr; //保存原有的 CRO 屬性
61
62 }
63
64
65 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 // author: herso date: 2009/04/18
67 --------------------------------------------------------------------------------------------
68 // 说明: 恢復原有 CR0 屬性
69
70
71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
72 VOID WPON()
73 {
74 _asm
75 {
76 sti
77 push eax;
78 mov eax, g_cr0; //恢復原有 CR0 屬性
79 mov cr0, eax;
80 pop eax;
81 };
82 }
83
84
85
86 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
87 // author: herso date: 2009/04/18
88 --------------------------------------------------------------------------------------------
89 // 说明:
90
91
92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
93 NTSTATUS hook_native_api()
94 {
95 KIRQL oldIrql;
96
97 //得得导出的函数的地址
98 g_function_address = get_function_address( HOOK_FUNCTION_NAME );
99
100 //减5是计算相对地址时,把本身的这个JMP指令占的5个字节要减去,从它下面的地址开始算起。
101 *((PULONG)&g_hook_code[1]) = (ULONG)fake_my_native_api - g_function_address - 5;
102
103 *((PULONG)&g_back_code[1]) = (ULONG) ((BYTE*)g_function_address + 5);
104
105 //1. 保存native api的前5个字节
106 RtlCopyMemory( g_origcode, (BYTE*)g_function_address, HOOK_LENGTH );
107
108 // 禁止系统写保护,提升IRQL到DPC
109 WPOFF();
110 oldIrql = KeRaiseIrqlToDpcLevel();
111
112 //2. 修改native api的前5个字节为一个jmp指令,跳到我们的函数中去
113 RtlCopyMemory( (BYTE*)g_function_address, g_hook_code, 5 );
114
115 //3. 填充proxy函数,该函数执行native api的前5个字节,然后用一个长跳转跳回原函数
116 RtlCopyMemory( (BYTE*)fake_proxy_my_native_api, g_origcode, 5 );
117 RtlCopyMemory( (BYTE*)fake_proxy_my_native_api+5, g_back_code, 7 );
118
119 // 恢复写保护,降低IRQL
120 KeLowerIrql(oldIrql);
121 WPON();
122
123 return STATUS_SUCCESS;
124
125 }
126
127
128
129 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
130 // author: herso date: 2009/04/18
131 --------------------------------------------------------------------------------------------
132 // 说明:恢复原函数的前5个字节,卸掉hook函数
133
134
135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
136 NTSTATUS un_hook_native_api( )
137 {
138 KIRQL oldIrql;
139
140 // 禁止系统写保护,提升IRQL到DPC
141 WPOFF();
142 oldIrql = KeRaiseIrqlToDpcLevel();
143
144 RtlCopyMemory( (BYTE*) g_function_address, g_origcode, 5 );
145
146 // 恢复写保护,降低IRQL
147 KeLowerIrql(oldIrql);
148 WPON();
149
150 return STATUS_SUCCESS;
151 }
152
153
154 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
155 // author: herso date: 2009/04/18
156 --------------------------------------------------------------------------------------------
157 // 说明:在该函数中进行过滤,完成操作后通过jmp 跳到 proxy_my_native_api,完成hook动作。
158
159
160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
161 _declspec (naked )
162 void fake_my_native_api(PKAPC Apc, KPRIORITY Increment )
163 {
164 __asm
165 {
166 jmp fake_proxy_my_native_api;
167 }
168
169 }
170
171
172 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
173 // author: herso date: 2009/04/18
174 --------------------------------------------------------------------------------------------
175 // 说明:执行原native api的一条指令,然后通过长跳转回到原函数中。
176
177
178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
179 _declspec ( naked )
180 void fake_proxy_my_native_api(PKAPC Apc, KPRIORITY Increment )
181 {
182 __asm
183 {
184 //_emit伪指令相当于MASM中的DB,但一次只能定义一个字节 一行用来保留字节
185 // 共12个字节 前五个字节是要hook的函数的5个字节,然后是一个long jmp 最后 有个 0x08, 0x00
186 // 需要七个字节
187
188 _emit 0x90 // \
189 _emit 0x90 // |
190 _emit 0x90 // | 将被替换成要hook函数的第一条指令执行。
191 _emit 0x90 // |
192 _emit 0x90 // /
193
194 _emit 0x90 // jmp (0xea)
195 _emit 0x90 // \/
196 _emit 0x90 // | 跳转的地址 address_hook_native_api + 5
197 _emit 0x90 // |
198 _emit 0x90 // /
199
200 _emit 0x90 // ;0x08
201 _emit 0x90 // ;0x00
202 }
203 }
204
205
206
207
208 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
209 // author: herso date: 2009/04/18
210 --------------------------------------------------------------------------------------------
211 // 说明:如果一个 native api 已经被ntoskrel.exe 导出,那么通过MeGetSystemRoutineAddress可以找
212 // 到该函数的地址,如果没有导出,只能通过搜索特征值的办法进行。
213
214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
215 ULONG get_function_address( IN PCWSTR _pname )
216 {
217
218 UNICODE_STRING us_function_name;
219
220 RtlInitUnicodeString( &us_function_name, _pname );
221
222 return (ULONG)MmGetSystemRoutineAddress( &us_function_name );
223
224 }
225
226
227
228 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
229 // author: herso date: 2009/04/18
230 --------------------------------------------------------------------------------------------
231 // 说明:卸载驱动
232
233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
234 VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
235 {
236 DbgPrint("My Driver Unloaded!");
237 un_hook_native_api();
238 }
239
240
241
242 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
243 // author: herso date: 2009/04/18
244 --------------------------------------------------------------------------------------------
245 // 说明:驱动入口
246
247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
248 NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
249 {
250
251 DbgPrint("My Driver Loaded!");
252 theDriverObject->DriverUnload = OnUnload;
253
254 hook_native_api();
255
256 return STATUS_SUCCESS;
257 }
258
259
1 #include <ntddk.h>
2 #include <windef.h>
3
4 /************************************************************************/
5 /* inline hook的框架, 今天好好的做下笔记。。 */
6 /*1. 查找到native api的地址。 */
7 /*2. 保存native api的前五个字节 */
8 /*3. 写一个hook函数 */
9 /*4. 修改native api的前五个字节,使其执行时跳到我们的函数中 */
10 /*5. 执行完成后跳回原函数 */
11 /* */
12 /* */
13 /************************************************************************/
14
15 #define HOOK_FUNCTION_NAME L"KeInsertQueueApc"
16 #define HOOK_LENGTH 5
17
18 UCHAR g_origcode [5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
19 UCHAR g_hook_code[5] = { 0xe9/*short jmp*/, 0x00, 0x00, 0x00, 0x00 };
20 UCHAR g_back_code[7] = { 0xea/*long jmp*/, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 };
21
22
23 ULONG g_cr0;
24 ULONG g_function_address;
25
26
27
28 ULONG get_function_address( IN PCWSTR _pname );
29
30 NTSTATUS hook_native_api( );
31
32 NTSTATUS un_hook_native_api( );
33
34 void fake_my_native_api(PKAPC Apc, KPRIORITY Increment );
35
36 void fake_proxy_my_native_api(PKAPC Apc, KPRIORITY Increment );
37
38
39 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
40 // author: herso date: 2009/04/18
41 --------------------------------------------------------------------------------------------
42 // 说明: 内核数据的页属性都是只读的,不能更改。内核模式也没有提供类似应用层的VirtualProtectEx()
43 等函数来修改页面属性,所以我们可以通过修改cr0寄存器的的写保护位来使得内核页面可写。
44
45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
46 void WPOFF()
47 {
48 ULONG uAttr;
49
50 _asm
51 {
52 push eax;
53 mov eax, cr0;
54 mov uAttr, eax;
55 and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
56 mov cr0, eax;
57 pop eax;
58 cli
59 };
60 g_cr0 = uAttr; //保存原有的 CRO 屬性
61
62 }
63
64
65 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 // author: herso date: 2009/04/18
67 --------------------------------------------------------------------------------------------
68 // 说明: 恢復原有 CR0 屬性
69
70
71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
72 VOID WPON()
73 {
74 _asm
75 {
76 sti
77 push eax;
78 mov eax, g_cr0; //恢復原有 CR0 屬性
79 mov cr0, eax;
80 pop eax;
81 };
82 }
83
84
85
86 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
87 // author: herso date: 2009/04/18
88 --------------------------------------------------------------------------------------------
89 // 说明:
90
91
92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
93 NTSTATUS hook_native_api()
94 {
95 KIRQL oldIrql;
96
97 //得得导出的函数的地址
98 g_function_address = get_function_address( HOOK_FUNCTION_NAME );
99
100 //减5是计算相对地址时,把本身的这个JMP指令占的5个字节要减去,从它下面的地址开始算起。
101 *((PULONG)&g_hook_code[1]) = (ULONG)fake_my_native_api - g_function_address - 5;
102
103 *((PULONG)&g_back_code[1]) = (ULONG) ((BYTE*)g_function_address + 5);
104
105 //1. 保存native api的前5个字节
106 RtlCopyMemory( g_origcode, (BYTE*)g_function_address, HOOK_LENGTH );
107
108 // 禁止系统写保护,提升IRQL到DPC
109 WPOFF();
110 oldIrql = KeRaiseIrqlToDpcLevel();
111
112 //2. 修改native api的前5个字节为一个jmp指令,跳到我们的函数中去
113 RtlCopyMemory( (BYTE*)g_function_address, g_hook_code, 5 );
114
115 //3. 填充proxy函数,该函数执行native api的前5个字节,然后用一个长跳转跳回原函数
116 RtlCopyMemory( (BYTE*)fake_proxy_my_native_api, g_origcode, 5 );
117 RtlCopyMemory( (BYTE*)fake_proxy_my_native_api+5, g_back_code, 7 );
118
119 // 恢复写保护,降低IRQL
120 KeLowerIrql(oldIrql);
121 WPON();
122
123 return STATUS_SUCCESS;
124
125 }
126
127
128
129 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
130 // author: herso date: 2009/04/18
131 --------------------------------------------------------------------------------------------
132 // 说明:恢复原函数的前5个字节,卸掉hook函数
133
134
135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
136 NTSTATUS un_hook_native_api( )
137 {
138 KIRQL oldIrql;
139
140 // 禁止系统写保护,提升IRQL到DPC
141 WPOFF();
142 oldIrql = KeRaiseIrqlToDpcLevel();
143
144 RtlCopyMemory( (BYTE*) g_function_address, g_origcode, 5 );
145
146 // 恢复写保护,降低IRQL
147 KeLowerIrql(oldIrql);
148 WPON();
149
150 return STATUS_SUCCESS;
151 }
152
153
154 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
155 // author: herso date: 2009/04/18
156 --------------------------------------------------------------------------------------------
157 // 说明:在该函数中进行过滤,完成操作后通过jmp 跳到 proxy_my_native_api,完成hook动作。
158
159
160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
161 _declspec (naked )
162 void fake_my_native_api(PKAPC Apc, KPRIORITY Increment )
163 {
164 __asm
165 {
166 jmp fake_proxy_my_native_api;
167 }
168
169 }
170
171
172 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
173 // author: herso date: 2009/04/18
174 --------------------------------------------------------------------------------------------
175 // 说明:执行原native api的一条指令,然后通过长跳转回到原函数中。
176
177
178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
179 _declspec ( naked )
180 void fake_proxy_my_native_api(PKAPC Apc, KPRIORITY Increment )
181 {
182 __asm
183 {
184 //_emit伪指令相当于MASM中的DB,但一次只能定义一个字节 一行用来保留字节
185 // 共12个字节 前五个字节是要hook的函数的5个字节,然后是一个long jmp 最后 有个 0x08, 0x00
186 // 需要七个字节
187
188 _emit 0x90 // \
189 _emit 0x90 // |
190 _emit 0x90 // | 将被替换成要hook函数的第一条指令执行。
191 _emit 0x90 // |
192 _emit 0x90 // /
193
194 _emit 0x90 // jmp (0xea)
195 _emit 0x90 // \/
196 _emit 0x90 // | 跳转的地址 address_hook_native_api + 5
197 _emit 0x90 // |
198 _emit 0x90 // /
199
200 _emit 0x90 // ;0x08
201 _emit 0x90 // ;0x00
202 }
203 }
204
205
206
207
208 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
209 // author: herso date: 2009/04/18
210 --------------------------------------------------------------------------------------------
211 // 说明:如果一个 native api 已经被ntoskrel.exe 导出,那么通过MeGetSystemRoutineAddress可以找
212 // 到该函数的地址,如果没有导出,只能通过搜索特征值的办法进行。
213
214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
215 ULONG get_function_address( IN PCWSTR _pname )
216 {
217
218 UNICODE_STRING us_function_name;
219
220 RtlInitUnicodeString( &us_function_name, _pname );
221
222 return (ULONG)MmGetSystemRoutineAddress( &us_function_name );
223
224 }
225
226
227
228 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
229 // author: herso date: 2009/04/18
230 --------------------------------------------------------------------------------------------
231 // 说明:卸载驱动
232
233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
234 VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
235 {
236 DbgPrint("My Driver Unloaded!");
237 un_hook_native_api();
238 }
239
240
241
242 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
243 // author: herso date: 2009/04/18
244 --------------------------------------------------------------------------------------------
245 // 说明:驱动入口
246
247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
248 NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
249 {
250
251 DbgPrint("My Driver Loaded!");
252 theDriverObject->DriverUnload = OnUnload;
253
254 hook_native_api();
255
256 return STATUS_SUCCESS;
257 }
258
259