保护模式篇——中断与异常和控制寄存器
写在前面
此系列是本人一个字一个字码出来的,包括示例和实验截图。由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读 羽夏看Win系统内核——简述 ,方便学习本教程。
看此教程之前,问几个问题,基础知识储备好了吗?上一节教程学会了吗?上一节课的练习做了吗?没有的话就不要继续了。
🔒 华丽的分割线 🔒
练习及参考
本次答案均为参考,可以与我的答案不一致,但必须成功通过。
1️⃣ 在10-10-12
分页模式下体会TLB
的存在。要求:通过代码挂物理页,不能通过Windbg
挂。原物理页挂完写入值读取,然后把地址换物理页继续读取,看看值是否发生变化。然后用INVLPG
指令之后再看看值是否变化。
🔒 点击查看答案 🔒
此题目一看就需要一个调用门实现提权,如果有所忘却请翻看前面的教程。
首先构造一个调用门:eq 8003f098 0040EC0000081250
,注意调用门和裸函数的地址一致。然后运行代码,可以得到下面的结果:
刷新缓存
不刷新缓存
通过这个实验,看到TLB
的作用了吧?
🔒 点击查看代码 🔒
#include "stdafx.h"
#include <iostream>
#include <windows.h>
int isinv=0;
int num1=0;
int num2=0;
void __declspec(naked) callgate()
{
_asm
{
push 0x30;
pop fs;
pushad;
pushfd;
mov edi,0xC0000000;
mov eax,0x10000;
shr eax,10;
add eax,edi;
mov eax,dword ptr ds:[eax];
mov dword ptr ds:[edi],eax;
mov edx,dword ptr ds:[0];
mov [num1],edx;
mov eax,isinv ;
test eax,eax;
jz end;
invlpg dword ptr ds:[0];
end:
mov eax,0x20000;
shr eax,10;
add eax,edi;
mov eax,dword ptr ds:[eax];
mov dword ptr ds:[edi],eax;
mov edx,dword ptr ds:[0];
mov [num2],edx;
popfd;
popad;
retf;
}
}
int main(int argc, char* argv[])
{
LPVOID page1 = VirtualAlloc((LPVOID)0x10000,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
LPVOID page2 = VirtualAlloc((LPVOID)0x20000,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (!page1||!page2)
{
puts("分配内存失败!!!");
VirtualFree(page1,0,MEM_FREE);
VirtualFree(page2,0,MEM_FREE);
system("pause");
return 0;
}
*(int*)page1 = 0x12345;
*(int*)page2 = 0x67890;
puts("是否清理缓存?");
scanf("%d",&isinv);
const char buffer[6]={0,0,0,0,0x9B,0};
_asm
{
push fs;
call fword ptr [buffer];
pop fs;
}
printf("第一次挂页的值:%x\n换页后的值:%x\n",num1,num2);
VirtualFree(page1,0,MEM_FREE);
VirtualFree(page2,0,MEM_FREE);
system("pause");
return 0;
}
中断
中断通常是由CPU
外部的输入输出设备(硬件)所触发的,供外部设备通知CPU
有事情需要处理,因此又叫中断请求,英文为Interrupt Request
。中断请求的目的是希望CPU
暂时停止执行当前正在执行的程序,转去执行中断请求所对应的中断处理例程,中断处理程序由哪有IDT表决定。
80x86
有两条中断请求线:非屏蔽中断线,NMI
,全称NonMaskable Interrupt
和可屏蔽中断线,INTR
,全称Interrupt Require
。
不可屏蔽中断
什么是不可屏蔽中断
?CPU
的EFLAG
之中有一个位,它是IF
位。如果它被置0。如果有可屏蔽中断告诉CPU
有中断来了,你能先执行我的代码呢?可是IF
位是0,对不起,我听不见。左耳朵进,右耳朵出。反之,我会处理。常见的不可屏蔽中断有电脑长按关机、键盘输入等等。当非可屏蔽中断产生时,CPU在执行完当前指令后会里面进入中断处理程序,非可屏蔽中断不受那个位的影响,一旦发生,CPU
必须处理。为了方便观看,给个EFLAG
图解:
那么CPU
是如何处理我们的不可屏蔽中断呢?我们先来看如下表格:
(IDT表)中断号 | NMI | 说明 |
---|---|---|
0x2 | 不可屏蔽中断 | 80x86 中固定为 0x2 |
如果处理不可屏蔽中断,CPU
会调用2号中断。涉及的IDT
表和中断门的知识如果忘却请查看前面的教程。
可屏蔽中断
什么是可屏蔽中断
,我就不赘述了。在硬件级,可屏蔽中断是由一块专门的芯片来管理的,通常称为中断控制器。它负责分配中断资源和管理各个中断源发出的中断请求.为了便于标识各个中断请求,中断管理器通常用IRQ
,全称为Interrupt Request
,后面加上数字来表示不同的中断。
在Windows
中,怎么查看某个可屏蔽中断的IRQ
。可以在计算机管理中查看。我以键盘的输入的IRQ
为例,如下图所示,可以看到它的IRQ
为0x1
。
那么CPU
是如何处理我们的可屏蔽中断呢?我们先来看如下表格:
(IDT表)中断号 | IRQ | 说明 |
---|---|---|
0x30 | IRQ0 | 时钟中断 |
0x31-0x3F | IRQ1-IRQ15 | 其他硬件设备的中断 |
如果自己的程序执行时不希望CPU去处理这些中断,可以用CLI
指令清空EFLAG
寄存器中的IF
位,用STI
指令设置EFLAG
寄存器中的IF
位。
硬件中断与IDT
表中的对应关系并非固定不变的,可以参考白皮书的Chapter 10 Advanced Programmable Interrupt Controller(APIC)
进行了解。
异常
异常通常是CPU
在执行指令时检测到的某些错误,比如除0、访问无效页等。中断与异常之间有一些相似之处,但它们是不一样的:中断来自于外部设备,是中断源(比如键盘)发起的,CPU
是被动的;而异常来自于CPU
本身,是CPU
主动产生的。INT N
虽然被称为“软件中断”,但其本质是异常,EFLAG
的IF
位对INT N
是无效。
异常处理
无论是由硬件设备触发的中断请求还是由CPU
产生的异常,处理程序都在IDT
表。常见的异常处理程序如下表所示:
错误类型 | (IDT表)中断号 |
---|---|
页错误 | 0xE |
段错误 | 0xD |
除零错误 | 0x0 |
双重错误 | 0x8 |
有些异常比较特别,我们在来略微讲解一下:
缺页异常
缺页异常当PDE/PTE的P=0
时或当PDE/PTE
的属性为只读但程序试图写入的时就会触发。一旦发生缺页异常,CPU
会执行IDT
表中的0xE
中断处理程序,由操作系统来接管。
你或许不清楚操作系统来接管。一个程序要是使用内存,必须有一个物理页。但物理页被挂上之后,这个物理页也不一定是永久属于你的。如果不经常用,操作系统看到后,就操作PDE/PTE
的P位为0,把它放到称之为虚拟内存交换文件之中。毕竟内存宝贵,不能养“闲人”嘛。当这个程序过了好长时间又想要它了,结果发现PDE/PTE
不合法,触发缺页异常。然后操作系统过来,通过查看PDE/PTE
看看是不是我自己裁的员(如下图所示),如果是的话我再招一个物理页,然后把数据写进入,然后重新挂上,然后告诉CPU
我处理妥善,继续干活,然后程序就像没啥事情一样正常使用。可以说,缺页异常无时无刻发生着。
那么我们如何查看虚拟内存交换文件呢?如何设置它的大小呢?看下面的示意图就知道了。
文件位置
大小设置
控制寄存器
控制寄存器用于控制和确定CPU的操作模式。控制寄存器有Cr0
、Cr1
、Cr2
、Cr3
、Cr4
。Cr1
被保留了,Cr3
用于页目录表基址,其他的将继续详细讲解。
Cr0
Cr0
是一个十分重要的寄存器,可以说它是总开关的集合体。如下图所示:
PE
位是启用保护模式(Protection Enable)标志。若PE = 1
是开启保护模式,反之为实地址模式。这个标志仅开启段级保护,而并没有启用分页机制。若要启用分页机制,那么PE
和PG
标志都要置位。
PG
位是启用分页机制。在开启这个标志之前必须已经或者同时开启PE
标志。PG = 0
且PE = 0
,处理器工作在实地址模式下。PG = 0
且PE = 1
,处理器工作在没有开启分页机制的保护模式下。PG = 1
且PE = 0
,在PE
没有开启的情况下无法开启PG
。PG = 1
且PE = 1
,处理器工作在开启了分页机制的保护模式下。
WP
位对于Intel 80486
或以上的CPU
,是写保护(Write Proctect)标志。当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向用户级只读页面执行写操作;当CPL < 3
的时候,如果WP = 0
可以读写任意用户级物理页,只要线性地址有效。如果WP = 1
可以读取任意用户级物理页,但对于只读的物理页,则不能写。
Cr2
当CPU访问某个无效页面时,会产生缺页异常,此时,CPU会将引起异常的线性地址存放在CR2中,如下图所示:
Cr4
Cr4
的结构如下图所示:
VME
用于虚拟8086模式。PAE
用于确认是哪个分页,PAE = 1
,是2-9-9-12
分页,PAE = 0
是10-10-12
分页。PSE
是大页是否开启的总开关,如果置0,就算PDE
中设置了大页你也得是普通的页。
小节
有些结构的位我并没有详细介绍,详情请查看白皮书的控制寄存器的篇章,如下图所示:
练习
本节的答案将会在下一节进行讲解,务必把本节练习做完后看下一个讲解内容。不要偷懒,实验是学习本教程的捷径。
俗话说得好,光说不练假把式,如下是本节相关的练习。如果练习没做好,就不要看下一节教程了,越到后面,不做练习的话容易夹生了,开始还明白,后来就真的一点都不明白了。本节练习不多,请保质保量的完成。
1️⃣ 分析IDT
表中0x2
号中断的执行流程。
2️⃣ 分析IDT
表中0x8
号中断的执行流程。
下一篇
本文来自博客园,作者:寂静的羽夏 ,一个热爱计算机技术的菜鸟
转载请注明原文链接:https://www.cnblogs.com/wingsummer/p/15364650.html