在这里要明确一个概念,就是“段选择子”。选择段子所选择的是一个描述符,在这里只考虑全局描述符表的时候,也可以认为一个段选择子就选择了一个GDT中的描述符。 所有的全局描述符都存在全局描述符表中,结构和上面的调用门类似。其中P表示这个描述符是否有效,DPL表示调用门的特权级,段选择子指出要访问的代码段,偏移量指出在代码段中的入口点,参数计数给出的是要传递的参数的数量。主程序通过堆栈把入口参数传递给子程序。如果利用调用门调用子程序时,引起特权级的转换和堆栈的改变,那么就需要将外层堆栈中的参数复制到内存堆栈,而复制的数量则由参数计数决定。 问题在于:sysenter虽然可以在R3下执行,但是跳转的目的地址却一定要在R0下指定。换句话说,我可以在R3下调用sysenter,却无法控制我要跳转的地址。 跳转地址是由Windows预先设置的,下面介绍这个地址的设置方法。这些地址保存在3个特殊的寄存器中。
设置方法为调用wrmsr指令,这是特权指令。方法如下:把寄存器代号放入ecx中,把要设置的内容放在eds:eax中。 mov ecx,0x8 ;Windows xp下代码段选择子为8 mov dword ptr eds:[eax],0x8????? ;固定跳转到某个内核地址 wrmsr ;写入 以上代码当然是Windows系统执行的。然而如果编写了R0代码也可以执行,但是在R3下不能执行。 值得注意的是,SYSENTER_CS_MSR总是被设置为8。Windows中所有的内核代码段都公用这个描述符-----实际计算得到的段基地址总数全0,这就是为何在Windows下虚地址总是线性地址的原因。 此外,sysenter执行后的堆栈段,以及sysexit返回后的代码段和堆栈段也需要确定段选择子。这个在指令手册上已经有规定,所以只需要设置一个SYSENTER_CS_MSR就可以了。剩下的这个选择子之后连续排列。 总而言之,sysenter的过程可以概述如下: 1、装载SYSENTER_CS_MSR到cs寄存器 2、装载SYSENTER_EIP_MSR到eip寄存器 3、装载SYSENTER_CS_MSR+8到SS寄存器 4、装载SYSENTER_ESP_MSR到esp寄存器 5、切换到R0层 6、清除eflags寄存器中的VM标志 7、执行eip开始的R0例程 而sysexit返回的过程除了用到上面表格中的两个段选择子之外,还要加载edx到eip中,加载ecx的值到esp中。换句话说,在执行sysexit之前,要返回的地址应保存在edx中,概述如下 1、SYSENTER_CS_MSR+16装载到cs寄存器 2、将edx的值送人eip 3、SYSENTER_CS_MSR+24装载到ss寄存器 4、将ecx的值送入ESP 5、切换回R3层 6、执行eip处的R3指令
|
|
来自: astrotycoon > 《386》