中断门和调用门类似,也是一种系统段。同样的它也可以用来提权。
中断门:
虽然中断门的段描述符如下:
但是中断门其实也就是段描述的一种。只不过有稍微区别,并且和调用门的段描述符类型非常相似。
中断门和调用门的区别:
这里将调用们的段描述符拿来对比下:
可以看到大致的结构是相同的,只不过 高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
注:这里的配段描述符的过程可以参考前一博客:
中的流程。
存放中断门
中断门和调用门类似,我们需要把它的段描述符保存到表里,中断门的表是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#include 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系统上运行了。
小结