#include <iostream>
#include <Windows.h>
//全局描述符地址是6字节,高32位是起始地址,低16位是大小
char GDT[7] = { 0 };
void _declspec(naked)GetRegister()
{
_asm
{
//特权指令
sgdt GDT;
retf
}
}
int main()
{
printf("%08x\n", GetRegister);
//call CS:EIP (EIP弃用)
char buff[6] = {0};
//EIP弃用
*(DWORD*)&buff[0] = 0x12345678;
//CS段选择子:
//13位:段描述符[9] 1位:TI=0 2位:RPL=3
//1001011->0x4b
*(DWORD*)& buff[4] = 0x4b;
//保存跳转后要执行函数的地址
char szFunAddress[9] = { 0 };
sprintf_s(szFunAddress,9,"%08x", GetRegister);
//构建跳转门描述符:
//高32位:
//16位:偏移=0 1位:P=1 2位:DPL=3 1位0=0 4位:Type=12 3位0 5位:参数=0
//0000 0000 0000 0000 1110 1100 0000 0000
//0 0 0 0 E C 0 0
//低32位:
//--------------------------------------------------------------------------------------------------------
//跳转门执行的地址是:门描述符高32位中的16位偏移和低32位中的16位偏移合成一个(32位)4字节的地址偏移,
//加上低32位中的段选择子索引到的GDT表中的项(段描述符)的段基址,得到Call的地址。因此,要想控制Call的地址,
//就要把偏移修改成要执行的函数地址,把段选择子索引到一个段基址为0的字段,同时DPL=0,S=1,这时Call的函数就能
//提权操作,而GDT[1]项正好符合。
//--------------------------------------------------------------------------------------------------------
//16位段选择子->13位索引:0 1位TI=0 2位RPL=3; 16位偏移=0
//0000 0000 0000 1 0 00->0x0008 0x0000
//得到的是:0x0000 EC00 0008 0000
//修改: 地址前4位 地址后4位
char szCallDoor[18] = { 0 };
//写入地址前4位
memcpy_s(szCallDoor,18, szFunAddress,4);
//写入段属性
memcpy_s(szCallDoor+4, 14, "EC00 ", 5);
//写入段选择子
memcpy_s(szCallDoor + 9, 9, "0008", 4);
//写入地址后4位
memcpy_s(szCallDoor + 13, 5, szFunAddress+4, 4);
//打印
printf("复制这个值:[ %s ]到GDT[9]\n", szCallDoor);
system("pause");
_asm
{
call fword ptr ds :[buff]
}
printf("%s\n", GDT);
system("pause");
return 0;
}
不知道为啥,程序运行总是报错。拿到x64调试发现:调用门正常运行,访问到了GDT的地址和大小。
转载于:https://blog.51cto.com/14317856/2411263