自由不同特权切换,需要用到几种方式-门描述符。

S为1时-代码段/数据段。

S为0时-系统段

| 门 | TYPE | 描述 |
| - | - | - |
| 调用门 | 12 | |
| 中断门 | 14 | 异常处理的函数地址,中断门执行IF位会清零,屏蔽可以屏蔽的中断,陷阱门不会 |
| 陷阱门 | 15 | 中断处理的函数地址 |
| 任务门 | 5 | |

196406-20191230101816343-1359964647.png

结构体

使用unsigned 避免因为符号位干扰到最高位。


typedef struct _CALLGATE 
{
    unsigned int offset1 : 16;                // 提权后执行代码的低地址
    unsigned int selector : 16;                // 需要提升的权限对应的选择子
    unsigned int paramcount : 5;                // 提权后执行的代码用到的参数
    unsigned int : 3;                    // 保留位
    unsigned int type : 4;                    // 对于调用门始终是 1100 
    unsigned int S : 1;                    // 对于调用门始终是 0
    unsigned int DPL : 2;                    // 访问我需要的权限,应该写 3
    unsigned int P : 1;                    // 必须是有效的段描述符
    unsigned int offset2 : 16;                // 提权后执行代码的高地址
} CALLGATE, *PCALLGATE;

手动解析系统段

在之前的表中找到

image.png

| 高4位 | | 基地址(31-24) | G(23) | D/B(22) | O(21) | AVL(20) | 段限长(19-16) | P(15) | DPL(14-13) | S(12) | TYPE(11-8) | 基地址(7-0) |
| - | - | - | - | - | - | - | - | - | - | - | - | - |
| 80008b1e | 1000
0000
0000
0000
1000
1011
0001
1110 | 1000
0000 | 0 | 0 | 0 | 0 | 0000 | 1 | 00 | 0 | 1011 | 00011110 |

调用门提升权限

配置属性

取消随机机制-方便测试调用

image.png

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct _CALLGATE
{
    unsigned int offset1 : 16;                // 提权后执行代码的低地址
    unsigned int selector : 16;                // 需要提升的权限对应的选择子
    unsigned int paramcount : 5;                // 提权后执行的代码用到的参数
    unsigned int : 3;                    // 保留位
    unsigned int type : 4;                    // 对于调用门始终是 1100 
    unsigned int S : 1;                    // 对于调用门始终是 0
    unsigned int DPL : 2;                    // 访问我需要的权限,应该写 3
    unsigned int P : 1;                    // 必须是有效的段描述符
    unsigned int offset2 : 16;                // 提权后执行代码的高地址
} CALLGATE, * PCALLGATE;


// 在进行权限切换的过程中,栈也会随之改变
short r0_ss = 0;
int r0_esp = 0;

// 裸函数,只生成用户编写的代码,在其中操作高地址空间
_declspec(naked) void r0_function()
{
    __asm
    {
        int 3
        mov r0_ss, ss        //; 获取 r0 权限的 ss
        mov r0_esp, esp        //; 获取 r0 权限的 esp
        retf            //; 调用门必须使用 retf 进行返回

                    //; 实现通过调用门读取到 gdt 中的第 3 项
                    //; sgdt 可以获取 gdt 的地址
                    //; 对于中断门和陷阱门必须使用 iretd
    }
}

int main()
{
    //1. 利用段描述符使 - 跳转到段描述符位置
    // 描述符表索引:13   TI:1    RPL:2    我们必须按照这个格式进行填充
    // 在图中第九位为 空借用  0 0000 0000 1001  0 11    11可以低权限调用   1001 = 9 
    //                            0000 0000 0100 1011
    //                            0x00        0x4B
    BYTE Dest[] = { 0x00,0x00,0x00,0x00,0x4B,0x00 };        //从小端开始  加载到内存 4B 00  2字节16位

    //2. 构建系统段描述符
    //Call 构造的地址  0045 3500  构造门
     //        0045EC00`00083500

    __asm push fs
    __asm call fword ptr Dest  
    __asm pop fs

    //输出
    printf("%04X:%08X\n", r0_ss, r0_esp);
    system("pause");
    r0_function();
    return 0;
}

image.png

在代码中找到位置

image.png

查看gdtr 看到第九项 - 全为0 更改一下为代码段地址 0045EC00`00083500

image.png

image.png

image.png

image.png

最后修改:2021 年 02 月 02 日 02 : 11 PM