Windows内核实验:InlineHook
hook的话,我们肯定要把代码hook到内核空间里,所以必须要把代码写到内核里,我们可以利用ExAllocatePool分配一块内存或者在内核里找一块安全的内核不会用到的内存
kd> dq @gdtr l100 8003f000 00000000`00000000 00cf9b00`0000ffff 8003f010 00cf9300`0000ffff 00cffb00`0000ffff 8003f020 00cff300`0000ffff 80008b04`200020ab 8003f030 ffc093df`f0000001 0040f300`00000fff ...... 8003f110 f840933d`5400ffff 00000000`8003f120 8003f120 00000000`8003f128 00000000`8003f130 8003f130 00000000`8003f138 00000000`8003f140 8003f140 00000000`8003f148 00000000`8003f150 8003f150 00000000`8003f158 00000000`8003f160 8003f160 00000000`8003f168 00000000`8003f170 8003f170 00000000`8003f178 00000000`8003f180 8003f180 00000000`8003f188 00000000`8003f190 8003f190 00000000`8003f198 00000000`8003f1a0 8003f1a0 00000000`8003f1a8 00000000`8003f1b0 8003f1b0 00000000`8003f1b8 00000000`8003f1c0 8003f1c0 00000000`8003f1c8 00000000`8003f1d0 8003f1d0 00000000`8003f1d8 00000000`8003f1e0 8003f1e0 00000000`8003f1e8 00000000`8003f1f0 8003f1f0 00000000`8003f1f8 00000000`8003f200 8003f200 00000000`8003f208 00000000`8003f210 8003f210 00000000`8003f218 00000000`8003f220 8003f220 00000000`8003f228 00000000`8003f230 8003f230 00000000`8003f238 00000000`8003f240 8003f240 00000000`8003f248 00000000`8003f250 8003f250 00000000`8003f258 00000000`8003f260 .........
|
gdt表里其实有好多没有用的位置,完全满足我们写小代码hook的需求
hook的函数_KiFastCallEntry,这个函数会被频繁调用,3环到0环的需求是很频繁的
.text:80541510 _KiFastCallEntry proc near ; DATA XREF: KiLoadFastSyscallMachineSpecificRegisters(x)+24↑o .text:80541510 .text:80541510 B9 23 00 00 00 mov ecx, 23h ; '#' .text:80541515 6A 30 push 30h ; '0' .text:80541517 0F A1 pop fs .text:80541519 8E D9 mov ds, ecx .text:8054151B 8E C1 mov es, ecx .text:8054151D 64 8B 0D 40 00 00 00 mov ecx, large fs:40h .text:80541524 8B 61 04 mov esp, [ecx+4] .text:80541527 6A 23 push 23h ; '#' .text:80541529 52 push edx .text:8054152A 9C pushf
|
hook到8054151D处,这里ecx寄存器会再次被赋值,我们就可以利用ecx寄存器去避免jmp偏移地址的计算(膜拜周壑orz)
注入代码地址选择到gdt表8003f130处
#include <stdio.h> #include <stdlib.h> #include <windows.h> void JmpTarget(); char* p = (char *)0x8003f130; size_t i; void __declspec(naked) IdtEntry() { __asm { push 0x30 pop fs sti } for (i = 0; i < 0x30; i++) { *p = ((char*)JmpTarget)[i]; p++; } __asm { cli push 0x3B pop fs iretd } } void __declspec(naked) JmpTarget() { __asm { mov ecx, 0x23 push 0x30 pop fs mov ds, cx mov es, cx mov ecx,0x8054151D jmp ecx } } void interrupt() { __asm { int 0x20 } } int main() { if (0x401040 != IdtEntry) { printf("IdtRntry address wrong"); system("pause"); exit(-1); } interrupt(); system("pause"); }
|
kd> u 0x8003f130 l30 8003f130 b923000000 mov ecx,23h 8003f135 6a30 push 30h 8003f137 0fa1 pop fs 8003f139 668ed9 mov ds,cx 8003f13c 668ec1 mov es,cx 8003f13f b91d155480 mov ecx,offset nt!KiFastCallEntry+0xd (8054151d) 8003f144 ffe1 jmp ecx
|
80541510这个地址是不可写的,CR0[16] WP(Write Protect) 写保护位,为1时,禁止内核级代码写用户级的只读内存页;为0时允许
偏移=8003f130-80541515=FFAF DC1B
#include <stdio.h> #include <stdlib.h> #include <windows.h> void __declspec(naked) IdtEntry() { __asm { mov eax, cr0 and eax, not 0x10000 mov cr0, eax
mov al, 0xe9 mov ds : [0x80541510] , al mov dword ptr ds : [0x80541511],0xFFAFDC1B
mov eax, cr0 or eax, 0x10000 mov cr0, eax iretd } } void interrupt() { __asm { int 0x20 } } int main() { if (0x401040 != IdtEntry) { printf("IdtRntry address wrong"); system("pause"); exit(-1); } interrupt(); system("pause"); }
|
这样写代码去改_KiFastCallEntry入口点代码主要是因为我们是单核单线程的机器
如果是多核多线程,显然会有并发问题,比如我cpu1在改的过程中还没改完,此时调度到cpu2执行可能执行到我们还没改完的代码造成蓝屏,需要加把锁
ok了
kd> u 80541510 nt!KiFastCallEntry: 80541510 e91bdcafff jmp 8003f130 80541515 6a30 push 30h 80541517 0fa1 pop fs 80541519 8ed9 mov ds,cx 8054151b 8ec1 mov es,cx 8054151d 648b0d40000000 mov ecx,dword ptr fs:[40h] 80541524 8b6104 mov esp,dword ptr [ecx+4] 80541527 6a23 push 23h kd> u 8003f130 8003f130 b923000000 mov ecx,23h 8003f135 6a30 push 30h 8003f137 0fa1 pop fs 8003f139 668ed9 mov ds,cx 8003f13c 668ec1 mov es,cx 8003f13f b91d155480 mov ecx,offset nt!KiFastCallEntry+0xd (8054151d) 8003f144 ffe1 jmp ecx 8003f146 cc int 3
|
然后我们就可以把寄存器都保存一下然后写自己的代码
void __declspec(naked) JmpTarget() { __asm { pushad pushfd +++++your code++++++ popfd popad mov ecx, 0x23 push 0x30 pop fs mov ds, cx mov es, cx mov ecx, 0x8054151D jmp ecx } }
|