6.调用门

1、调用门执行流程指令格式:
CALL CS:EIP(EIP是废弃的)cs:真正执行的代码下面解释
执行步骤:.
1)根据CS的值查GDT表,找到对应的段描述符,这个描述符是一个调用门
2)在调用门描述符中存储另一个代码段段的选择子
3)选择子指向的段 ,段.Base +偏移地址就是真正要执行的地址.
6.调用门
当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();
}

6.调用门

windbg修改如下
6.调用门

执行后堆栈变化
6.调用门

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个参数

自己构建门
6.调用门

测试代码

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为第一个参数

成功读取到参数
6.调用门