任务段进行任务切换,Jmp Call指令实现任务切换

2024-03-17 09:58

本文主要是介绍任务段进行任务切换,Jmp Call指令实现任务切换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        任务段描述符的格式我们就不说了太基本了,它的Base指向TSS结构的地址,Limit设置为0x68就够了TSS结构的大小就是104个字节,我们之前讲过,通过中断门,调用们提权的时候 ring0的堆栈ESP和SS都是TSS提供的,TSS结构每个核只有一个和KPCR结构一样,每当线程切换的时候会把当前线程的ESP0写入TSS结构中(以后进行线程切换逆向的时候会找到具体的代码),所以我们所Ring3提权到Ring0得到ESP都是当前线程的Ring的栈顶。

       TSS是CPU设计的实现多任务的方式,但是操作系统没有使用TSS作为线程切换,而是自己实现的线程切换,自己设计了一个Trap_Frame结构作为线程切换用于保存寄存器环境的一块内存,每个线程有一个通过线程结构可以找到这个字段,而TSS32位下操作系统只使用ESP0,SS0这两个字段用于门提权的时候获得RIng0的栈,

   今天我们带领大家通过任务段的方式实现任务的切换,可以使用jmp指令和Call指令

我们之前讲过jmp指令有四种使用方式   这是白皮书卷2jmp指令四种不同的跳转方式原话

1.jmp近跳,就是我们平常使用的jmp 硬编码后面接4个字节,可以跳转的地址为4GB,也称为段内跳转

2.jmp短跳,跳转的范围只限于当前EIP +128到-127 硬编码后面跟一个1字节

3.jmp远跳,   也称为段间跳转(会修改cs寄存器和eip寄存器的值)格式位  jmp  0x23:0x12345678  

4.任务切换,就是使用TSS结构中的值替换到当前寄存器,当我们把TSS 中的cs设置成0环的代码段就能实现提权

所以jmp指令是可以提权的,jmp指令任务切换的格式和jmp远跳的格式完全相同,有一点含义不同

jmp  0x48:0x12345678  如果此时0x48指向的是一个代码段的段描述符,此时就是jmp远跳,如果此时0x48指向的是一个任务段描述符,则此时是进行任务切换(会把这个加载任务段描述符到tr寄存器),jmp的远跳不能提权,jmp任务切换可以,

听过一位大佬说过非常经典的一段话,所有的指令要么操作内存,要么修改寄存器,jmp远跳修改的是cs和eip,而任务切换只是把tss里那些寄存器一下子全都替换而已

首先试试提权jmp任务切换提权

#include "stdafx.h"
#include <Windows.h>
int   taolaoda=0;
char  Ret[6]={0};
void  _declspec(naked) print(){
#if 0    
    __asm{
        mov eax,0x66666666
        mov taolaoda,eax
        mov eax,eax
        mov ebx,ebx
        pushfd
        pop eax
        or  eax,0x4000
        push eax
        popfd
        iretd
    }
#else
    __asm{
        int 3
         mov eax,0x66666666
        mov taolaoda,eax
        jmp fword ptr Ret
    }
#endif
}
int main(int argc, char* argv[]){
    char Buf[6]={0};

    char arrr[0x1000]={0};
    WORD  tr;
    DWORD Cr3=0;
    DWORD Pro=0;
    /*在0x1000 0000开辟一页的内存权限为可读可写*/
    int* P=(int*)VirtualAlloc((void*)0x10000000,0x1000,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE);
    if(NULL==P){
        MessageBox(NULL,"开辟虚拟内存失败",0,0);
    }
    __asm{
        str tr                                                       //读取tr寄存器的值到tr变量中
    }
    *(WORD*)&Ret[4]=tr;
    *(WORD*)&Buf[4]=0x48;
    printf("请输入CR3:");
    scanf("%x",&Cr3);
    P[1]=((int)arrr+0x100);
    P[2]=0x10;    
    P[7]=Cr3;
    P[8]=(int)print;            //EIP
    P[0xA]=1;
    P[0xB]=2;
    P[0xC]=3;
    P[0xD]=4;
    P[0xE]=((int)arrr+0x200);            //ESP

    P[0x12]=0x23;                //ES
    P[0x13]=0x8;                //CS
    P[0x14]=0x10;                //SS
    P[0x15]=0x23;                //DS
    P[0x16]=0x30;                //FS
    P[0x19]=0x20ac0000;    

    __asm{
        mov eax,0x00000000
        mov ecx,0x11117777
        mov edx,0x33333333
        mov ebx,0x11111111
        mov edi,0x22222222
        mov esi,0x33333333
        mov ebp,0x44449999

        jmp  fword ptr Buf;
    }
    printf("%p\n",taolaoda);
    getchar();
    return 0;
}

在构造一个任务段描述符 Base=0X10000000  Limlit=0x68

 

此时查看80042000处的TSS存储的值0x28选择子对应的也是一个任务段描述符 ,有人会奇怪一个是eb,一个是e9

e9是因为这个TSS段没有使用,eb是因为这个段描述符加载到了tr寄存器中,正在别使用,等会我们切换任务后就能看到变化了

找到当前进程的进行Cr3

输入TSS的cr3字段,注意cr3非常的重要,(我们知道每一个进行都有4GB虚拟内存),而每个进程都有一个0x10000000虚拟地址,这些0x10000000对应的物理内存肯定不同,CPU如何知道我们要找就是哪一个进程的?就是根据Cr3寄存器中的值查找的

MMU(存储管理单元,会根据Cr3和虚拟地址自动拆分,找到对应的物理页),这里需要一丢丢页的知识就能理解

任务切换就是把当TSS中的寄存器全都替换了,那肯定得把自己切换前的环境保存起来了,否则(我环境不就丢了)

返回地址就是0x40FCD0

继续F11可以看到Windug断下来了可以看到,它把当前环境保存到了前一个TSS中了就是0x28处的那个TSS

看一个当前TSS我们自己构造的  Previous Task  Link前一个任务段链接,没有填充这里的话如果使用Jmp不会填充这个字段,但是如果使用Call会在这里填充上一个TSS段的选择子,Jmp任务切换和Call任务切换的返回方式不一样,Jmp是切换提权,然后Jmp又切换回去

可以看到在切换任务之前tr加载的是0x28处的任务段描述符,指向jmp切换任务后 tr加载了0x48处的任务段描述符,并且把b位置为1了表示正在使用这个任务段,而前一个任务段的TSS就是0x28的Base指向的TSS中保存了切换任务之前的环境,便于我们等会在切换任务把那个环境恢复切换回去,

可以看到使用jmp和call(切换任务的时候都会把切换前的环境保存到上一个TSS中(call的我就不贴出来了))把call和jmp任务切换不同的贴不来

 

 

call指令的任务切换,还是当前进程的找到Cr3

F11继续,可以看到Call切换任务的时候,Previous Task  Link存储的前一个链接

按下去立马就挂了(这不像是蓝屏错误信息都没有,像是重启)这就是call指令任务切换不同的地方

Call指令任务切换的返回指令是iretd指令,中断门的时候返回指令及时iretd,当时说的是iretd指令从堆栈中弹出5值给 eip  cs  elfag  esp   ss,其实iretd指令会怎么执行依赖于elfag寄存器的NT位如果NT位=1就会从当前TSS结构中的Previous Task  Link找到上一个TSS的选择子,通过选择子找到上一个TSS,直接过如果单步Call里面就挂了

如果直接过就ok


直接F5就过了

 

直接进入call直接F5过 也能过  Previous Task  Link,jmp,call任务切换的时候他们都将切换前的环境保存在了前一个TSS中,

jmp指令如果jmp切换回去,call指令iretd  如果单步会将eflag寄存器nt设置为0,这个一定要主要,否定一定挂如果nt=0,iretd会从堆栈弹出5个值给那些寄存器,堆栈根本没有东西所以

获得Cr3

可以看到Call指令填充了

 

为了让大家跟加了解任务切换,我们从A进程切换到B进程

texttest进程有一个楼函数print地址0x401005

我们将Cr3改成texttest进程的

一按下就蓝了,应该TSS是设置的堆栈在texttest进程的没挂物理页,这就需要全都设置一下,在试试一次

设置好重新设置好esp为exttest进程控制堆栈

可以看到把堆栈设置后就过了,Windug给了一个警告,我们切换的进程不是当前进程就是cr3和当前进程的cr3不一样了

环境也保存在了前一个TSS里面

没执行一条指令就弹出一个警告

然后返回的时候有挂了,一想我就知道了,TSS的base是0x10000000是TSS进程的,使用texttest的cr3是找不到另外一个进程TSS(读其他进程的空间就是通过那个进程Cr3去读的哦,比如readprocessmemory函数writeprocessmemory),texttest的cr3去访问直接就挂了,如果在texttest的相同位置也搞个tss,或者挂相同的物理页,原理就是这样子了,这就是切换任务,写完这篇帖子感觉理解更加的深刻了,需要追到的是这是CPU提供切换任务的方式,操作系统没有用,但是本质是一样,切换Cr3切换ESP,任务就切换了至于其他寄存器就是回答现场的问题了,比如eip啊,(后面逆向线程切换的时候会带家详细的了解),学习内核的话没有捷径可以走,只有做实验,其他的什么都是扯淡,什么都是扯淡,除了自己动手做,TSS结构里面写入的堆栈必须是一个局部变量开辟在堆栈里面的,我试过用VirtualAlloc开辟块内存,让ESP指向这里面,和全局数据内存当做堆栈,都是直接挂,我们想线程有两个堆栈,是有默认大小的,而局部变量内存时在堆栈开辟的,所有可定不会有问题,而VirtualAlloc和全局数据的地址很大了,可能就溢出了,所以直接挂,我这里可能蓝屏了50次才想到这个原因,所有除了实验之外没有捷径可以走,太多太多的坑了。

 

这篇关于任务段进行任务切换,Jmp Call指令实现任务切换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取