Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.html
任務段與任務門
索引:
1.任務段
2.如何加載一個段寄存器和取出段寄存器
3.TSS的作用(在Windows操作系統上)
4.如何查看TSS段內容
5.構造TSS門並進行提權
6.使用int3指令斷下觀察esp的實驗(出現一個elfags標志位的坑)
7.int3斷下時,如果不回復eflags寄存器,其就會卡死
8.任務門的作用(在Windows操作系統上)
9.任務門實驗
解答:
1. 任務段
任務段是系統段的一種,Windows操作系統只運行一個(啟動時就已經確定)

查看對應的任務段的屬性,當切換進執行程序時,其會將任務段屬性改為繁忙,
可以看出下表紅色的位置。

tr 寄存器表示當前的任務段,我們可以使用windbg 的 dg指令解析該段

2. 如何加載一個段寄存器和取出段寄存器
加載段寄存器 load (零環)
mov ax,0x28
ltr ax
取出段寄存器 store (三環)
str dword ds:[0x12345678]
獲取gdt: sgdt (三環) 加載gdt: lgdt (零環)
獲取idt: sidt ……………
3. TSS的作用(在Windows操作系統上)
線程切換時,一次保存多個寄存器。
注意:是線程切換,不是進程切換,進程切換還要替換整個環境遠不止寄存器那么多!!
4. 如何查看TSS段內的內容
TSS的地址就是TSS段描述符描述的基地址,因此我們通過 dg tr 查看其Base為 80042000。
對於查看TSS段,有一個單獨的指令。
dt _KTSS base_address
效果如下圖(此時沒用到,之后線程切換會有新的效果)

5. 構造tss門並進行提權
1)實驗代碼
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
DWORD iTSS[26];
DWORD ESP0[0x1000];
DWORD ESP3[0x1000];
DWORD dwESP;
DWORD dwCS;
DWORD dwCR3;
_declspec(naked) void Call(){
_asm{
mov dwESP,ESP;
mov ax,cs;
mov dwCS,eax;
iretd;
}
}
int main(int argc, char* argv[])
{
memset(iTSS,0,sizeof(iTSS));
memset(ESP0,0,sizeof(ESP0));
memset(ESP3,0,sizeof(ESP3));
dwESP = 0;
dwCS = 0;
dwCR3 = 0;
iTSS[1] = (DWORD)(ESP0+0x900); // ESP
iTSS[2] = 0x10; // SS0
iTSS[8] = (DWORD)Call; // EIP
iTSS[14] = (DWORD)(ESP3+0x900); // ESP3
iTSS[18] = 0x23; // ES
iTSS[19] = 0x08; // CS
iTSS[20] = 0x10; // SS
iTSS[21] = 0x23; // DS
iTSS[22] = 0x30; // FS
printf("iTSS:%x ESP3:%x ESP0:%x\n",iTSS,(ESP3+0x900),(ESP0+0x900));
printf("input cr3:");
scanf("%x",&dwCR3);
iTSS[7] = dwCR3; // cr3
char buf[6] = {0,0,0,0,0x48,0};
_asm{
call fword ptr buf;
}
printf("ESP:%x CS:%x\n",dwESP,dwCS);
return 0;
return 0;
}
2)查看TSS的內存地址,然后來修改任務門的偏移量(注意之前為函數地址,但任務門是一次性替換全部寄存器,因此函數地址在tss的eip中)。

0x48偏移處構造,windbg指令 eq 8003f048 0000e943`2c680068
3)使用 !process 0 0 找到對應的CR3(物理頁處),然后輸入進去。

4)可以看到其直接使用了三環的esp(雖然我們權限是零環,但它並沒有使用零環esp,而是直接替換目錄中的esp)。

6. 使用int3指令斷下觀察esp的實驗(出現一個eflags標志位的坑)
// #include "stdafx.h" #include "windows.h" DWORD iTSS[26]; DWORD ESP0[0x1000]; DWORD ESP3[0x1000]; DWORD dwESP; DWORD dwCS; DWORD dwCR3; _declspec(naked) void Call(){ _asm{ int 3; mov dwESP,ESP; mov ax,cs; mov dwCS,eax; // reset the NT flag in eflags register pushfd; pop eax; or eax,0x4000; push eax; popfd; iretd; } } int main(int argc, char* argv[]) { memset(iTSS,0,sizeof(iTSS)); memset(ESP0,0,sizeof(ESP0)); memset(ESP3,0,sizeof(ESP3)); VirtualLock(iTSS),0x2000); VirtualLock(ESP0),0x2000); VirtualLock(ESP3),0x2000); dwESP = 0; dwCS = 0; dwCR3 = 0; iTSS[1] = (DWORD)(ESP0+0x900); // ESP iTSS[2] = 0x10; // SS0 iTSS[8] = (DWORD)Call; // EIP iTSS[14] = (DWORD)(ESP3+0x900); // ESP3 iTSS[18] = 0x23; // ES iTSS[19] = 0x08; // CS iTSS[20] = 0x10; // SS iTSS[21] = 0x23; // DS iTSS[22] = 0x30; // FS printf("iTSS:%x ESP3:%x ESP0:%x\n",iTSS,(ESP3+0x900),(ESP0+0x900)); printf("input cr3:"); scanf("%x",&dwCR3); iTSS[7] = dwCR3; // cr3 char buf[6] = {0,0,0,0,0x48,0}; _asm{ call fword ptr buf; } printf("ESP:%x CS:%x\n",dwESP,dwCS); return 0; return 0; }

7. int 3 斷下時,如果不恢復eflags寄存器,其就會卡死。
因為當進行TSS跳轉時,其會將老的TSS保存在新的TSS頭部(上面我們看到),當我們使用iretd返回時,其不是像中斷那樣根據返回地址,而是根據TSS段選擇子找舊的TSS段內存,然后將里面的寄存器全部加載進去。
而INT 3 會清空 VM、NT、IF、TF四個位,其中NT表示嵌套任務段(nested task),如果清空,其就認為不存在任務段嵌套,直接像常規那樣,根據返回地址返回,此時就會出錯。
因此就會存在下面一段代碼來修改elfags寄存器中的NT位。
// reset the NT flag in eflags register
pushfd;
pop eax;
or eax,0x4000;
push eax;
popfd;
8. 任務門的作用

當CPU出現雙重錯誤,其就會通過任務門,調到08到中斷去。
任務門在IDT表中,觸發同樣適用 int 0x20;
9. 任務門實驗
// #include "stdafx.h" #include <stdlib.h> #include <windows.h> #include <memory.h> DWORD iTSS[26]; DWORD ESP0[0x1000]; DWORD ESP3[0x1000]; DWORD dwESP; DWORD dwCS; DWORD dwCR3; _declspec(naked) void Call(){ _asm{ //int 3; mov dwESP,ESP; mov ax,cs; mov dwCS,eax; // reset the NT flag in eflags register /* pushfd; pop eax; or eax,0x4000; push eax; popfd; */ iretd; } } int main(int argc, char* argv[]) { memset(iTSS,0,sizeof(iTSS)); memset(ESP0,0,sizeof(ESP0)); memset(ESP3,0,sizeof(ESP3)); VirtualLock(iTSS,28); VirtualLock(ESP0,0x1000); VirtualLock(ESP3,0x1000); dwESP = 0; dwCS = 0; dwCR3 = 0; iTSS[1] = (DWORD)(ESP0+0x900); // ESP iTSS[2] = 0x10; // SS0 iTSS[8] = (DWORD)Call; // EIP iTSS[14] = (DWORD)(ESP3+0x900); // ESP3 iTSS[18] = 0x23; // ES iTSS[19] = 0x08; // CS iTSS[20] = 0x10; // SS iTSS[21] = 0x23; // DS iTSS[22] = 0x30; // FS printf("iTSS:%x ESP3:%x ESP0:%x\n",iTSS,(ESP3+0x900),(ESP0+0x900)); printf("input cr3:"); scanf("%x",&dwCR3); iTSS[7] = dwCR3; // cr3 char buf[6] = {0,0,0,0,0x48,0}; _asm{ int 0x20; } printf("ESP:%x CS:%x\n",dwESP,dwCS); return 0; return 0; }
windbg 修改
其根據任務門屬性來進行如下修改:
eq 8003f500 0000e500`00480000 (任務門,通過int 0x20觸發,找到48選擇子處)
eq 8003f048 0000e943`2c680068 (TSS內存地址構造TSS段描述符)
填寫進程的CR3地址,之后就可以看見運行成功。
