(7) [保护模式]任务段 (TSS)

2023-10-12 16:30
文章标签 任务 保护模式 tss

本文主要是介绍(7) [保护模式]任务段 (TSS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • TR寄存器
  • TR寄存器的作用
  • 任务段描述符
  • TSS (任务段)
  • 使用任务段修改寄存器的值
  • jmp far 和 call far 的不同
  • 拓展

TR寄存器

说到TSS就不得不提TR寄存器了
TR段寄存器依然是指向一个段描述符,但是是一个比较特殊的描述符,我们称之为任务段描述符

TR寄存器的作用

在这里插入图片描述

书中表示栈的方式与OD表示的方式刚好相反

TR 寄存器中的selector查找GDT表后将段寄存器剩余内容填充,address刚好指向TSS表,而limit则是这张表的大小

TR寄存器的读写:(特权指令,只能在0环用)

  • LTR (Load TR):写入TR寄存器,和往常一样写入selector,剩余的查GDT表填充 (LTR reg16 / men)
  • STR (Save TR):读取TR寄存器的值并存储到 (STR reg16 / men)

任务段描述符

在这里插入图片描述
B (busy flag) : 当进入任务时设置为1,退出时设置为0。若是B为1时被调用,则会出异常

TSS (任务段)

TSS : Task-state segment (任务状态段)
在这里插入图片描述

这个表的主要作用就是用来进行任务切换。

任务可以是一个线程,也可以是一个进程。也就是说线程切换或者进程切换的时候使用这个表

  • 顾名思义,从4-95位都是用于保存任务切换时当前任务寄存器的状态,当切换回来当前任务的时候填充寄存器的。
  • 每个任务都有自己独立的CR3,当前只要知道这个一定要填就行
  • Previous Task Link : 指向前一个TSS表的段选择子
  • 每个任务都有自己的LDT表(局部描述符表),但不使用
  • T (debug trap flag): 是表示当前的是否是debug状态,如果是1则调试断点被设置,我们写0
  • IO Map Base Address : IO权限位图,本实验中不涉及这个。是一个基于TR.BaseAddress的偏移。IO权限和EFLAG中的12,13位也有关联,而权限位图中表示端口是否可用

TSS表每个任务一份,当进行任务切换的时候,我们只需要改变TR寄存器的值就能用上不同的表了

我们知道,函数调用的时候要把某些寄存器的值存起来,以便return回来的时候能够继续执行。
任务切换的时候也不例外,需要保存现场,所以需要找一个地方存放上下文(context),当任务切换回来时使用上下文替换寄存器,继续执行当前任务。


使用任务段修改寄存器的值

  • 首先构造一个TSS
  • 然后使用call far 或 jmp far调用这个TSS描述符
  • 函数返回

首先写出函数

#include <windows.h>int tss[] = {		0x00000000,//link0x00000000, //esp0	10x00000010,//ss0	20x00000000,//esp10x00000000,//ss10x00000000,//esp20x00000000,//ss20x00000000,//cr3	70x00000000,//eip	8 func addrs0x00000000,//eflags0x11111111,//eax0x22222222,//ecx0x33333333,//edx0x44444444,//ebx0x00000000, //esp	140x00000000,//ebp0x00000000,//esi0x00000000,//edi0x00000023,//es0x00000008,//cs		190x00000010,//ss0x00000023,//ds0x00000030,//fs0x00000000,//gs0x00000000,//ldt0x20ac0000 // IO map
};BYTE stack[0x100];
void __declspec(naked) func(){_asm{pushfint 3popfiretd}
}int main(){BYTE callAddrs[6] = {0x00, 0x00, 0x00, 0x00, 0x48, 0x00};memset(stack, 0, 0x100);	//init stackprintf("TSS    addrs: %x\n", tss);printf("input CR3:\n");scanf("%x", &tss[7]);		//cr3tss[8] = (DWORD)&func;		//eiptss[14] = stack + 0x100;	//esp 一定要设置堆栈,否则蓝屏_asm{	call fword ptr[callAddrs]}}

在这里插入图片描述
获取TSS地址,并准备填入CR3

找一个位置写入TSS段描述符
在这里插入图片描述

eq 8003f048 0000e942`9a300068

执行!process 0 0,然后复制CR3,输入到程序中去
在这里插入图片描述
在这里插入图片描述

运行后,程序在windbg上断下来了
在这里插入图片描述
千万别单步,直接 go

单步会修改EFLAG的NT位,会蓝屏

NT == 1 //iretd使用上一个 TSS 返回
NT == 0 //iretd使用 堆栈 返回

使用了TSS进入,自然要使用TSS返回,所以NT位改变了就会蓝屏


jmp far 和 call far 的不同

jmp far和call far调用的TSS,EFLAG是不同的

#include <windows.h>int tss[] = {		0x00000000,//link0x00000000, //esp0	1 stack00x00000010,//ss0	20x00000000,//esp10x00000000,//ss10x00000000,//esp20x00000000,//ss20x00000000,//cr3	70x00000000,//eip	8 func addrs0x00000000,//eflags0x11111111,//eax0x22222222,//ecx0x33333333,//edx0x44444444,//ebx0x00000000, //esp	14 stack30x00000000,//ebp0x00000000,//esi0x00000000,//edi0x00000023,//es0x00000008,//cs		190x00000010,//ss0x00000023,//ds0x00000030,//fs0x00000000,//gs0x00000000,//ldt0x20ac0000 // IO map
};
BYTE tss2[0x68];
DWORD jmpEflag;
DWORD callEflag;
BYTE jmpBack[6];
BYTE stack[0x100];void __declspec(naked) funcCall(){_asm{pushadpushf//int 3 //打开注释可以断下调试mov eax, [esp];//刚push过EFLAGSmov callEflag, eax //保存EFLAGSpopfpopadiretd}
}void __declspec(naked) funcjmp(){_asm{pushadpushf//int 3mov eax, [esp];mov jmpEflag, eax //保存EFLAGSpopfpopad//即使NT现在是0,在这里iretd也会直接蓝屏//因为堆栈中并没有供iretd返回的 SS:ESP EFLAGS CS:EIP 结构jmp fword ptr[jmpBack]}
}int main(){//C语言只能在头部把变量全都申请了BYTE callAddrs[6] = {0x00, 0x00, 0x00, 0x00, 0x48, 0x00};WORD valTR;memset(stack, 0, 0x100);	//init stackprintf("TSS    addrs: %x\n", tss);printf("input CR3:\n");scanf("%x", &tss[7]);		//cr3tss[8] = (DWORD)&funcCall;		//eiptss[14] = stack + 0x100;	//espmemcpy(tss2, tss, 0x68);//备份TSS_asm{	call fword ptr[callAddrs]}memcpy(tss, tss2, 0x68);//这里是怕之前的TSS被覆盖了,所以使用备份重新填一次tss[8] = (DWORD)&funcjmp;//修改TSS的跳转位置_asm{str valTR	//保存当前TR,跳回使用}*(WORD*)(&jmpBack[4]) = valTR;//重新构造一个跳回的fword_asm{jmp fword ptr[callAddrs]}printf("call eflag: %x\n", callEflag);printf("jump eflag: %x\n", jmpEflag);system("pause");
}

在这里插入图片描述
上面代码的执行结果
4002 = 100 0000 0000 0010,第14位是NT位
这里也算是写出了 jmp far 跳回来的方法了


拓展

如果limit大于了0x68会发生什么?

  • 书中写了:如果limit < 0x67 调用将会报错,但是如果limit > 0x67系统在使用任务段的时候懒得检查。除非检查IO权限位图,才会检查limit与权限位图偏移之间的关系。

这就是intel提供的任务切换方案,也只能是他自己的一厢情愿。windows和linux都没有使用intel制定的方案,只有在权限切换时才会用到SS:ESP这两个值,其他的并没有使用。

3环:
在这里插入图片描述
跳转到0环:
在这里插入图片描述

3环转到0环的时候,堆栈的SS:ESP从何而来,就是从这张表里查的。

系统把返回时用到的CS,EIP,EFLAGS,SS,ESP都放入堆栈了,所以windows操作系统并没有完全使用这张表,至少跳回去的时候,我们可以直接在堆栈里把值取了。

系统不用,不代表我们不能用。

这篇关于(7) [保护模式]任务段 (TSS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/197078

相关文章

Python Invoke自动化任务库的使用

《PythonInvoke自动化任务库的使用》Invoke是一个强大的Python库,用于编写自动化脚本,本文就来介绍一下PythonInvoke自动化任务库的使用,具有一定的参考价值,感兴趣的可以... 目录什么是 Invoke?如何安装 Invoke?Invoke 基础1. 运行测试2. 构建文档3.

解决Cron定时任务中Pytest脚本无法发送邮件的问题

《解决Cron定时任务中Pytest脚本无法发送邮件的问题》文章探讨解决在Cron定时任务中运行Pytest脚本时邮件发送失败的问题,先优化环境变量,再检查Pytest邮件配置,接着配置文件确保SMT... 目录引言1. 环境变量优化:确保Cron任务可以正确执行解决方案:1.1. 创建一个脚本1.2. 修

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

FreeRTOS学习笔记(二)任务基础篇

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、 任务的基本内容1.1 任务的基本特点1.2 任务的状态1.3 任务控制块——任务的“身份证” 二、 任务的实现2.1 定义任务函数2.2 创建任务2.3 启动任务调度器2.4 任务的运行与切换2.4.1 利用延时函数2.4.2 利用中断 2.5 任务的通信与同步2.6 任务的删除2.7 任务的通知2

Flink任务重启策略

概述 Flink支持不同的重启策略,以在故障发生时控制作业如何重启集群在启动时会伴随一个默认的重启策略,在没有定义具体重启策略时会使用该默认策略。如果在工作提交时指定了一个重启策略,该策略会覆盖集群的默认策略默认的重启策略可以通过 Flink 的配置文件 flink-conf.yaml 指定。配置参数 restart-strategy 定义了哪个策略被使用。常用的重启策略: 固定间隔 (Fixe

第49课 Scratch入门篇:骇客任务背景特效

骇客任务背景特效 故事背景:   骇客帝国特色背景在黑色中慢慢滚动着! 程序原理:  1 、 角色的设计技巧  2 、克隆体的应用及特效的使用 开始编程   1、使用 黑色的背景: ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7d74c872f06b4d9fbc88aecee634b074.png#pic_center)   2

AsyncTask 异步任务解析

1:构建AsyncTask 子类的回调方法: A:doInBackground:   必须重写,所有的耗时操作都在这个里面进行; B: onPreExecute:     用户操作数据前的调用; 例如:显示一个进度条 等 ; C: onPostExecute:    当doInBackground 执行完成后;会自动把数据传给onPostExecute方法;也就是说:这个方法是处理返回的数据的方法