6.调用门
1、调用门执行流程指令格式:
CALL CS:EIP(EIP是废弃的)cs:真正执行的代码下面解释
执行步骤:.
1)根据CS的值查GDT表,找到对应的段描述符,这个描述符是一个调用门
2)在调用门描述符中存储另一个代码段段的选择子
3)选择子指向的段 ,段.Base +偏移地址就是真正要执行的地址.
当s位为0的时候说明是系统描述符了, type域为1100这时后就是一个门描述符。
它的低16~31位才是代码真正要调用的代码存在哪个段中(Segment Selector)
低0~15位存着一段偏移,高16-31位也存着一段偏移(Offset in Segment),两段偏移组成一个32位地址
(Segment Selector).Base + (Offset in Segment)两段组成的一段偏移,才是这个指令真正要执行的位置
windows并没有使用调用门,做实验要自己构造调用门
高位:
0000(31~16)我们并不知道要跳到哪里先填0
E p位必须为1,DPL为11,s位为0
C TYPE 1100
00 5~7位默认0,0~4也0因为不需要传参
低位:
0008 真正选择子(Segment Selector)
0000 (Offset in Segment)
合成:0000EC00`00080000
测试代码:
void _declspec(naked) GetRegister()
{
//这里的代码执行位ring0权限
//int 3会中断到windbg
_asm
{
int 3
retf //注意返回不能是ret
}
}
int main()
{
//GetRegister();
char buff[6];
//长调用
*(DWORD*)&buff[0] = 0x12345678;
*(WORD*)&buff[4] = 0x48;//cs:
_asm
{
call fword ptr[buff]
}
getchar();
}
windbg修改如下
执行后堆栈变化
r3读取高2g内存
BYTE GDT[6] = {0};
DWORD dwH2GValue;
void _declspec(naked) GetRegister()
{
_asm
{
pushad
pushfd
mov eax,0x80b95048
mov ebx,[eax]
mov dwH2GValue,ebx
sgdt GDT
popfd
popad
retf //注意返回不能是ret
}
}
void Print()
{
DWORD gdt_addr = *(PDWORD)(&GDT[2]);
WORD gdt_limit = *(PWORD)(&GDT[0]);
printf("r0数据:%X gdt_addr:%X gdt_limit:%X", dwH2GValue, gdt_addr,gdt_limit );
}
int main()
{
_asm
{
mov ebx,ebx
mov ebx,ebx
}
char buff[6];
//长调用
*(DWORD*)&buff[0] = 0x12345678;
*(WORD*)&buff[4] = 0x48;//cs:
_asm
{
call fword ptr[buff]
}
Print();
getchar();
}
上面的都是无参数的,下面来看看有参的
只需要修改参数位
0000EC03`00080000
参数位为3说明要传入3个参数
自己构建门
测试代码
DWORD x;
DWORD y;
DWORD z;
void _declspec(naked) GetProc()
{
_asm
{
pushad
pushfd
//将参数读出来
mov eax, [esp + 0x24 + 0x8 + 0x8]
mov dword ptr ds : [x], eax
mov eax, [esp + 0x24 + 8 + 4]
mov dword ptr ds : [y], eax
mov eax, [esp + 0x24 + 8 + 0]
mov dword ptr ds:[z],eax
popfd
popad
retf 0xC //平衡堆栈,3个参数
}
}
void Print()
{
printf("%X %X %X", x, y, z);
}
int main()
{
char buff[6];
//长调用
*(DWORD*)&buff[0] = 0x12345678;
*(WORD*)&buff[4] = 0x48;//cs:
_asm
{
push 1
push 2
push 3
call fword ptr[buff]
}
Print();
getchar();
}
ESP+0x4到ESP+0x20为8个通用寄存器(pushad)
ESP+0x24为返回地址
ESP+0x24+0x4为调用者CS
ESP+0x24+0x8为第三个参数
ESP+0x24+0x8+0x4为第二个参数
ESP+0x24+0x8+0x8为第一个参数
成功读取到参数