} }
VOID RestoreHook() {
UINT ln=sizeof(HookData)/sizeof(__hook_find); UINT i;
PUCHAR pAddr; DWORD dwOldAddr; for (i=0;i if(HookData[i].dwFindPos) { pAddr=(PUCHAR)HookData[i].dwFindPos; dwOldAddr = *((ULONG*)(pAddr+1)); CLR_WP(); *((ULONG*)(pAddr+1)) (HookData[i].dwCallDst-HookData[i].dwFindPos-5); SET_WP(); HookData[i].dwCallDst=dwOldAddr; HookData[i].dwFindPos=0; } } } = 5.8 HOOK Windows内核异常处理函数 上面功能都还容易实现,但是异常处理就有点困难,因为它属于Windows系统内核很底层了。在Windows系统中,中断和异常是其重要的机制。Windows系统采用中断描述述表(IDT),对于每个CPU,Windows系统都定义一个IDT表。IDT表中比较常见的异常有_KiTrap00(除0异常), _KiTrap03(断点异常)是我们的关键。_KiTrap0E(缺页异常),后面一般是中断的,比如键盘,鼠标驱动的中断响应程序等等。 Windows内核采用分页文件虚拟内存技术,当我们进程要操作的内存不在物理内存时或者因为我们的权限不够不能访问相应内存时,CPU就会产生0xE号异常,CPU会自动保存当前上下文。然后调用_KiTrap0E异常响应函数,它里面就会判断是不是因为要访问的内存在分页文件中,如果在分页文件,则Windows 内存管理器会把它调进物理内存,然后继续访问。如果是因为访问权限不够的话就会抛出异常。一层一层的返回到用户层。如果用户层有处理的话就处理了,没有处理的话,这个程序就会弹出大家所熟悉的(访问内存错误)ACCESS_VIALATION对话框,然后程序崩溃。 Int 3异常才是我们真正感兴趣的异常。比如我们用OD调试一个进程时,F2下断点,真正做的是把这个指令改成0xCC也就是Int 3。为什么程序一运行这个int 3,OD就会中断理解如下: 当用户层进程执行INT 3指令时,CPU会产生异常,从而执行_KiTrap03异 35 常处理机制,_KiTrap03会先构造此次异常结构,然后调用CommonDispatchException()这个函数,这个函数最终会调用Windows内核真正通用的异常处理函数KiDispatchException()。一般产生的异常都会进入这个函数进行处理,这个函数会对产生此次异常时是处于用户层模式还是内核模式,如果产生此次异常时是内核下,刚这个函数会几次交给内核调试器处理,如果没有找到内核调试器的话,会再次调用RtlDispatchException()这个函数交给内核我们自己的异常处理,如果这也没有找到异常处理函数,则调用KeBugCheckEx()使之蓝屏。如果产生些次异常是在用户模式下,则会在内核下构造堆栈,使之返回到用户层,然后用户层就会一次一次的处理异常。找到处理这次异常的处理函数,如果这个进程当前处于被调试状态,刚会向调试这个进程的调试器发送调试事件。然后会给异常处理机制,如果都没有处理,刚这个进程就会强制结束。所以我们要HOOK的函数就是KiDispatchException(),然后进入我们自己的处理函数。 系统开发小结 本系统基本实现了能改变OD调试器的关键函数的系统调用,使其调用我们自己在内核中实现的系统调用,还有调试时常用的调试模块也是用的我们自己实现的。但是DebugPort的移值还没有测试,异常处理机制的HOOK也没有完善,因为Windows异常处理机制是Windows内核的处理核心,我调试了很久,仍然存有问题。仍需以后慢慢完善。通过此次的论文,我学到了很多,比如弄懂了Windows内核的调试机制是怎么实现的。Windows系统调用是怎么实现的。还有就是学会了怎么在内核下调用微软未导出的内核函数,弄懂了很多Windosw XP内核的系统知识。 参考文献 [1] Mark E.Russinovich and David A.Solomon < Windows Internals>(第5版) [2] Jeff Prosise [4] David j.Kruglinski 36