现在探讨内核程序和应用程序之间的本质区别。除了能用WDK编写内核程序和阅读一部分Windows的内核代码之外,我们还需要了解它们的本质是什么,它们和我们熟悉的应用程序有什么区别。
Intel的x86处理器是通过Ring级别来进行访问控制的,级别共分4层,从Ring0到Ring3(后面简称R0、R1、R2、R3)。R0层拥有最高的权限,R3层拥有最低的权限。按照Intel原有的构想,应用程序工作在R3层,只能访问R3层的数据;操作系统工作在R0层,可以访问所有层的数据;而其他驱动程序位于R1、R2层[多多关注www.hitidc.com],每一层只能访问本层以及权限更低层的数据。
这应该是很好的设计,这样操作系统工作在最核心层,没有其他代码可以修改它;其他驱动程序工作在R1、R2层,有要求则向R0层调用,这样可以有效保障操作系统的安全性。但现在的OS,包括Windows和Linux都没有采用4层权限,而只是使用2层——R0层和R3层,分别来存放操作系统数据和应用程序数据,从而导致一旦驱动加载了,就运行在R0层,就拥有了和操作系统同样的权限,可以做任何事情,而所谓的rootkit也就随之而生了。
rootkit在字面上来理解,是拥有“根权限”的工具。实际上,所有的内核代码都拥有根权限,当然,并不一定它们都叫做rootkit,这要看你用它来做什么。用rootkit技术开发的木马和病毒正在迅速发展,它们往往极难清除,以往杀毒软件可以轻松清除掉系统中病毒的时代似乎已经一去不复返了。
大多数指令可以同时使用于R0层和R3层,但有[多多关注www.hitidc.com],些和系统设置相关的指令却只能在R0层被使用,或者在R3层的使用受到限制,主要有下面这些:
lgdt:加载GDT寄存器
lldt:加载LDT寄存器
ltr:加载任务寄存器
lidt:加载IDT寄存器
mov:加载和存储控制寄存器、调试寄存器时受限
lmsw:加载机器状态字
clts:清除cr0中的任务切换标记
invd:缓冲无效,并不写回
wbinvd:缓冲无效,并写回
invlpg:无效TLB入口
hlt:停止处理器
rdmsr:读模式指定寄存器
wrmsr:写模式指定寄存器
rdpmc:读取性能监控计数器
rdtsc:读取时间戳计数器
最后2条指令rdpmc和rdtsc,在cr4的位4(PCE)和位2(TSD)被设置的情况下可以同时被R0层和R3层调用。任何违反上面规定的操作,在Windows下都可能会产生通用保护故障的异常。
另外,还有些所谓的IO敏感指令,包括:
cli:关闭中断
sti:开启中断
in:从硬件端口读
out:往硬件端口写
这些指令在R0层可以直接被使用,在R3层被使用的时[多多关注www.hitidc.com],候还要检查IO许可位图,综合判断是否允许调用。
当然,前面已经声明我们写的和研究的代码都是内核代码,也就是说,上面这些指令都是可以用的。当然,相应的rootkit技术的病毒和木马的作者显然也会明白这一点,所以这并不是让人很有安全感的一个现状。
更重要的保护机制是如何保证系统内存空间的读/写、可执行属性,这将在12.2节“保护模式下的分页内存保护”中详述。对于病毒和木马来说,使用硬件机制来实现破坏虽然并非不可能,但是远不如直接修改内存中的操作系统内核和其他[多多关注www.hitidc.com],软件的代码来得简洁方便,那是破坏与安全对抗的主战场。