【编程技术-30.滴水中级班(内核驱动)——API函数的调用过程(3环进入0环)下】此文章归类为:编程技术。

我们这节课继续分析一下中断门也好、system也好,它的下一步是怎么执行的,我们先来看一下中断门,假设当前的CPU不支持快速调用的话(也就是sys指令),那么所有的API都是通过0x2e这个中断进入到零环的。

之前我们也分析过,进入零环的时候,有四个寄存器是必须要更改的就是CS/SS/ESP/EIP,CS和SS从三环进入零环的时候必须要切换为一个零环的段,ESP指向了切换到零环后堆栈从哪里执行,EIP指向了切换到零环后代码从哪里开始跑。也就是说,如果正确地设置好这四个值,那么程序从三环进入到零环后就可以正常地执行。所以我们分析一下,当我们通过中断门进入到零环的时候,这四个值是从哪里来的,那么我们来看一下,因为0x2e是IDT表里面的一个中断号,我们先找一下IDT这张表:

0x2e对应的十进制是46,那就是8003f570这里对应的了,也就是说的那个我们通过中断门进入零环的时候,对应的就是这个门,那么这个门具体是什么呢?我们知道IDT里面存储了三种门分别是中断门、任务门和陷阱门,我们看到这里的804dee00,这里的ee就说明是一个中断门,大家注意观察后面的0008f631,这里的十六位提供的就是CS,这块如果听不懂回去看中断门那节课的视频,我们已经找到了CS是这个中断门里面的,那我么了解中断门结构的话,是知道最高的两个字节加上最低的两个字节所凑成的四个字节就是EIP,也就是我们进到零环的时候要执行的代码在哪里,也就是说在中断门描述符里面,这四个寄存器的值我们已经找到了CS和EIP,那SS和ESP是哪里来的呢?TSS提供的,如果你不知道TSS的话就参考保护模式的TSS那一节的视频。好了,到现在为止,四个寄存器的值都是哪里来的我们已经知道了,下面我们进行分析当我们通过中断门进入到零环的时候它的代码是从哪里开始执行的。我们用U这个指令,这个指令可以对地址进行反汇编,当我们通过中断门进去的时候,它的执行地址是这四个字节:8040d+f631

我们注意观察,当我们发现我们通过中断门进入零环以后,它要执行的这个函数叫KiSystemService,这个函数不是ntdll模块,是真正的内核模块,稍后海哥会告诉我们内核模块是哪个文件,我们现在知道通过中断门进入零环的时候,对应的函数就是内核模块中的KisystemService这样的一个函数,通过中断门,我们现在已经知道怎么进入零环、替换那些寄存器、进入到零环以后从哪个函数开始执行。接下来我们再分析一下如果通过sysenter进入0环的话,它是如何找到这些值的,大家知道通过sysenter进入零环的时候,它省略了查找IDT表、查找TSS、查找内存的这些步骤,所以它的执行速度会非常的快,那这四个值也就是CS/SS/ESP/EIP又从哪里来呢?从MSR寄存器中来。CPU有一个叫MSR的寄存器,这个寄存器非常庞大,如果大家感兴趣呢可以去查看intel的白皮书,这个MSR寄存器在174H这个位置存储了一个值就是新的CS的h值,在175H的位置存储了ESP的值,在176H这个位置存储了EIP的值,也就是说我们要找的四个值,其中三个值都存储在MSR这个寄存器中了,当我们执行sysenter这个指令的时候,CPU会将这个IA32_SYSENTER_CS里面的CS的值存储到CS寄存器里、将ISA32_SYSENTER_ESP里面的ESP的值存储到ESP寄存器里、将IA32_SYSENTER_EIP里面的EIP的值存储到EIP寄存器里,以上皆是硬件的操作了,跟CPU没有关系。这时候还差一个SS,这个SS并没有写到MSR寄存器里,而是通过计算算出来的,怎么算呢?当我们执行sysenter指令的时候,IA32_SYSENTER_CS里面的值加上8对应的就是SS的选择子。所以虽然MSR里面只存了三个我们需要的寄存器,但是呢通过计算也可以得到SS的值。

以上说的这些并不是操作系统做的,与操作系统没有关系,以上说的这些都是CPU做的,如果你想了解刚才描述的更多细节,可以去看白皮书,白皮书里面会详细描述当我们执行sysenter指令的时候cpu都做了什么事。

这里有一个特别需要注意的地方,就是当我们执行sysenter指令的时候,必须保证我们要用到的CS/ESP/EIP的值已经正确写入到这个MSR寄存器里了,操作系统正是在启动的时候就已经把这些值提前写好,操作系统可以通过这个指令WRMST来向MSR这个寄存器中的某个位置写入这些值,我们可以通过这个指令来查看当前MSR寄存器中存储的值都是什么,比如说我想查看现在这个MSR寄存器里面存储的CS的值是什么,我就可以使用这些行指令rdmsr来看一下:

可以看到这里是08,我们散寒进入零环的时候CS的段选择子确实是08,我们再看一下esp:

esp是我们从三环进入零环的时候的值。
我们看一下通过这sysenter进入零环的时候,执行的代码在哪里,也就是EIP的值。

同样的,我们看一下这个地址的反汇编:

也就是说,我们通过sysenter指令进入到零环的时候,执行的内核的代码就是kifastcallentry函数,这个与我们通过中断门进入内核执行的函数是不一样的,那它的模块也是内核模块。到现在为止,我们学到了如何从三环进入零环,怎样找到我们需要的寄存器,进入零环以后执行的代码在哪里。
我们做个总结,如下图所示:

对于sysenter指令进入零环,也就是意味着如果我们是操作系统开发人员,那么我们必须要求MSR寄存器提供的要求去提供零环的SS。因为它的四个值CS/ESP/EIP和潜藏的SS在计算的时候,CPU已经提前约定好了,当我们通过sysenter进入零环的时候,CS的值加8就是SS的段选择子,所以你必须要提前给我提供好一个SS的段选择子,这里大家要好好理解,这里和操作系统是没有关系的。通过sysenter进入零环以后执行的内核代码是kifastcallentry,之前给大家看到过很多模块了比如kernel32dll和ntdll,这些dll都是三环的给三环用的,真正的内核模块在哪里呢?可以在c盘下面windows的system32,这个文件夹里面能找的两个文件ntoskrnl和ntkrnlpa.exe,这两个模块到底用哪个呢?取决于你的系统的分页模式,如果分页模式是29912的话那么用的是ntkrnlpa模块,如果是101012用的是ntoskrnl.exe模块。所以可以用IDA去根据分页模式打开模块。

我们刚才给大家分析的kisystemservice和kifastcallentry这两个函数自己进行分析分析,看看三环的API进入到零环以后操作系统都做了哪些事情,这里留了两道课后练习题。
更多【编程技术-30.滴水中级班(内核驱动)——API函数的调用过程(3环进入0环)下】相关视频教程:www.yxfzedu.com