好吧,我胡汉三肥来了..(确实肥了- -),几个月没发什么文章.其实.我也只是一个新丁~欢迎大家交流,高手勿喷,谢谢合作^_^
对于SSDT,不知道的同学请自己百度,判断出SSDT被HOOK之后,如何恢复成原始服务地址?主要方法有两个,简单来说,一个Ring0,一个Ring3的方法(可能分类不够准确),我今天除了介绍方法之外,主要还是讲讲里面的原理吧,原理神马的才是最吸引人的对吧.
首先科普一下基础,SSDT,就是System Service Descriptor Table,在内核中导出符号为KeServiceDescriptorTable.对于Ring3下的一些API,最终会对应于Ntdll.dll里一个Ntxxx的函数,例如CreateFile,最终调用到Ntdll.dll里的NtCreateFile这个函数,NtCreateFile最终将系统服务号放入EAX,然后CALL系统的7FFE0300处存放的一个地址(后面细说),进入到内核当中,从Ring3->Ring0,最终在Ring0当中通过传入的EAX得到对应的同名系统服务的内核地址.这样就完成了一次系统服务的调用.下面的图是ntdll!NtCreateFile的反汇编片段:
可以看到,NtCreateFile传入的服务号是25h,对于7FFE0300h处,实际上是UserShareData!SystemCallStub,这是一个函数指针,里面存放的值可能是KiIntSystemCall或者是KiFastSystemCall的地址,在我的Xp下,存放的是KiFastSystemCall的地址,之后的流程是:KiFastSystemCall->sysenter->KiFastCallEntry->查找SSDT,call过去.有兴趣的同学可以在WRK当中搜索相关的函数去走一下流程.
说了那么多不相关的话- -,好吧,这个SSDT的表这么理解(如果你硬是要纠结于细节的话,是KeServiceDescriptorTable->Base这个表),就是一个存放着函数指针的表,而这些函数指针指向的就是系统重要的服务例程.这个表的重要性很高,如果说有恶意的程序对这个表进行了HOOK,修改了服务例程地址为自己提供的假服务例程,那么就可以干一些坏事了.我们可以很容易的得到SSDT的具体内容,如何知道SSDT有没有被Hook,一个简单的方法就是判断SSDT中的函数指针是否是在内核(ntoskrnl.exe或ntkrnlpa.exe)的内存镜像地址范围内,这个只是单纯的检测,具体恢复需要知道原始的服务例程的原始地址.我一开始以自己很傻很天真的思路想,内核获取函数地址不就是用MmGetSystemRoutineAddress么,那么这样就可以得到原始地址了嘛,结果实现了一下发现,你妹的MmGetSystemRoutineAddress只对导出的函数(输出目录当中的函数有用),我当时就凌乱了..痛苦的把脸转向一边...
对于KeServiceDescriptorTable是在KiInitSystem中初始化,代码如下:
具体是通过KiServiceTable初始化的,KiServiceTable的具体内容通过反汇编内核,我这里是ntkrnlpa.exe,如下:
可以看到,KiServiceTabl