前言
之前的实验让我们学习到了如何调用内核的API,我们可以通过创建一个稳定的零环到三环之前的切换环境,而在此次实验中我们将把从三环到零环的_KiFastCallEntry
进行Hook
,通过该操作来达到在三环到零环之前切换前执行相应的代码
实验过程
我们还是利用上次的代码逻辑,不同的是在本次实验中我们需要使用两个exe
来完成对应的Hook
第一个exe
将对应_KiFastCallEntry
的地址空间进行修改,通过把前几个字节替换为jmp
(0xe9)进行跳转到我们构造的代码上,第二个则是将构造的代码写入到内核的某个全局位置,在第一个exe
跳转的时候进行执行我们构造的特殊内容,同时执行原有的_KiFastCallEntry
的内容,避免内核崩溃,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| #include <stdio.h> #include <stdlib.h> #include <Windows.h>
#define Part 1 #if Part
void __declspec(naked) IdtEntry() { __asm { mov eax, cr0 and eax, not 10000h mov cr0, eax; 关闭写保护
mov al, 0xe9; jmp mov ds : [0x80542520] , al mov eax, 0xFFAFCBFB; 计算相应偏移量 0x8003f120 - 0x80542525 = 0xFFAFCBFB mov ds : [0x80542521] , eax
mov eax, cr0 or eax, 10000h mov cr0, eax; 打开写保护 iretd } } void crash() { while (1) { __asm { int 0x20 } } } int main() {
if ((DWORD)IdtEntry != 0x00401040) { printf("wrong addr : %p \n", IdtEntry); exit(-1); } crash(); system("pause"); return 0; } #else void hook(); int i = 0; char* p = (char*)0x8003f120;
void __declspec(naked) IdtEntry() { for (i = 0; i < 64; i++) { *p = ((char*)hook)[i]; p++; } __asm { iretd } } void crash() { __asm { int 0x20 } } void __declspec(naked) hook() { __asm { pushad pushfd
mov eax, ds: [0x8003f1f0] inc eax mov ds : [0x8003f1f0] , eax ;每当执行一次零环到三环的切换时对应的值便会加一
popfd popad
mov cx, 0x23 push 0x30 pop fs mov ds, cx mov es, cx mov ecx, 0x8054252D; 跳回去执行后续代码 jmp ecx } } int main() { if ((DWORD)IdtEntry != 0x00401040) { printf("wrong addr : %p \n", IdtEntry); exit(-1); } crash(); system("pause"); return 0; } #endif
|
在上述的代码过程中我们使用的内核的GDTR
表中的空字节数据,将我们的构造的代码进行填充。同时把我们在GDTR
的0x8003f1f0
处设定了一个变量(虽然没初始化),每当有三环到零环的切换其值便会增加一。
上面的代码使用#if
、#else
、#endif
的宏来进行控制对应的代码生成,因为笔者环境莫名其妙的在开多个工程文件的时候会出现编译问题
总结
在此过程中我们并没有实现太多的东西,只是简单的对三环到零环切换次数进行计算,此次实验中对于jmp
的地址调试以及忘记将Hook
函数设置为裸函数而导致花费了挺长时间(归根还是菜QwQ),以及一些细节方面的小问题。
相信通过上述的简单逻辑介绍各位师傅可以实现更实用的功能。此处便不再往后讲解了。