c++
即 若是 是 29 9 12 分頁 請求數據 可能須要訪問 4次內存;爲了解決這個問題;出現了 TLB (虛擬地址到物理地址的轉換關係),若是目標地址在TLB緩存中,那麼直接從TLB 取出 物理地址;web
》 這個實驗作起來很麻煩,由於:緩存
TLB 是CPU 內部的,無法經過彙編指令訪問TLB;ide
調試器,也沒有辦法知道 TLB 中有哪些項函數
只有經過實驗現象 結果,來證實其存在。測試
》 注意 TLB 產生異常 3; 不會回到 2;而是產生 0x0E 異常。spa
// 7_TLB_test.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
DWORD g_out;
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
__asm mov eax, ds: [0x405000]
//確保虛擬地址在TLB中
PTE(0x41c000)[0] = PTE(0x41d000)[0];
PTE(0x41c000)[1] = PTE(0x41d000)[1];
g_out = page2[0];
__asm {
iretd
}
}
void _declspec(naked) go() {
{
pagel[0] = 1; //確保物理頁存在
page2[0] = 2;
}
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00~ 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
go();
printf("%d\n", g_out);
system("pause");
}
太快了 。。。 截圖不到。。。額3d
因爲 是對同一個物理頁釋放了兩次形成了藍屏;調試
因此 保存好 原來的pte值;orm
因此在 中斷返回以前,將那個 虛擬頁的 pte 修改回來便可
這個cr3 的切換 會致使 沒有 g 屬性的tlb 失效。即清除;
緣由很簡單,由於 這個 cr3都切換了 tlb 中的虛擬地址沒有g屬性的;已經在當前cr3 中沒有意義了。雖然 這裏切換的是本身的,可是同樣能夠達到效果。
// 7_TLB_test.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
DWORD g_out;
DWORD g_OldPte[2];
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
// 確保虛擬地址在TLB中
__asm mov eax, ds: [0x405000];
// 保存舊的pte ,以用來恢復pte 解決不藍屏
g_OldPte[0] = PTE(0x41c000)[0];
g_OldPte[1] = PTE(0x41c000)[1];
PTE(0x41c000)[0] = PTE(0x41d000)[0];
PTE(0x41c000)[1] = PTE(0x41d000)[1];
__asm{
mov eax,cr3
mov cr3,eax
}
g_out = page2[0];
// 恢復到原來的pte
PTE(0x41c000)[0]=g_OldPte[0];
PTE(0x41c000)[1]=g_OldPte[1];
__asm {
iretd
}
}
void _declspec(naked) go() {
{
pagel[0] = 1; //確保物理頁存在
page2[0] = 2;
}
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00~ 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
go();
printf("%d\n", g_out);
system("pause");
}
數據正確了 ,並且沒有藍屏
查看 pte 有無G位:
通常3環的 pte 沒有G位。內核屬性爲 G位這樣TLB 就不會被刷新出去。
// 7_TLB_test.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
DWORD g_out;
DWORD g_OldPte[2];
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
// 確保虛擬地址在TLB中
__asm mov eax, ds: [0x405000];
// 保存舊的pte ,以用來恢復pte 解決不藍屏
g_OldPte[0] = PTE(0x41c000)[0];
g_OldPte[1] = PTE(0x41c000)[1];
PTE(0x41c000)[0] = PTE(0x41d000)[0]|0x100;// 設置G位
PTE(0x41c000)[1] = PTE(0x41d000)[1];
__asm{
mov eax,cr3
mov cr3,eax
}
// 調用調用;確保在 TL B 中
__asm mov eax, ds:[0x41c000];
// 恢復到原來的pte
//---- 這樣
// 按道理 後面一旦後面刷新 TLB 將 普通 TLB 刷新出去,
// 那麼 g_out = page2[0] 的值就 應該是 正常 的原 pte 對應的數據 -- 2。
PTE(0x41c000)[0] = g_OldPte[0];
PTE(0x41c000)[1] = g_OldPte[1];
__asm
{
mov eax,cr3
mov cr3,eax
}
g_out = page2[0]; // 講道理 在非G位下 應該是2(原PTE解析出的) -- 可是這裏咱們設置了PTE 的G位,
// so 這裏應該是 TLB快表中 對應的 1;
__asm {
iretd
}
}
void _declspec(naked) go() {
{
pagel[0] = 1; //確保物理頁存在
page2[0] = 2;
}
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00~ 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
go();
printf("%d\n", g_out);
system("pause");
}
果真 G位的TLB 不會被 刷新出去:
__asm invlpg ds: [0x41c000] //強行更新TLB項,無視G位
這時候 TLB 中就沒有以前那個虛擬地址的TLB 虛擬項了。這時候就是正常的值了。
前面 咱們 hook 系統函數 systemfastcallentry 是修改 cr0 無視 WP位 頁寫保護。
如今咱們能夠使用 直接 修改 systemfastcallentry( ) 所在的pte;爲 可寫的狀態;而且使用強行刷新TLB 將那個pte在TLB中的數據刷新
PTE(XXX)[0] =...;
PTE(XXX)[1] = ..;
__asm invlpg ds: [XXX] //強行更新TLB項,無視G位