保护模式笔记九 中断门和IDT(中断描述符表)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

保护模式笔记九 中断门和IDT(中断描述符表)

https://www.52pojie.cn/thread-1455684-1-1.html
(出处: 吾爱破解论坛)

前言

所有保护模式索引链接:保护模式笔记一 保护模式介绍

前面学习了调用门之后继续学习中断门

中断门

中断门的作用
先前学习的调用门在实际的Windows中并没有被使用,只是操作系统提供了调用门描述符给开发人员使用。相比之下,Windows使用了中断门,用于:

系统调用(老的CPU通过中断门进入RING(内核)0层;新的CPU使用快速调用)
调试(常见的INT3 对应硬编码为0xCC)

中断门执行流程

根据INT XXX的值 查IDT(中断描述符表),找到对应的段描述符 这个描述符是一个中断门描述符
在中断门描述符中存储另一个代码段的选择子
选择子指向的段 段.Base + 偏移地址 就是真正要执行的地址

IDT

IDT全称Interrupt Descriptor Table(中断描述符表),和GDT相似,IDT也是由一系列描述符组成的。

IDT中存储的段描述符都是系统段描述符
IDT中的第一个元素不是NULL(不为空)
IDT可以包含三种门描述符:①任务门描述符;②中断门描述符;③陷阱门描述符
使用windbg查看IDT的地址和长度:

查看地址:

复制代码 隐藏代码

r idtr

查看长度:

复制代码 隐藏代码

r idtl

在这里插入图片描述

中断门描述符

对比调用门描述符
在这里插入图片描述

中断门描述符结构
在这里插入图片描述

当一个段描述符是一个调用门描述符时,有以下特征:

S位为0,表示该段描述符为系统段描述符(中断门描述符属于系统段描述符)
Type域为1110,表示该段描述符为32位中断门
低16位到31位存储一个段选择子,该段选择子才和代码真正要调用的地址相关
真正要调用的地址 = 段选择子所指向的段.Base + 32位的段中偏移 (段中偏移分为两部分:高位31-16位和低位15-0位)
段.Base默认为0,故真正要调用的地址 = 32位的段中偏移
给出调用门描述符和中断门描述符各部分的对比(上半部分为调用门描述符,下半部分为中断门描述符):
在这里插入图片描述

可以发现中断门描述符和调用门描述符的结构基本一致,只在Type域和参数计数处不同(Type域是描述符的类型标识;中断门不允许传参)

构造中断门描述符
了解了中断门描述符的结构后,尝试自己构造一个无参的中断门描述符,如下:

在这里插入图片描述

得到调用门描述符为:0000EE00`00080000

段中偏移暂时不明确要调用的代码段,先置0

示例代码

接下来给出一段演示代码:

复制代码 隐藏代码

#include <Windows.h>
#include <stdio.h>
int value;__declspec(naked) void INTGate(){_asm{pushadpushfd        mov value,0x610popfdpopadiretd}}int main(){//使用 中断门_asm{int 0x20}printf("%X\n",value);return 0;
}

代码说明

代码十分简单,主要分为两部分:

INTGate:中断门真正要调用的函数,给全局变量赋值,之后中断返回
main:通过中断进入中断门,最后输出全局变量观察是否通过中断门被修改

将门描述符写入IDT

中断索引和IDT地址的对应关系
在代码中,索引的值为0x20,其对应的IDT中的地址为:8003f500

关于索引值和IDT地址的对应关系为:

IDT地址 = 索引值 × 8 + IDT首地址

代入当前的值即为:IDT地址 = 0x20 × 8 + 0x8003f400 = 0x100 + 0x8003f400 = 0x8003f500

确定门描述符
在写入GDT前,还需要确定要写入的值,前面已经构造好了的门描述符为:0x0000EE00`00080000

但其段中偏移还未确定,于是使用VC++ 6.0查看要调用的代码的地址:

进入debug模式,中断后,选中INTGate函数,然后右键→Go to Disassembly(查看反汇编)
在这里插入图片描述
在这里插入图片描述

可以得到要调用的函数的地址为0x00401020

将得到的要调用的函数地址填入门描述符中对应的offset得到:

原:0000EE00`00080000

现:0040EE00`00081020

于是得到确定的门描述符为0040EE00`00081020

确定中断索引并写入门描述符
确定中断索引其实就是确定要写入中断描述符的地址,根据前面中断索引和IDT地址的对应关系,不难倒推出:

中断索引 = (要写入中断描述符的地址 - IDT首地址)÷ 8

因此问题又转换为了确定要写入的中断描述符地址

流程如下图所示:

在这里插入图片描述

用到的指令如下:

1.查看IDT首地址:

复制代码 隐藏代码

r idtr

2.使用指令查看IDT内容:

复制代码 隐藏代码

dq 8003f400 L30

这里的L30代表要查看的长度为 0x30 个qword长度的数据,即0x30个段描述符

3.找到要写入的地址后,将构造好的中断门描述符写入:

复制代码 隐藏代码

eq 8003f500 0040EE00`00081020

同时在确定了要写入的地址后,就可以根据计算出中断索引:

中断索引 = (要写入中断描述符的地址 - IDT首地址)÷ 8 = (8003f500 - 8003f400) ÷ 8 = 0x100 ÷ 8 = 0x20

4.最后再查看写入的地址,确保已正确写入:

dq 8003f500

执行代码
执行结果如下:

在这里插入图片描述

全局变量能够被修改,说明中断门能够正常执行

对比执行前后寄存器和堆栈

执行前寄存器情况
在使用中断门语句处下断点,断下后得到:

在这里插入图片描述

得到此时的寄存器情况:

寄存器 说明 值
在这里插入图片描述

有关段寄存器的详解可回顾:保护模式笔记二 段寄存器

关于标志寄存器的详解可回顾:逆向基础笔记五 标志寄存器

这里简单拆解一下标志寄存器:

先将值转换为二进制得到 0x202→ 0000 0000 0000 0000 0000 0010 0000 0010

按对应的结构填入得到:

在这里插入图片描述

此时IF标志位为1表示当前CPU允许响应INTR可屏蔽中断请求
若IF标志位为0则表示CPU不会响应可屏蔽中断请求
执行前堆栈情况
记录下此时的堆栈情况:

在这里插入图片描述

执行后寄存器情况
为了查看执行后寄存器的情况,在INTGate函数中加入了INT 3引发软中断,但在中断门调用的代码中再引发软中断会引发错误,这里仅作演示观察使用。修改后的INTGate函数如下:

 __declspec(naked) void INTGate(){_asm{int 3                                        //中断pushadpushfd        mov value,0x610popfdpopadiretd}}

之后INT3中断后查看寄存器情况如下:

在这里插入图片描述

得到此时的寄存器情况:

在这里插入图片描述

执行后堆栈情况
通过内存窗口观察此时的堆栈情况:

在这里插入图片描述

得到此时的堆栈情况:

在这里插入图片描述

对比执行前后寄存器
执行前后寄存器情况如下:
在这里插入图片描述

主要关注到执行前后标志寄存器的变化:

将执行后的EFL按对应的结构拆解得到:

在这里插入图片描述

对比发现,中断门调用后将标志寄存器的IF标志位置为0,表明当前正在处理中断请求,不再响应其它可屏蔽中断

对比执行前后堆栈
执行前后堆栈情况如下:

在这里插入图片描述

不难发现中断门执行后,向堆栈中压入了5个值:SS、ESP、EFL、CS、返回地址

IRETD指令

为了研究IRETD指令干了什么,观察IRETD执行前后堆栈和寄存器的变化情况

IRETD执行前
在这里插入图片描述

通过内存窗口观察执行前的堆栈情况:

在这里插入图片描述

得到此时的堆栈情况:

在这里插入图片描述

再观察此时的寄存器情况:

在这里插入图片描述

在这里插入图片描述

IRETD执行后
通过内存窗口观察执行后的堆栈情况:

在这里插入图片描述

在这里插入图片描述

查看寄存器情况:

在这里插入图片描述

在这里插入图片描述

IRETD执行前后对比
堆栈对比
在这里插入图片描述

寄存器对比
在这里插入图片描述

IRETD返回的时候比RETF多了一个EFL的恢复,关于RETF的内容可回顾:保护模式笔记八 调用门提权(无参+有参)

中断门使用RETF返回

了解了IRETD的原理后,就可以尝试使用RETF来返回

示例代码
示例代码如下:

 __declspec(naked) void INTGate(){_asm{pushadpushfd        //中断门会修改eflags的IF位为0  所以需要保存标志寄存器mov eax,[esp+0x24]   //retmov ebx,[esp+0x28]   //cs//中间少了个esp+0x2c 为EFLmov ecx,[esp+0x30]        //espmov edx,[esp+0x34]        //ssmov [esp+0x24+4],eaxmov [esp+0x28+4],ebxmov [esp+0x2c+4],ecxmov [esp+0x30+4],edxmov value,0x610popfdpopadadd esp,4retf}}

执行结果
在这里插入图片描述

依旧可以正常返回,并且执行正常

代码说明
代码也比较简短简单,可以分为七个部分:

保护现场:pushad、pushfd
将堆栈中的数据取出存到寄存器
将取出来的数据覆盖到堆栈中
全局变量赋值
恢复现场:popfd、popad
堆栈平衡:add esp,4
返回:retf
要理解堆栈数据的覆盖和平衡首先要了解IRETD和RETF的区别

IRETD 中断返回需要堆栈中按顺序存储:返回地址、CS、EFL、ESP、SS 共5个数据

RETF返回需要堆栈中按顺序存储:返回地址、CS、ESP、SS 共4个数据

因此将堆栈中的数据由原本的5个数据替换成4个数据即可

在这里插入图片描述

因此通过对堆栈中数据进行覆盖,即可实现在中断门中使用RETF返回

总结

中断门执行后会将EFL(标志位寄存器)中的IF标志位 置0,使CPU不再响应可屏蔽中断
执行中断门时,分为两种情况:
在没有权限切换时,只向堆栈中压入3个值:①CS;②EFL;③返回地址
在涉及权限切换时,会向堆栈中压入5个值:①SS;②ESP;③EFL;④CS;⑤返回地址
中断门不允许传递参数,调用门允许传递参数
中断门通过INT N(索引)执行,调用门通过远调用 CALL FAR CS:EIP执行
中断门一般使用IRET(16位)/IRETD(32位)返回,调用门一般使用RETF返回
Windows并没有使用调用门,但有使用中断门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/509175.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于条件风险价值的虚拟电厂参与能量及备用市场的双层随机优化》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 这篇文章的标题涉及到以下几个关键点…

SQL入门教程参考

参考 SQL视频教程 LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; SQL基础教程 SQL 教程 SQL 教程2 SQL教程 - 廖雪峰的官方网站 史上最全SQL基础知识总结(理论举例)-CSDN博客 数据库表基础操作 首先数据库表必掌握的基础操作&#xff0c;建表、删表、…

PyTorch-神经网络

神经网络&#xff0c;这也是深度学习的基石&#xff0c;所谓的深度学习&#xff0c;也可以理解为很深层的神经网络。说起这里&#xff0c;有一个小段子&#xff0c;神经网络曾经被打入了冷宫&#xff0c;因为SVM派的崛起&#xff0c;SVM不了解的同学可以去google一下&#xff0…

OpenCV 4基础篇| OpenCV图像的拆分和合并

目录 1. 通道拆分1.1 cv2.split1.1.1 语法结构1.1.2 注意事项1.1.3 代码示例 1.2 NumPy切片1.2.1 代码示例 2. 通道合并2.1 cv2.merge2.1.1 语法结构2.1.2 注意事项2.1.3 代码示例 1. 通道拆分 1.1 cv2.split 1.1.1 语法结构 b,g,r cv2.split(img[, mv]) #图像拆分为 BGR 通…

【Simulink系列】——控制系统仿真基础

声明&#xff1a;本系列博客参考有关专业书籍&#xff0c;截图均为自己实操&#xff0c;仅供交流学习&#xff01; 一、控制系统基本概念 这里就不再介绍类似于开环系统、闭环系统等基本概念了&#xff01; 1、数学模型 控制系统的数学模型是指动态数学模型&#xff0c;大致…

程序员的金三银四求职宝典:如何在关键时期脱颖而出?

个人主页&#xff1a;17_Kevin-CSDN博客 随着春天的脚步渐近&#xff0c;程序员们的求职热潮也随之而来。在这个被称为“金三银四”的招聘季&#xff0c;如何从众多求职者中脱颖而出&#xff0c;成为了许多程序员关注的焦点。本文将为你提供一份全面的求职宝典&#xff0c;助你…

【JMeter】 二次开发插件开发 Dubbo 接口测试插件浅析

概述 在一些企业中&#xff0c;各类业务系统非常丰富&#xff0c;相互之间或对外提供很多的服务或接口这些服务或接口中&#xff0c;有很多是需要强契约约束的&#xff0c;服务的提供方、服务的使用方必须遵守相同契约这类服务最典型的就是RPC&#xff0c;其中应用广泛的有Dub…

Vue3中Vuex状态管理库学习笔记

1.什么是状态管理 在开发中&#xff0c;我们会的应用程序需要处理各种各样的数据&#xff0c;这些数据需要保存在我们应用程序的某个位置&#xff0c;对于这些数据的管理我们就称之为状态管理。 在之前我们如何管理自己的状态呢&#xff1f; 在Vue开发中&#xff0c;我们使用…

Linux设备模型(十一) - platform设备

一&#xff0c;platform device概述 在Linux2.6以后的设备驱动模型中&#xff0c;需关心总线、设备和驱动这3个实体&#xff0c;总线将设备和驱动绑定。在系统每注册一个设备的时候&#xff0c; 会寻找与之匹配的驱动&#xff1b;相反的&#xff0c;在系统每注册一个设备的时…

浅显易懂:WinForms、WPF和Electron的区别和优缺点

在开发桌面应用的时候&#xff0c;WinForms、WPF和Electron是绕不过去的三个技术栈&#xff0c;本文就详细据介绍了三者的区别和优缺点&#xff0c;帮助老铁们做个抉择。 一、winform wpf Electron 三者区别 WinForms、WPF和Electron是三种不同的框架和技术&#xff0c;用于开…

alfred自定义脚本执行报错,alfred task launch path not accessible问题解决

alfred自定义脚本执行报错,alfred task launch path not accessible 原因是mac升级后 /usr/lib/php 已经不存在了,可以改由zsh方式执行,如下图 右击打开目录 将执行脚本放入目录 code如下: <?phprequire ./Util.php; $qs $argv; $query $qs[1]; date_default_timezon…

#QT(智能家居界面-布局)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 水平布局&#xff0c;垂直布局&#xff0c;栅格布局&#xff08;弹簧&#xff09; 界面自动调整 3.记录 注意弹簧不是拖拽拉长&#xff0c;而是使用栅格布局 运行发现窗口放大缩小可以自动调整 如果想要重新布局&#xff0c;需…