Windows保护模式学习笔记(五)—— 任务段&任务门

  • 要点回顾
  • 任务段
    • TSS (Task-state segment )
    • TR段寄存器
      • TR段寄存器的读写
    • TSS段描述符
    • 实验:加载自定义TSS
      • 第一步:获取必要参数
      • 第二步:构造TSS段描述符
      • 第三步:将TSS段描述符写入GDT表
      • 第四步:解除中断,继续执行代码
  • 任务门
    • 任务门执行过程
    • 实验:通过任务门切换TSS
      • 第一步:构造任务门描述符
      • 第二步:将任务门描述符写入IDT表
      • 第三步:构造TSS段描述符
      • 第四步:运行代码

要点回顾

  1. 在调用门、中断门与陷阱门中,一旦出现权限切换,那么就会有堆栈的切换;而且,由于CS的CPL发生改变,也导致了SS也必须要切换
  2. 思考:切换时,会有新的ESP和SS(CS是由中断门或者调用门指定)这2个值从哪里来的呢?
    答案:TSS (Task-state segment ):任务状态段

任务段

TSS (Task-state segment )

描述:

TSS是一块内存
大小:104字节
TSS存储了一堆寄存器的值

TSS结构图:

TSS的作用

  1. Intel的设计思想:通过使用TSS以达到任务(线程)的切换
  2. 操作系统的设计思想:与Intel设计思想不同的是,Windows并没有根据Intel的设计思想来做,甚至Linux也没有这样做

TSS的本质

  1. 不要把TSS与"任务切换"联系到一起
  2. TSS的意义就在于可以同时换掉"一堆"寄存器

CPU通过TR段寄存器寻找TSS

TR段寄存器

描述:

TR寄存器的值是当操作系统启动时,从TSS段描述符中加载出来的,TSS段描述符在GDT表中
TR.Base = TSS起始地址
TR.Limit = TSS大小

TR段寄存器的读写

一、将TSS段描述符加载到TR寄存器
指令:LTR
说明:

  1. 用LTR指令去装载的话 仅仅是改变TR寄存器的值(96位)
  2. 并没有真正改变TSS
  3. LTR指令只能在系统层使用
  4. 加载后TSS段描述符的状态位会发生改变

二、读TR寄存器
指令:STR
说明:如果用STR去读的话,只读了TR的16位,也就是段选择子

TSS段描述符

描述:

TSS段描述符是系统段描述符中的一种

结构图:

Type = 二进制1001:说明该TSS段描述符被加载到TR段寄存器中
Type = 二进制1011:说明该TSS段描述符被加载到TR段寄存器中

TSSTSS段描述符TR段寄存器关系示意图:

实验:加载自定义TSS

第一步:获取必要参数

在VC6中运行如下代码并在main函数头部设置中断:

#include <windows.h>DWORD dwOK;
DWORD dwESP;
DWORD dwCS;void __declspec(naked) func()
{dwOK = 1;__asm{int 3mov eax,espmov dwESP,eaxmov ax,csmov word ptr [dwCS],ax//回去的代码没写。。。}
}int main(int argc, char* argv[])
{char bu[0x10];  //12ff70int iCr3;printf("input CR3:\n");scanf("%x", &iCr3);DWORD iTss[0x68] = {0x00000000,        //link0x00000000,       //esp0      //(DWORD)bu0x00000000,      //ss00x00000000,        //esp10x00000000,       //ss10x00000000,        //esp20x00000000,       //ss2(DWORD)iCr3,   //cr30x0040DE50,        //eip0x00000000,        //eflags0x00000000,     //eax0x00000000,        //ecx0x00000000,        //edx0x00000000,        //ebx(DWORD)bu,     //esp0x00000000,        //ebp0x00000000,        //esi0x00000000,        //edi0x00000023,        //es0x00000008,     //cs        0x0000001B0x00000010,       //ss        0x000000230x00000023,       //ds0x00000030,     //fs0x00000000,     //gs0x00000000,     //dit0x20ac0000};char buff[6];*(DWORD*)&buff[0] = 0x12345678;*(WORD*)&buff[4] = 0xC0;__asm{call fword ptr[buff]}printf("ok=%d \t ESP=%x \t CS=%x \n", dwOK, dwESP, dwCS);return 0;
}

进入反汇编窗口查看 func 函数起始地址,我这里是0x401020

将地址填入iTss数组注释为eip的地方,表示TSS切换后EIP的值

再通过 memory 窗口查看iTss数组所在地址,记下来备用

注意:代码中如有地方发生修改,需要先停止程序,重新编译

第二步:构造TSS段描述符

Offset in Segment 31:16 = 0x0000        // 暂定G = 0AVL = 0Limit = 二进制:0000P = 1DPL = 二进制:11Type = 二进制:1001Segment Limit = 0068H           // Intel规定TSS段描述符G=0时Limit必须大于或等于67H
Offset in Segment 15:00 = 0x0000       // 暂定

由上述参数构造出的门描述符为:0000E900`00000068

在第一步中,我们已经知道iTss数组所在地址为0x12FDCC
因此,TSS段描述符最终确定为:0000E912`FDCC0068

第三步:将TSS段描述符写入GDT表

我写入的地址是8003f0c0,若写入其他地址,则需要修改buff数组的后两个字节

这时候先不要急着继续运行代码,先在WinDbg中输入命令:!process 0 0
获得当前进程的Cr3(我这里进程名叫TestDoor.exe,之前是用来做调用门的实验,TSS没有新建项目)

DirBase的值就是Cr3

第四步:解除中断,继续执行代码

输入上一步得到的Cr3,回车

WinDbg成功获得了中断信号

这时候看一下反汇编代码

可以确定正在执行func函数的代码

再看一下寄存器

eip、cs、ss都符合我们想要的结果

至此,TSS切换成功!


思考:TSS切换完成后,如何回到切换前的下一行继续执行?

任务门

描述:

任务门存在于IDT表
任务门中包含TSS段选择子
可以通过访问任务门达到切换TSS的目的

结构图:

任务门执行过程

  1. INT N(N为IDT表索引号)
  2. 系统通过用户指定的索引查找IDT表,找到对应的门描述符
  3. 门描述符若为任务门描述符,则根据任务门描述符中TSS段选择子查找GDT表,找到TSS段描述符
  4. 将TSS段描述符中的内容加载到TR段寄存器
  5. TR段寄存器通过Base和Limit找到TSS
  6. 使用TSS中的值修改寄存器
  7. IRETD返回

实验:通过任务门切换TSS

第一步:构造任务门描述符

任务门描述符结构图灰色部分默认填充为0

                   P = 1DPL = 二进制:11TSS Segment Selector = 0x00C3     // TSS段描述符选择子

由上述参数及默认参数构造出的门描述符为:0000e500`00C30000

第二步:将任务门描述符写入IDT表

第三步:构造TSS段描述符

TSS段描述符构造具体过程参照任务段实验部分,这里不再详解,只给出测试代码

代码如下:

#include <windows.h>DWORD dwOK;
DWORD dwESP;
DWORD dwCS;void __declspec(naked) func()
{dwOK = 1;__asm{mov eax,espmov dwESP,eaxmov ax,csmov word ptr [dwCS],axiretd}
}int main(int argc, char* argv[])
{char bu[0x10];  //12ff70int iCr3;printf("input CR3:\n");scanf("%x", &iCr3);DWORD iTss[0x68] = {0x00000000,        //link0x00000000,       //esp0      //(DWORD)bu0x00000000,      //ss00x00000000,        //esp10x00000000,       //ss10x00000000,        //esp20x00000000,       //ss2(DWORD)iCr3,   //cr30x00401020,        //eip0x00000000,        //eflags0x00000000,     //eax0x00000000,        //ecx0x00000000,        //edx0x00000000,        //ebx(DWORD)bu,     //esp0x00000000,        //ebp0x00000000,        //esi0x00000000,        //edi0x00000023,        //es0x00000008,     //cs        0x0000001B0x00000010,       //ss        0x000000230x00000023,       //ds0x00000030,     //fs0x00000000,     //gs0x00000000,     //dit0x20ac0000};__asm{int 0x20}printf("ok=%d \t ESP=%x \t CS=%x \n", dwOK, dwESP, dwCS);getchar();return 0;
}

第四步:运行代码

需要输入Cr3,Cr3获取流程参照任务段实验部分,这里不再详解

运行结果:

TSS切换成功!

至此,我们已经学会通过CALL/JMP以及任务门来切换TSS


思考:既然已经可以直接访问任务段了,为什么还要有任务门?

Windows保护模式学习笔记(五)—— 任务段任务门相关推荐

  1. Windows保护模式学习笔记(四)—— 中断门陷阱门

    Windows保护模式学习笔记(四)-- 中断门&陷阱门 要点回顾 中断描述符表(IDT) 一.中断门 实验:构造一个中断门 第一步:初步构造参数 第二步:确定 Offset in Segme ...

  2. Windows保护模式学习笔记(二)—— 代码跨段跳转

    Windows保护模式学习笔记(二)-- 代码跨段跳转 要点回顾 代码跨段跳转 执行流程 1)段选择子拆分 2)查表得到段描述符 3)权限检查 4)加载段描述符 5)代码执行 6)总结 一致代码段(共 ...

  3. Windows保护模式学习笔记(一)—— 段寄存器GDT表

    Windows保护模式学习笔记(一)-- 段寄存器&GDT表 保护模式 参考书籍: 一.段寄存器 段寄存器的结构 段寄存器的读写 段寄存器的属性 1)探测Attribute: 2)探测Base ...

  4. Windows保护模式学习笔记(十二)—— 控制寄存器

    Windows保护模式学习笔记(十二)-- 控制寄存器 控制寄存器 Cr0寄存器 Cr2寄存器 Cr4寄存器 控制寄存器 描述: 控制寄存器有五个,分别是:Cr0 Cr1 Cr2 Cr3 Cr4 Cr ...

  5. Windows保护模式学习笔记(九)—— 2-9-9-12分页

    Windows保护模式学习笔记(九)-- 2-9-9-12分页 要点回顾 10-10-12分页 原理 环境配置 2-9-9-12分页 原理 PDPTE PDE PTE XD/NX标志位 环境配置 实验 ...

  6. Windows保护模式学习笔记(六)—— 10-10-12分页

    Windows保护模式学习笔记(六)-- 10-10-12分页 基本概念 4GB内存空间 有效地址-线性地址-物理地址 有效地址与线性地址 物理地址 控制寄存器:Cr3 10-10-12分页 实验:通 ...

  7. Windows保护模式学习笔记(三)—— 长调用/短调用/调用门

    Windows保护模式学习笔记(三)-- 长调用/短调用/调用门 要点回顾 长调用与短调用 一.短调用 二.长调用(跨段不提权) 三.长调用(跨段并提权) 长调用执行时: 执行返回(RETF)时: 总 ...

  8. Windows保护模式学习笔记(八)—— 页目录表基址/页表基址

    Windows保护模式学习笔记(八)-- 页目录表基址/页表基址 要点回顾 一.页目录表基址 实验:拆分线性地址C0300000,并查看其对应的物理页 第一步:打开一个进程,获得它的Cr3 第二步:查 ...

  9. Windows保护模式学习笔记(十四)—— 阶段测试

    Windows保护模式学习笔记(十四)-- 阶段测试 题目一 解题步骤 题目二 解题步骤 题目一 描述:给定一个线性地址,和长度,读取内容 int ReadMemory(OUT BYTE* buffe ...

最新文章

  1. *13.图的存储方式
  2. DFS解01背包问题
  3. Scala Array sum recursive call
  4. JAVA第六章第6题,java第六章例题源代码
  5. ThreadLocal线程范围内的共享变量
  6. 实战 | 后端日志的前世今生
  7. java多线程,java线程同步
  8. 睡眠分期中的各种特征
  9. 实现简易网易云音乐播放器
  10. Linux 删除分区
  11. 一年半,从编程都不懂的小白到成功入职!
  12. 2.07 CISC与RISC
  13. ResNeXt代码复现+超详细注释(PyTorch)
  14. nginx正则表达式快捷测试方法
  15. 计算机毕业设计Android网上相亲交友婚恋app(源码+系统+mysql数据库+Lw文档)
  16. pandas含有空列表
  17. 《Qt Quick核心编程》勘误
  18. WEB应用项目开发-网店购物系统开发
  19. 通达信行情数据获取--python_Python读取通达信数据
  20. 7-10 公路村村通 (30分) C++ kruskal算法

热门文章

  1. HighNewTech:20190824上海人工智能大会(2019SHAI)暨第二届图像视频处理与人工智能国际会议参会感悟记录
  2. Crawler:基于urllib+requests库+伪装浏览器实现爬取国内知名招聘网站,上海地区与机器学习有关的招聘信息(2018.4.30之前)并保存在csv文件内
  3. Express框架(http服务器 + 路由)
  4. Win8怎么查看IP地址
  5. 关于mysql_connect CLIENT_MULTI_RESULTS
  6. quick 关于触摸的问题
  7. delphi和INNO SETUP 文件关联操作
  8. VC里的集合类、链表类、映射类
  9. CFG_GCR全局配置寄存器设置
  10. 百度超级链XChain(2)p2p网络