系统段描述符表IDTR


系统段描述符表IDTR

中断门和陷阱门

不同描述符表中的值代表不同类型的门,放在gdtr表里面的门叫做调用门,放在idtr表里面的门叫做中断门和陷阱门

中断门和陷阱门描述中断/异常处理程序的入口点。中断门和陷阱门内的选择子必须指向代码段描述符,门内的偏移就是对应代码段的入口点偏移。中断门和陷阱门只有在描述符表IDT中才有效。

中断门结构

陷阱门结构

中断

对80386而言,中断是由异步的外部事件引起的,也就是cpu外部中断。在汇编中,可以用int指令进入中断门,int 0x1 代表调用IDTR指向的第一个门,依次类推,int 0x20 就是指向IDTR + 0x20 * 8地址的描述符。读取idt中的8个字节,就获取系统函数入口。

异常

异常时80386在执行指令期间检测到不正常的或非法的条件引起的,也就是cpu内部中断。当异常发生后,处理器就像响应中断那样处理异常。也就是根据中断向量号,跳转到IDT对应的地址。

故障

故障是在引起异常之前,把异常情况通知给系统的一种异常。故障往往是可修复的,在故障处理程序把故障排除后,执行IRET返回到故障程序继续执行,但不能保证继续执行的程序可以正确执行。

陷阱

陷阱是在引起异常指令后,把异常情况通知给系统的一种异常(如软中断指令、单步异常)。通常用于调试目的,如INT3和溢出检测指令INTO。在转入陷阱处理程序时,引起陷阱的指令应正常完成,他有可能改变了寄存器或储存单元。

终止

中止时在系统出现严重情况时,通知系统的一种异常。产生中止时正执行的程序不能被恢复执行。系统接受中止后处理程序要重新建立各种系统表格,并可能需要重新启动操作系统,也可能会蓝屏。

异常类型

中断和异常向量分配表

其中0x2的向量号为外部设备导致错误(cpu断电等)

在执行int 0x8双重错误时发生错误则变成三重错误,这时系统重启或卡死

任务段出错率较低,所有寄存器都换了一遍后,可以把寄存器恢复到出错之前

故障类异常

堆栈段故障

异常0CH

当处理器检测到用SS进行寻址的与段有关的某种问题时,就发生堆栈段故障。堆栈段故障提供一个出错码,格式如下:

段异常出错码格式

在出现如下三种情况将引起堆栈段故障:

1、偏移超出段界限所规定的范围,出错码为0。如PUSH时堆栈溢出

2、在又特权级变换所引起的对内层堆栈的操作时,偏移超出段界限对规定的范围,出错码包含又内层堆栈的选择子。

3、装入到SS寄存器的描述符中存在位为0,出错码包含又对应的选择子。

通用保护故障

异常0DH

​ 除了明确列出的段异常外,其他段异常均称为通用保护异常。在进入故障处理程序时,保存的CS和EIP指向发生故障的指令,或该故障作为任务切换的一部分发生时指向任务的第一条指令。通用保护故障通常分为两类:

1、违反保护方式,但程序无需中止的异常,出错码为0

2、外翻保护方式,导致程序中止异常,出错码不定

WinDBG测试

使用命令dq idtr l70在idt中找到一块空地址,计算一个描述符

此处选择0x8003f500地址,根据(当前地址-基址)/8可以算出中断偏移量为0x20

查找空的内存地址

根据下表进一步构造中断门这8字符的值,这里取0x60000000为基址,计算出来则为0x6000ee00`00080000

不同TYPE对应的意思

填入的字节

编写代码

#include "StdAfx.h"
#include <Windows.h>

WORD w_cs;
WORD w_ss;

BYTE GdtBuffer[0x4000];

DWORD GetFunAddress(void* Fun){
    BYTE* p;
    p = (BYTE*)Fun;
    if (*p == 0xe9){
        p = p+5+ *(DWORD*)&p[1];
    }
    return (DWORD)p;
}


_declspec(naked)void fun(){
    _asm {
        push ebp
        mov ebp,esp
        sub esp,0x44
        push ebx
        push esi
        push edi
    }

     _asm {
        mov ax,cs
        mov cx,ss
        mov w_cs,ax
        mov w_ss,cx
     }

    BYTE* pGdtAddress;
    int i;

    pGdtAddress = (BYTE*)0x8003f400;

    for (i = 0; i < 0x400; i++ ){
        GdtBuffer[i] = pGdtAddress[i];
    }

    _asm{
        pop edi
        pop esi
        pop ebx
        mov esp,ebp
        pop ebp
        iretd
    }
}

int main(int argc, char* argv[]){
    LPVOID pAddress;
    DWORD dwFunAddress;
    pAddress = VirtualAlloc((void*)0x60000000,0x4000, MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);

    if ( pAddress != NULL ){
        dwFunAddress = GetFunAddress(fun);
        memcpy(pAddress, (void*)dwFunAddress,0x200);
    }
    memset(GdtBuffer,0x0,0x4000);
    int i;

    _asm{
        int 0x20
    }
    printf("cs = %x  ss = %x\n", w_cs,w_ss);
    for ( i = 0; i < 0x100; i+= 2){
        printf(" 0x%08x`0x%08x\n", *(DWORD*)&GdtBuffer[i*4+4], *(DWORD*)&GdtBuffer[i*4]);
    }
    printf("Hello World!\n");
    return 0;
}

成功打印

打印IDT

IDT中不为空的地址代表系统函数的入口地址

取第一个地址的EIP u 0x805431a0,可以看到系统函数名和反汇编

IDT第一个地址

IDT第一个地址对应的函数

依次尝试接下来的几个,可以发现均为系统函数的入口

windbg查看汇编


文章作者: Kevin。
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kevin。 !
评论
 上一篇
TSS 任务状态段描述符 TSS 任务状态段描述符
TSS 任务状态段描述符​ TSS(Task State Segment)任务状态段描述符用于描述保存任务重要信息的系统段,权限发生变化要借用TSS。任务状态段寄存器TR的可见部分为当前任务状态段描述符的选择子,不可见部分是当前任务状
2022-04-15
下一篇 
利用门描述符从3环进入0环 利用门描述符从3环进入0环
利用门描述符从3环进入0环门描述符格式在开始前先了解一下门描述符的作用 门描述符不描述某种内存段,而是描述控制转移的入口点,简单来说就是中介,通过这道门,可实现任务内特权级的变换和任务间的切换,获取最后的访问地址。 Attributesm
2022-04-12
  目录