Windows内核中的CPU架构-6-中断门(32-Bit Interrupt Gate)
中断门和调用门类似,也是一种系统段。同样的它也可以用来提权。
中断门:
虽然中断门的段描述符如下:
但是中断门其实也就是段描述的一种。只不过有稍微区别,并且和调用门的段描述符类型非常相似。
中断门和调用门的区别:
这里将调用们的段描述符拿来对比下:
可以看到大致的结构是相同的,只不过 高32位的0-4位作为了一种保留位,采用0填充。
而Type位和段描述符中的s位采用了固定的值。其实这个就拿标准段描述符拿来对比就好了。
首先肯定是一个系统段,那么S字段就采用的是0,Type字段用来标记是系统段的哪一个段,根据下图就采用D,12的32-Bit Interrupt Gade段。
除了段描述符的区别,还有段选择子的区别:
中断门的段描述符存放在 idt表里面,前面解析的时候有提过idt和gdt表,两者用起来是一模一样的。
手动实现中断门:
构建中断门
跟前面一样根据段描述符来构建:
高32位:
0-7:
00
8-11:
E
12-15:
E
16-31:
0040
低32:
0-15:
1080
16-31:
0008
得到的段描述符为: 0040EE0000081080
注:这里的配段描述符的过程可以参考前一博客:Windows内核中的CPU架构-5-调用门(32-Bit Call Gate) - Sna1lGo - 博客园 (cnblogs.com)
中的流程。
存放中断门
中断门和调用门类似,我们需要把它的段描述符保存到表里,中断门的表是idt表,所以这里我们首先查看idt表里面的内容:
可以看到这个80b93500这里是空缺的,我们就把内容放到这里把:
使用中断门:
就首先得明白什么是中断:(百度百科)中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
其实就是停止当前的操作跳转到自己定义的中断操作里面。有点类似与异常处理了,但是它针对的是CPU的,就CPU才是真正执行代码的硬件,就CPU直接停止当前操作去进行中断操作了。大概这样理解就可以了。
然后执行中断操作采用的是int 指令,然后后面会加一个编号,来标识该中断的段描述符在idt表中的位置。 比如说int 3这个中断指令,我们通过WinDbg来查看下它的段描述符信息:
它的段描述符为 83e7ee00 000086180,然后函数地址是83e76180,函数名称是 KiTrap03
所以我们调用的时候,直接在自己的内联汇编里面采用 int x指令就行。
由于前面我们把自己的中断描述符放到了80b93500的位置,所以通过计算(80b93500-80b93400)/8=20。我们直接采用int 0x20就行了。
还需要注意的是编写中断的函数和普通的函数不一样,不能采用ret和retn,得采用iretd作为返回指令。
使用中断门完整代码:
#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
push eax
mov eax, 0x80b93040
mov eax, [eax]
pop eax
iretd
}
}
int main()
{
printf("%x\n", test);
__asm
{
int 0x20
}
system("pause");
return 0;
}
这样我们的程序就可以美美地在x86系统上运行了。
小结
中断门和调用门比较类似,也是一种用来提权的东西。其核心理念在于Windows对intel CPU的一种利用。中断也是一个常用的计算机术语,其内容也包含了很多,这里就不深入了。任重而道远,大家加油。