文章目录
-
- 调用门
-
- 调用门执行流程
- 调用门描述符
- 调用门实验
-
- 无参调用门
-
- 示例代码
- 构造调用门
- 修改GDT表
- 执行流程
- 中断现场
- 有参调用门
-
- 示例代码
- 构造调用门
- 修改GDT表
- 中断现场
- 总结
调用门
调用门执行流程
CALL FAR的指令格式:CALL CS:EIP(EIP是废弃的)
执行步骤:
- 根据CS的值 查GDT表,找到对应的段描述符,这个描述符是一个调用门
- 在调用门描述符中存储另一个代码段的段选择子
- 选择子指向的段 段的Base+偏移 就是真正要执行的地址
调用门描述符
调用门描述符如图:
调用门实验
无参调用门
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>void __declspec(naked)GetRegister()
{__asm{int 3;retf;}
}int main()
{__asm{int 3;}printf("%p", GetRegister);//构造call cs eip指令char buff[6];*(DWORD*)&buff[0] = 0x12345678; //废弃的EIP*(WORD*)&buff[4] = 0x48; //段选择子 __asm{call fword ptr[buff];}getchar();return 0;
}
构造调用门
首先查看函数地址
记录下这个值:00401040
offset in segment 31:16:0040
P:1 DPL:11 S:0--->E
Type:1100--->C
Param Count:0
Segment Select:0008
offset in Segment 15:00:1040
#调用门描述符
0040EC00`00081040
修改GDT表
查看GDT表
kd> dq gdtr
80b95000 00000000`00000000 00cf9b00`0000ffff
80b95010 00cf9300`0000ffff 00cffb00`0000ffff
80b95020 00cff300`0000ffff 80008b1e`400020ab
80b95030 834093f7`1c003748 0040f300`00000fff
80b95040 0000f200`0400ffff 00000000`00000000
80b95050 830089f6`f0000068 830089f6`f0680068
80b95060 00000000`00000000 00000000`00000000
80b95070 800092b9`500003ff 00000000`00000000
80b95048这个位置并没有用到,我们就将构造好的调用门放到这个位置,然后查看修改后的结果
kd> eq 80b95048 0040EC00`00081040
kd> dq gdtr
80b95000 00000000`00000000 00cf9b00`0000ffff
80b95010 00cf9300`0000ffff 00cffb00`0000ffff
80b95020 00cff300`0000ffff 80008b1e`400020ab
80b95030 834093f7`1c003748 0040f300`00000fff
80b95040 0000f200`0400ffff 0040ec00`00081040
80b95050 830089f6`f0000068 830089f6`f0680068
80b95060 00000000`00000000 00000000`00000000
80b95070 800092b9`500003ff 00000000`00000000
执行流程
接下来捋一遍整个调用门的执行流程
char buff[6];*(DWORD*)&buff[0] = 0x12345678; //废弃的EIP*(WORD*)&buff[4] = 0x48; //段选择子 __asm{
call fword ptr[buff];}
当代码执行到call fword ptr[buff];
时,其实就相当于执行下面这句
call 0x48:0x12345678
首先拆分0x48这个段选择子
?01001000?
index:9
TI:0
PRL:0
接着查IDT表的第十项 也就是我们构造的调用门。
进行段权限检查,检查通过,切换CS段寄存器提升权限,并跳转到段的Base+Offset的位置。
中断现场
将程序编译后放到虚拟机运行,此时windbg第一次产生中断,这个时候中断在用户层
kd> g
Break instruction exception - code 80000003 (first chance)
001b:00401056 cc int 3
查看一下用户层的寄存器环境
kd> r
eax=00203340 ebx=7ffd9000 ecx=3d9c2800 edx=00000002 esi=74c62108 edi=002040b0
eip=00401056 esp=0012ff38 ebp=0012ff40 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
001b:00401056 cc int 3
- EIP=00401056
- esp=0012ff38
- cs=001b
- ss=0023
接着再次运行程序,此时windbg第二次产生中断,这个时候中断于内核层
kd> g
Break instruction exception - code 80000003 (first chance)
00401040 cc int 3
再次查看当前的寄存器环境
kd> r
eax=00000048 ebx=7ffd9000 ecx=74c19a18 edx=74c610a4 esi=74c62108 edi=002040b0
eip=00401040 esp=a74ffca0 ebp=0012ff40 iopl=0 nv up ei pl nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202
00401040 cc int 3
- eip=00401040 ->我们指定的偏移
- cs=0008->我们指定的零环的段选择子
- ss=0010 ->零环的ss段寄存器
- esp=a74ffca0 ->零环的堆栈
接着再查看一下当前的ESP
kd> dd esp
a74ffca0 0040107c 0000001b 0012ff38 00000023
a74ffcb0 00000000 00000000 00000000 00000000
a74ffcc0 0000027f 00000000 00000000 00000000
a74ffcd0 00000000 00000000 00001f80 0000ffff
a74ffce0 00000000 00000000 00000000 00000000
a74ffcf0 00000000 00000000 00000000 00000000
a74ffd00 00000000 00000000 00000000 00000000
a74ffd10 00000000 00000000 00000000 00000000
- 0040107:三环的返回地址
- 0000001b:三环段选择子
- 0012ff38:三环的ESP
- 00000023:三环的SS段寄存器
有参调用门
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>void __declspec(naked)GetRegister()
{__asm{int 3;retf;}
}int main()
{__asm{int 3;}printf("%p", GetRegister);//构造call cs eip指令char buff[6];*(DWORD*)&buff[0] = 0x12345678; //废弃的EIP*(WORD*)&buff[4] = 0x48; //段选择子 __asm{//有参数的时候 参数需要自己指定push 1;push 2;push 3;call fword ptr[buff];}getchar();return 0;
}
构造调用门
offset in segment 31:16:0040
P:1 DPL:11 S:0--->E
Type:1100--->C
Param Count:3
Segment Select:0008
offset in Segment 15:00:1040
#调用门描述符
0040EC03`00081040
Param Count参数个数修改为3 其他不变
修改GDT表
kd> eq 80b95048 0040EC03`00081040
kd> dq gdtr
80b95000 00000000`00000000 00cf9b00`0000ffff
80b95010 00cf9300`0000ffff 00cffb00`0000ffff
80b95020 00cff300`0000ffff 80008b1e`400020ab
80b95030 834093f7`1c003748 7f40f3fd`f0000fff
80b95040 0000f200`0400ffff 0040ec03`00081040
80b95050 830089f6`f0000068 830089f6`f0680068
80b95060 00000000`00000000 00000000`00000000
80b95070 800092b9`500003ff 00000000`00000000
中断现场
编译后在虚拟机中运行,此时windbg第一次中断,这个时候中断在用户层,查看一下当前的寄存器环境
kd> g
Break instruction exception - code 80000003 (first chance)
001b:00401056 cc int 3
kd> r
eax=00203340 ebx=7ffda000 ecx=8966fe00 edx=00000002 esi=74c62108 edi=002040b0
eip=00401056 esp=0012ff38 ebp=0012ff40 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
001b:00401056 cc int 3
- eip=00401056
- esp=0012ff38
- cs=001b
- ss=0023
接着再次运行,程序第二次中断,此时中断在内核层,并查看当前的寄存器环境
kd> r
eax=00000048 ebx=7ffda000 ecx=74c19a18 edx=74c610a4 esi=74c62108 edi=002040b0
eip=00401040 esp=8d303c94 ebp=0012ff40 iopl=0 nv up ei pl nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202
00401040 cc int 3
- eip=00401040–>我们指定的Offset
- esp=8d303c94–>零环的堆栈
- cs=0008–>我们指定的零环的段选择子
- ss=0010–>零环的SS段寄存器
接着再查看一下当前的堆栈
kd> dd esp
8d303c94 00401082 0000001b 00000003 00000002
8d303ca4 00000001 0012ff2c 00000023 00000000
8d303cb4 00000000 00000000 00000000 0000027f
8d303cc4 00000000 00000000 00000000 00000000
8d303cd4 00000000 00001f80 0000ffff 00000000
8d303ce4 00000000 00000000 00000000 00000000
8d303cf4 00000000 00000000 00000000 00000000
8d303d04 00000000 00000000 00000000 00000000
- 00401082为三环的返回地址
- 0000001b为三环的CS段选择子
- 00000003 00000002 00000001为我们传递的三个参数
- 0012ff2c为三环的ESP
- 00000023为三环的SS段寄存器
总结
- 当通过调用门,权限提升到零环时,会Push四个值:返回地址 CS ESP SS
- 新的CS值由调用门决定
- 新的SS和ESP由TSS提供