实验
加载自定义TSS
先定义104个字节,代码如下:
// KernalTest.cpp : Defines the entry point for the console application.
//代码借鉴了https://blog.csdn.net/Kwansy/article/details/108896989
#include "stdafx.h"
#include <Windows.h>
DWORD dwOK;
DWORD dwESP;
DWORD dwCS;
char trs[6]={0};
void __declspec(naked) func()
{
dwOK = 1;
__asm
{
//jmp回去
jmp fword ptr trs;
//call回去
/*
pushfd
int 3 //此处int3会将nt位置1,不会通过link,因此提前保存eflag,返回之前还原nt位
mov eax,esp
mov dwESP,eax
mov ax,cs
mov word ptr [dwCS],ax
popfd
iretd*/
}
}
int main(int argc, char* argv[])
{
char bu[0x10]; //12ff70
int iCr3;
printf("input CR3:\n");
scanf("%x", &iCr3);
DWORD iTss[0x68] = {
0x00000000, //link
0x00000000, //esp0 //(DWORD)bu
0x00000000, //ss0
0x00000000, //esp1
0x00000000, //ss1
0x00000000, //esp2
0x00000000, //ss2
(DWORD)iCr3, //cr3
0x00401120, //eip
0x00000000, //eflags
0x00000000, //eax
0x00000000, //ecx
0x00000000, //edx
0x00000000, //ebx
(DWORD)bu, //esp
0x00000000, //ebp
0x00000000, //esi
0x00000000, //edi
0x00000023, //es
0x00000008, //cs 0x0000001B
0x00000010, //ss 0x00000023
0x00000023, //ds
0x00000030, //fs
0x00000000, //gs
0x00000000, //dit
0x20ac0000
};
char buff[6];
*(DWORD*)&buff[0] = 0x12345678;
*(WORD*)&buff[4] = 0xC0;
WORD rs=0;
__asm
{
str ax;
mov rs,ax;
}
*(WORD*)&trs[4]= rs;
__asm
{
jmp fword ptr buff;
//call fword ptr[buff]
}
printf("ok=%d \t ESP=%x \t CS=%x \n", dwOK, dwESP, dwCS);
getchar();
return 0;
}
反汇编查看func函数地址:
然后修改iTss结构中的eip,在获取iTss的地址:0012FDCC
构造TSS段描述符
Offset in Segment 31:16 = 0x0000 //
G = 0
AVL = 0
Limit = 二进制:0000
P = 1
DPL = 二进制:11
Type = 二进制:1001
Segment Limit = 0068 // 104的十六进制 0x68
Offset in Segment 15:00 = 0x0000 // 暂定
构造出TSS描述符为:0000E900 00000068,然后替换base 后结果为0000E912 FDCC0068,然后修改gdt表
eq gdtr+0xc0 0000E912`FDCC0068
dq gdtr+0xc0
当TR寄存器加载时候就会到0012FDCC中寻找TSS,在windg中获取CR3的值:
然后根据对应的进程名获取DirBase的值,0aac02a0,这个就是CR3的值,输入时候前面0不需要 不然系统会崩溃
运行程序
然后查看TR寄存器:
base已经被改变,再查看TSS