OS修炼指南之保护模式
文章平均质量分 91
一套完整的保护模式学习笔记,包括段页、中断、异常等知识,理论与实践并行。需要有一定的汇编语言基础才能看懂。
--Allen--
我知道我不知道。
展开
-
操作系统修炼指南——保护模式
环境搭建000 实验环境搭建保护模式001 保护模式 002 段寄存器 003 段选择子与段描述符结构 004 段描述符属性分析 005 特权级 006 数据段权限检查 007 代码段权限检查与 jmp 008 跨段提权与调用门 009 调用门(无参) 010 调用门(有参) 011 中断门 012 陷阱门 013原创 2016-09-14 15:45:01 · 10646 阅读 · 12 评论 -
9-调用门(无参)
编写 r0 函数 getData查看函数 getData 地址构造调用门描述符运行结果编写 r0 函数 getData该函数将运行在ring 0下,因为其中读取了高2G内存数据。在 main 函数执行长调用,注意VC6.0 不能直接写 call 0x48:0,编译不通过#include <windows.h>#include <stdio.h>WORD g_cs0, g_ss0, g原创 2016-09-14 14:34:50 · 3730 阅读 · 10 评论 -
2-段寄存器
从 ds 说起段寄存器段寄存器有96位段寄存器数据来源从 ds 说起如果你稍稍懂一点汇编,当你执行下面这行代码的时候,它会把 32 位整数 5 写入到地址 0x0012f000 这个位置处。dword 就表示这是一个 double word 宽度的数,一个 word 是 16 bit.mov dword ptr ds:[0x0012f000], 5不要惊讶,不要因为不懂汇编而苦恼,接触多了,就原创 2016-09-14 14:50:05 · 6942 阅读 · 20 评论 -
3-段选择子与段描述符结构
段描述符与段选择子的结构段选择子结构段选择子一共有16位,结构如下:| 1 | 0 | 字节|7654321076543 2 10| 比特|-------------|-|--| 占位| INDEX |T|R | 含义| |I|P || | |L |INDEX:在GDT数组或LDT数组的索引号TI原创 2016-09-14 15:02:04 · 21183 阅读 · 6 评论 -
4-段描述符属性分析
段描述符结构| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 字节|76543210|7 6 5 4 3210 |7 65 4 3210|76543210|76543210|76543210|76543210|76543210| 比特|--------|-|-|-|-|----原创 2016-09-14 15:28:15 · 4139 阅读 · 9 评论 -
6-数据段权限检查
不妨先来做个实验。打开 OD,双击第一行,把代码改成 mov ax, 0x20; mov ds, ax,然后按两下 F8 键(单步),发现很正常。如果你把代码改成 mov ax, 0x10; mov ds, ax,按两下 F8 后,代码跳转到了一个地址以 7 开头的地方去了。 图1 这两行可以正常执行 图2 第二行不能正常执行 图3 图2中的代码执行异常会跳到这里 为了搞原创 2016-09-14 15:33:07 · 2507 阅读 · 4 评论 -
7- 代码段权限检查与 jmp
实现跨段:一致代码段(比当前权限高的)要求:CPL >= DPL 步骤:1. 在8003f048 处添加描述符 00cf9f00`0000ffff,该描述符描述的段为一致代码段,DPL = 0 命令 eq 8003f048 00cf9f00`0000ffff2. 打开 OD,修改当前指令为 jmp 48:0044420c3. 执行指令后跳转到了 0044420c 处,且 cs 变为原创 2016-09-14 15:39:47 · 3533 阅读 · 9 评论 -
10-调用门(有参)实验
编写R0函数int g_a, g_b, g_c;__declspec(naked) void getParam(int a, int b, int c) { __asm { // int 3 // 取消注释可以在WinDbg中看R0栈数据 pushad // 0x20 B pushfd // 0x04 B //原创 2016-09-14 23:10:29 · 2554 阅读 · 3 评论 -
11-中断门
除了使用调用门进行提权,本篇的中断门显的更加重要。因为在 Windows 中,大量使用了中断门。中断门的结构| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 字节|76543210|76543210|7 65 4 3210|76543210|76543210|76543210|76543210原创 2016-09-24 11:55:14 · 5596 阅读 · 4 评论 -
12-陷阱门
陷阱门的结构| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 字节|76543210|76543210|7 65 4 3210|76543210|76543210|76543210|76543210|76543210| 比特|-----------------|1|--|0|1111|--原创 2016-09-24 13:08:51 · 2202 阅读 · 4 评论 -
13-任务状态段(TSS)
任务状态段不要被名字所吓倒,它不过是一块位于内存中的结构体而已。有一点需要注意的是,不要把它和任务切换关联起来(切记),否则你会被搞晕,它只是位于内存中的一段数据。Intel 白皮书给出TSS在内存中的图是这样的,它保存了一些重要的值。 抽象成结构体就是下面这个样子。struct TSS { DWORD link, // 保存前一个 TSS 段选择子,使用 call 指令切换寄原创 2016-09-24 15:22:14 · 17963 阅读 · 7 评论 -
14-TSS切换实验
概述前面讲述了TSS有两个功能,提权的时候切换栈,需要用到TSS,另外执行 call/jmp 访问TSS段的时候,可以切换一堆寄存器。本节主要进行一个实验,来模拟第二个功能。实验思路编写测试入口函数构造TSS设计TSS段描述符并安装编写测试入口函数CPU利用 TSS 切换一堆寄存器后,转而就去执行 eip 所指向的指令,为了能够让CPU执行自己的代码,我们需要编写一个测试函数,把这个函数的地原创 2016-09-24 16:40:14 · 4521 阅读 · 18 评论 -
15-任务门
任务门上一节已经基本掌握了使用 call/jmp 去访问一个任务段,来达到切换一堆寄存器的目的。但是,CPU同时又提供了另一种方法让我们访问任务段——任务门。而任务门是安装在 IDT 表中的。之前学中断门的时候,就简单介绍了IDT表中可以安装中断门、陷阱门,还有一个当时只是稍微提了一下,那就是任务门。说白了就是想表达,IDT 表中只可以安装 3 种门:中断门、陷阱门和任务门。思考一下,既然都可以使用原创 2016-09-24 22:44:22 · 3800 阅读 · 6 评论 -
16-任务门实验
在第11篇《TSS切换实验》中,我们已经完成了使用 call 模拟了 TSS 的第二个功能——替换一堆寄存器。上一篇中,提到了任务门同样可以完成这个功能。本节主要通过设计任务门描述符以及INT指令来完成TSS的第二个功能。思路编写测试入口函数,把它的函数入口地址填写到 TSS 段中构造 TSS 段设计 TSS 段描述符,安装到 GDT 表设计任务门,安装到 IDT 表编写主函数,使用 IN原创 2016-09-25 14:31:29 · 2022 阅读 · 1 评论 -
17-分页
概述苦苦挣扎几近半月,保护模式中的段的篇章基本结束。迈过这个坑,踏过这个坎,前方还有千千万万个坑。只要坚持,一定可以走完。本篇开始进入新的篇章——页。不得不说,页在现代操作系统中起着无法动遥的地位,是实现现代操作系统的重要基础(当然,段也很重要)。你完全可以不用理解这句话,因为到目前为止,我们并没有进入操作系统正题。逻辑地址、线性地址与物理地址咳咳咳…一下子冒出这么多概念真的好吗?忍耐,我从简说。原创 2016-09-27 12:20:04 · 3129 阅读 · 6 评论 -
18-线性地址转换实验
概述上一篇介绍了有关页的概念,以及线性地址转换物理地址过程。受于篇幅限制,抱歉我把实验部分放在了这里。如果你觉得上一篇看完还是晕晕的,那这里的实验希望你能好好做一下。实验内容很简单,用 malloc 申请一段内存,然后往这段内存写点数据,顺便查看下申请的这段内存的地址是多少,接着,中断到 WinDbg 中,使用线性地址转换方法,找到这个线性地址对应的物理地址,并验证这段物理地址中保存的数据就是你在程原创 2016-09-27 23:02:56 · 2234 阅读 · 1 评论 -
0-实验环境搭建
工具下载安装 WinDbg安装VM在VM里安装XPXP 上的配置VM 上的配置WinDbg 配置测试工欲善其事,必先利其器。开篇要做的,当然是实验环境的搭建。工具下载https://yunpan.cn/ckI5hiW739Ipy 访问密码 8558安装 WinDbg此处省略 512 字节……安装VM此处省略 1024 字节……在VM里安装XP此处省略 65535 字节……XP 上的原创 2016-09-30 11:45:49 · 3099 阅读 · 3 评论 -
19-PDE-PTE
不知在第14篇《分页》文章里,你有没有搞懂什么是页,同时还延伸出了页表的概念。另外,还解释了逻辑地址、线性地址和物理地址之间的关系。我知道你脑子可能是一团浆糊,这只能怪我的语言表达能力还不够强。大段大段的文字让人读起来有时候很恼火,可是为了阐释问题,大段大段文字有时候又避免不了。所以,有时候不得不砍去细支末节,压缩篇幅。为了能够强化分页的知识,本篇扼要回顾前两篇内容,精简总结几个概念之间的关系。页、原创 2016-10-02 13:56:48 · 6949 阅读 · 3 评论 -
1-保护模式
保护模式操作系统这门课在本科是一块高地,很少有人能学懂,主要原因是本科的操作系统重在理论而无实践。然而,在国外的教学中,操作系统恰恰是一门工程性最强的学科。如果没有很强的实践,这门课也学不好。保护模式,是 x86 CPU 的一种运行模式。当然,除此之外,x86 架构的 CPU 还有实模式的工作状态和虚拟 8086模式。CPU 的工作模式是什么意思?举个例子,平时你在学校学习,比较散漫,开启的是懒散模原创 2016-10-03 10:07:58 · 3453 阅读 · 0 评论 -
5-特权级
CPU分级处于保护模式下的 CPU,有4种运行级别。 图1 CPU不同运行级别 围绕在最中心的那个圆心,叫 Ring 0,中文叫 0 环,这里运行特权级最高的代码。我在这里避免说这个级别运行操作系统内核,这是因为这是给设计操作系统的人看的。就目前来看,我不还不要和操作系统拉上关系,因为知识还不够。中间的 1 环和 2 环很少使用。最外层的 3 环,是运行级别最低的。怎样查看程序处于哪个运行级原创 2016-10-03 11:07:04 · 2219 阅读 · 3 评论 -
8-跨段提权与调用门
上一篇文章使用 jmp far 指令实现代码跨段,本质上就是改变 cs 段寄存器。但是我们发现,无论如何,jmp far 也无法更改 CPL。即使你的 RPL = 0,也是徒劳。有没有办法更改 cs 段寄存器,同时也更改 CPL?答案是肯定的。本篇提到了调用门只是其中的一种方法,还有其它方法,后文会陆续介绍。1. 在 3 环能读取高 2G 内存吗?回答这个问题最笨的方法就是做一个实...原创 2016-10-03 12:13:23 · 3191 阅读 · 6 评论 -
20-读写空指针
有不少人看到这个标题会说,博主疯了,走吧走吧,不看了。学过 C 语言的人都知道,0 地址是不可能被读写的。为了能够狡辩,我不得不提前把实验结果贴在下面。 图1 读写空指针 请原谅我,无论你在自己的 VC6.0 执行多少次,你都不会成功,但是我成功了。我确实做了手脚。难道你不想知道吗?聪明的你也许根本不需要继续往下读,就能完成这个功能(如果你真的搞定了前面的分页知识的话)。0 地址分析动手能力原创 2016-10-03 20:22:35 · 2220 阅读 · 5 评论 -
21-物理页属性-P-RW
熟练掌握了线性地址到物理地址的转换后,我们也知道PDE和PTE的结构。当时只知道PDE和PTE中保存了物理页的属性。PDE、PTE结构PDE 结构|<------ 31~12------>|<------ 11~0 --------->| 比特 |b a 9 8 7 6 5 4 3 2 1 0| |--------------------|-|-|-|原创 2016-10-03 21:28:16 · 2011 阅读 · 0 评论 -
22-物理页属性-U/S-PS-A-D
上一篇介绍了物理页的 P 属性和 RW 属性。本篇介绍 U/S、PS、A、D。PDE、PTE 结构PDE 结构|<------ 31~12------>|<------ 11~0 --------->| 比特 |b a 9 8 7 6 5 4 3 2 1 0| |--------------------|-|-|-|-|-|-|-|-|-|-|-|-|原创 2016-10-03 21:59:42 · 2407 阅读 · 3 评论 -
23-不提权读取高2G内存
我知道,就算我不写这篇文章,你也知道怎么做。可是,不管怎样,我还是得让这篇博客刷刷访问量。测试代码int main(int argc, char* argv[]){ int *p = (int*)0x8003f00c; getchar(); printf("%08x\n", *p); return 0;}实验修改 PDE、PTE上面的测试代码在 VC6.0 中编译原创 2016-10-03 22:42:37 · 1881 阅读 · 1 评论 -
24-PDT/PTT基址
概述在上一篇的总结中,我们有一个小小的愿望:把整个 4GB 线性地址的 U/S 位改成 1。我们要去 WinDbg 中手动一个一个的修改吗?显然不可能,给你一年时间你也未必改的完。既然如此,我们必然要能通过程序来修改 PDE 和 PTE 了。要知道,无论如何,程序中使用的都只能是线性地址。这可为难了,我们并不知道页目录基址。可别想着把 CR3 中保存的那个页目录基址拿来用,CR3 中保存的那可是物理原创 2016-10-04 16:55:36 · 3200 阅读 · 0 评论 -
25-PDT/PTT基址(实验与分析)
上一篇,我们分析了PDT的基址是 0xc0300000。这个地址拆分成三段式就是300-300-000. 用大白话说就是页目录表的第0x300号PDE指向的页表PTT768中的第0x300号PTE指向的物理页。 图1 PTT768 C0300000分析0xc0300000 拆成三段式300-300-000。所以我们可以在 WinDbg 中查找页目录表的第 0x300 号PDE指向的物理页到底原创 2016-10-04 17:53:09 · 3282 阅读 · 0 评论 -
26-PAE 分页
相信你已经对三段式分页掌握的非常熟练了。可是你有没有意识到,这种线性地址到物理地址的映射方式,存在着某种局限性?它能够映射的最大的物理地址,也只能是 0xffffffff. 原因在于,PTE 中的高20位保存的是页号,最大能保存的页号是 0xfffff,每个页占用 4KB,所以页号为 0xfffff 的物理页的物理偏移是 0xfffff000. 每次说保存的是页号,其实有点烦了。因为把 PDE原创 2016-10-19 10:18:11 · 3311 阅读 · 3 评论 -
27-PAE分页(实验)
在上一篇文末,我已经告诉了你如何把虚拟机中的 xp 系统配置成 PAE 分页模式。说不定,你已经自己完成了PAE的分页实验。可是为了照顾到有些做不出来的同学,我还是得把实验演示一遍。xp 系统改成 PAE 分页模式打开虚拟机中的 xp 系统,把 c:\boot.ini 文件打开,然后修改成图1的样子。注意只修改了一个地方,就是把以前的 /excute=option 改成了现在的 /noexecute原创 2016-10-20 10:32:04 · 2487 阅读 · 0 评论 -
28-PAE分页下的PDT-PTT基址
实际上,一路走来你也知道,在保护模式下你想通过写代码访问到物理地址简直天方夜谭。在 CPU 的世界里,无论是 PDT 还是 PTT 都保存在物理页中,PDT 和 PTT 中保存的也全部是物理地址不是线性地址。你要想访问到 PDT,除非你知道这个PDT所在的线性地址,这就是先有鸡还是先有蛋的问题了。倘若你搞懂了 10-10-12 分页模式下的 PDT-PTT 基址的话,想必本篇你也不在话下。有关 PD原创 2016-10-22 17:39:44 · 2231 阅读 · 2 评论 -
29-TLB
基本上到了这里,保护模式已接近尾声。不过,仍然有一些边角和细节需要你去掌握和理解。前面的文章里,尚有一些遗留的问题,比如页属性,并未介绍完,什么是 G 位,什么是 PWT,什么是 PCD?在解释这些东西之前,TLB(Translation Lookaside Buffer) 这个东西不讲,对不起这个博客,对不起阅读保护模式的读者。TLB 由来中译名为快表。经过前面大量的学习和实践,你已对 10-10原创 2016-10-23 21:52:21 · 1635 阅读 · 2 评论 -
30-TLB(实验)
还是老办法,实践出真知。上一篇已经介绍了 TLB 的有关概念。你已经知道,它无非就是位于 CPU 内部的一个数组,它保存了线性地址和物理地址的直接对应关系,以及页属性等信息。CPU 在做线性地址转换的时候,首先会去 TLB 中查找它对应的物理地址,如果找不到,才会根据 CR3 寄存器去查找页目录、页表。本篇的实验,主要是为了验证 TLB 本身的存在。为什么说是验证?因为 CPU 本身并未提供给我们访原创 2016-11-02 11:15:45 · 1679 阅读 · 5 评论 -
31-中断和异常
在经过了大量的学习和实践后,今天终于可以抛出这个沉重的话题了。不少操作系统相关的书籍喜欢很早就在书上给什么是中断,什么是异常下了一个让人抓狂的定义,可是这对初学者来讲真的不适合。1. 中断1.1 中断的概念看到这个标题,你肯定联想到之前我们学习过的中断门、中断描述表这些概念。如果把中断门玩溜了,肯定也知道int N这条汇编指令。不过我想告诉你的是,通过int N指令完成的中断,并不叫中断,相反,它属原创 2016-11-07 22:12:09 · 1578 阅读 · 1 评论