64位下好神奇啊(增加了PatchGuard技术保护自己,SSDT是相对地址,参数通过寄存器与rdi来传递)
近期可能会有一个64位平台的驱动开发任务,找了些资料,对64位平台下的驱动开发略知一二了,好神奇。
一。在64位系统下,有一项PatchGuard技术,它是微软为了防止自己的代码被Patch,进而影响系统的稳定性引入的,这项技术会检查以下内容有没有被恶意修改过:
1- SSDT (System Service Descriptor Table)
2- GDT (Global Descriptor Table)
3- IDT (Interrupt Descriptor Table)
4- System images (ntoskrnl.exe, ndis.sys, hal.dll)
5- Processor MSRs (syscall)
如果检测到以上内容被修改过就会出来一个BSOD。
二。在64位系统,内核函数开头地址的低四位一般是0,形如:xxxxxxxx`xxxxxxx0,这一特征在SSDT表中有很强大的引用,SSDT表在64位系统于32位系统有较大的差别。以下是在64位系统下的KeServiceDescriptorTable:
kd> dp KeServiceDescriptorTable
fffff800`0117bb80 fffff800`01076e00 00000000`00000000
fffff800`0117bb90 00000000`00000128 00000000`00000000
表的第二项于第四项都为0,这两项在32位系统下分别对应ServiceCounterTableBase与ParamTableBase。SSDT表还是同32位系统每4字节表示一项,由于函数的起始地址最低四位都是0,所以微软将SSDT中的低四位用来记录这个函数有多少个参数。并且由于表的每一项都为四个字节,保存的就不可能是绝对地址,而是相对KeServiceDescriptorTable表的地址。所以地址计算方法如下:
FuncAddr=([KeServiceDescriptortable+index*4]+KeServiceDescriptortable)&0xFFFFFFF0
三。在64位系统上,函数调用不再像32位系统下,先是一堆push,然后一个call。在64位系统上,参数不是通过堆栈传递的,而是寄存器与rdi。这样大大减少了被溢出的可能性,提高了安全性。
如果函数少于等于四个参数,那么直接使用寄存器,第一个参数保存在rcx,第二个参数rdx,第三个r8寄存器,第四个r9寄存器,
如果函数有大于四个参数,那么就将第五个开始的参数保护在rdi指向的内存空间,第5个参数保存在rdi+8,第6参数保存在rdi+0x10,第7个rdi+0x18.......