#include#include //全局描述符地址是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的地址和大小。