任务段call 与jmp实验
任务段
前言
在调用门和中断门还有陷阱门中,会有压栈操作,由于cs和cpl会发生改变,导致ss也必须切换,切换时候,esp和ss是从任务段中获得的,也及时TSS
TSS结构
大小共104字节
TR寄存器
了解任务段一定要知道TR寄存器,这是CPU找到TSS的关键,TR寄存器总共有98个位(其实是16位,跟段选择子一样)
流程:
1、tr寄存器通过段选择子
2、在gdt表里面找到段描述符,并且通过段描述符的结构,找到BaseAddress地址,找到BaseAddress地址后,相当于找到了TSS任务段
3、并且从段描述符中还获得了lmit其实就是TSS段的大小在32位的情况下一般是0x68字节的,如图
TSS段描述符结构
其实这里本应该在放一张开发Intel手册的图的,这样更清晰
Type 1001代表着是可用的任务段,如果B为1则是繁忙状态
TR寄存器的读写
将段描述符加载到TR寄存器
LTR指令
说明:
1、用LTR指令去装载的话,仅仅是改变TR寄存器的值(96位),并没有真正改变TSS(原来的TSS还在那)
2、LTR指令只能在系统层使用
3、加载后TSS段描述符会状态位会发生改变
读TR寄存器
STR指令
说明:
如果用STR去读的话,只读了TR寄存器的16为,也就是选择子
实验流程
先构造TSS任务段,然后在将任务段的eip改为你要执行函数的地址,其他的可以根据你自己的改,其次就是需要让cs和ss指向的是同一个(因为他们是一对),在去执行就可以调用成功了,不过我这里有个问题,希望有大佬可以指出
放代码,如下:
1 // Task_Segment.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include<windows.h> 6 DWORD dwOK; 7 DWORD dwESP; 8 DWORD dwCS; 9 __declspec(naked) void func() 10 { 11 dwOK=1; 12 __asm{ 13 int 3 14 mov eax,esp 15 mov dwESP,eax 16 mov ax,cs 17 mov word ptr [dwCS],ax 18 iretd 19 //go back code don't write 20 } 21 } 22 23 int main(int argc, char* argv[]) 24 { 25 char bu[0x10];//0x12ff70 26 int iCr3; 27 printf("input CR3:\n"); 28 scanf("%x",&iCr3); 29 30 DWORD iTss[0x68]={ 31 0x00000000,//link 32 (DWORD)bu,//esp0 33 0x00000010,//ss0 34 0x00000000,//esp1 35 0x00000000,//ss1 36 0x00000000,//esp2 37 0x00000000,//ss2 38 (DWORD)iCr3,//cr3 39 0x00401020,//eip 40 0x00000000,//eflags 41 0x00000000,//eax 42 0x00000000,//ecx 43 0x00000000,//edx 44 0x00000000,//ebx 45 (DWORD)bu,//esp 46 0x00000000,//ebp 47 0x00000000,//esi 48 0x00000000,//edi 49 0x00000023,//es 50 0x00000008,//cs 0x0000001B 51 0x00000010,//ss 0x00000023 52 0x00000023,//ds 53 0x00000030,//fs 0x0000003B 54 0x00000000,//ldt 55 0x20ac0000 56 }; 57 printf("iTss: %x\n",iTss); 58 /* 59 __asm{ 60 int 0x20 61 } 62 */ 63 char buff[6]; 64 65 *(DWORD*)&buff[0]=0x12345678; 66 *(WORD*)&buff[4]=0x48; 67 _asm 68 { 69 call fword ptr [buff] 70 } 71 printf("ok = %d ESP = %x CS = %x \n",dwOK,dwESP,dwCS); 72 return 0; 73 }
根据函数地址,创建段描述符
修改段描述符
通过指令!process 0 0输入CR3
输入0aac0320
输入g运行,可以看到,已经运行了
为了方便在来看下寄存器
观察寄存器可以发现,所有的寄存器已经被换掉了
但不知道为啥 运行到这里之后,运行了in3后,接着运行到iretd就开始报错了,所以我怀疑我跳回去的代码是有问题的,如果不是用iretd这个指令跳回去,那我应该怎么跳回去呢?
在网上也查了别人的执行流程,感觉是一个道理,沉淀依然不够,得把实验实力加深点,再来看看这个错误了,还得接着实验才行了
提问
1:)8号中断是什么?
8003f440 00008500`00501198
将其分解
在去查找其相对应的段选择子
8003f050 80008955`27000068
接着分解
可以知道base
用命令dt _KTSS 查看该地址检查
0: kd> dt _KTSS 80552700 nt!_KTSS +0x000 Backlink : 0 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x8054f700 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4] 0 +0x01c CR3 : 0xb0d000 +0x020 Eip : 0x80544509 +0x024 EFlags : 0 +0x028 Eax : 0 +0x02c Ecx : 0 +0x030 Edx : 0 +0x034 Ebx : 0 +0x038 Esp : 0x8054f700 +0x03c Ebp : 0 +0x040 Esi : 0 +0x044 Edi : 0 +0x048 Es : 0x23 +0x04a Reserved2 : 0 +0x04c Cs : 8 +0x04e Reserved3 : 0 +0x050 Ss : 0x10 +0x052 Reserved4 : 0 +0x054 Ds : 0x23 +0x056 Reserved5 : 0 +0x058 Fs : 0x30 +0x05a Reserved6 : 0 +0x05c Gs : 0 +0x05e Reserved7 : 0 +0x060 LDT : 0 +0x062 Reserved8 : 0 +0x064 Flags : 0 +0x066 IoMapBase : 0x20ac +0x068 IoMaps : [1] _KiIoAccessMap +0x208c IntDirectionMap : [32] ""
2:)做了什么事情?
替换当前环境的值
3:)替换了哪些寄存器?
查看了idtr表后可以知道,其切换了cs段,在学习调用门的时候就知道,提权会保存之前的环境的,所以在运行时,可以知道寄存器更改了cs、ss、esp、ip
在来看看任务门替换的,可以发现都是由于ss与ds必须是一对,cs又都是一样的,所以只有ip变了
4:)替换后的值是多少?
0x80544509
5:)为什么这样设计
程序出现异常,进行任务的切换