avatar

Catalog
中断门

上一篇提到过,Windows是不使用调用门的,所以在GDT表里没有找到调用门,那么Windows如何实现代码跨段,提权等行为呢?这里用的较多的是中断门,接下来就来介绍一下中断门。

IDT表

与GDT的区别

首先要提到IDT表(中断描述符表),在上一篇提到的调用门的门描述符,都在GDT表里,而中断门的门描述符在另一张叫做IDT的表里面。同GDT一样,IDT也是由一系列描述符组成的,每个描述符占8个字节。但需要注意的是,IDT表中的第一个元素不是NULL

在Windbg中查看IDT表的基址和长度:

IDT的构成

IDT表可以包含3种门描述符:

  • 任务门描述符
  • 中断门描述符
  • 陷阱门描述符

中断门执行流程

有了IDT表的概念后,咱们就可以开始讲讲中断门的执行流程,实际上和调用门差别不是很大,可以类比的来看:

  • 执行调用门的指令:CALL CS:EIP,其中CS是段选择子,包含了查找GDT表的是一个索引.
  • 执行中断门的指令:INT N,其中N是IDT表的一个索引

执行流程就只有这个差别,当CPU通过N这个索引在IDT表中找到了中断门描述符后,执行的步骤就和调用门的步骤完全一样了,可以参考调用们的执行流程。这里要注意一点,当找到中断门描述符后,还是会通过描述符里的段选择子,去GDT表中找需要跳转的代码段。所以说中断门的执行会查找两张表,先查找IDT表,再查找GDT表。

中断门描述符

简要说完了IDT表(实际上和GDT表没啥差别)来看看中断门描述符的结构:

粗略一看,和调用门描述符没差呀。这不就是无参调用门描述符换了个Type域嘛。没错,的确是这样(这里解释下D位,可以理解为段描述符的DB位,置0时为16位中断门,置1时为32位中断门)。当你发现这点时,说明调用门的结构你理解清楚了。因此结构不再赘述,可以参考调用门

中断返回

与调用门使用长返回RETF不同,中断门使用中断返回指令:IRET/IRETD

INT N指令:

  • 在没有权限切换时,会向堆栈压入3个值,分别是CS,EFLAG,返回地址
  • 在有权限切换时,会向堆栈压入5个值,分别是SS,ESP,EFLAG,CS,返回地址

这也是与调用门不同的地方,中断门会多压入一个值。于是有小盆友就要问啦,“死肥宅哥哥,为什么中断门会多压入一个参数呢?” 这还不明显吗,你想想人家调用门为什么要压入值进入堆栈啊?肯定是这些值会改变啊,所以要用堆栈保存一下,等长返回的时候,再还原状态;中断门多压入了一个EFLAG说明通过中断门跨段时,EFLAG的值会变啊!

所以,在中断门中,不能通过RETF返回,而应通过IRET/IRETD返回,其实只要改改堆栈,就可以通过RETF返回中断门,IRETD返回调用门。

代码实现

中断门比较简单,这里演示一个实现的范例

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "stdafx.h"

int saveEax = 0;
short cs3, ss3;
int eflags3, eflags0, esp3;

__declspec(naked) void GetValue() {
_asm {
mov saveEax, eax
pushfd
mov eax, [esp]
mov eflags0, eax
popfd
mov eax, [esp+4]
mov cs3, ax
mov eax, [esp+8]
mov eflags3, eax
mov eax, [esp+0xc]
mov esp3, eax
mov eax, [esp+0x10]
mov ss3, ax
mov eax, saveEax
iretd
}
}

int main(int argc, char* argv[])
{

_asm {
int 0x20
}
printf("cs3: %x, eflags3: %x, esp3: %x, ss3: %x\n \teflags0: %x", cs3, eflags3, esp3, ss3, eflags0);
getchar();
return 0;
}

根据GetValue函数的地址构造中断门描述符,然后填入中断门里即可

执行结果如下:

然后我们用int 3中断到Windbg里验证一下

验证成功。

总结

通过调用门与中断门的对比,来总结一下中断门:

  1. 调用门通过CALL FAR指令执行,但中断门通过INT指令
  2. 调用门查询GDT表,中断门查询IDT表(后续也会再查询GDT表)
  3. CALL CS:EIP中的CS是段选择子,由3部分组成,而INT N指令中的N只是索引,中断门不检查RPL,只检查CPL
  4. 调用门可以有参数,但中断门没有参数

参考教程:https://www.bilibili.com/video/av68700135?p=19

Author: cataLoc
Link: http://cataloc.gitee.io/blog/2020/03/15/%E4%B8%AD%E6%96%AD%E9%97%A8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶