》 TLB 是为了增加访问内存的效率

即 如果 是 29 9 12 分页 请求数据 可能需要访问 4次内存;为了解决这个问题;出现了 TLB (虚拟地址到物理地址的转换关系),如果目标地址在TLB缓存中,那么直接从TLB 取出 物理地址;

》 这个实验做起来很麻烦,因为:

  • TLB 是CPU 内部的,没法通过汇编指令访问TLB;

  • 调试器,也没有办法知道 TLB 中有哪些项

  • 只有通过实验现象 结果,来证明其存在。

内存访问的步骤:

注意 TLB 产生异常 3; 不会回到 2;而是产生 0x0E 异常。

1 简单实验查看 快表 带来的影响:

图解:

代码:

// 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
#pragma section("data seg", read, write)
_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");
}

效果:

蓝屏:

太快了 。。。 截图不到。。。额

解决蓝屏:

由于 是对同一个物理页释放了两次造成了蓝屏;

所以 保存好 原来的pte值;

所以在 中断返回之前,将那个 虚拟页的 pte 修改回来即可

刷新TLB,解决 结果和我们预期差异

这个cr3 的切换 会导致 没有 g 属性的tlb 失效。即清除;

原因很简单,因为 这个 cr3都切换了 tlb 中的虚拟地址没有g属性的;已经在当前cr3 中没有意义了。虽然 这里切换的是自己的,但是一样可以达到效果。

改后的代码:

// 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
DWORD g_OldPte[2];
#pragma section("data seg", read, write)
_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");
}

之后的效果:

数据正确了 ,而且没有蓝屏

2 有G属性的TLB 项

查看 pte 有无G位:

一般3环的 pte 没有G位。内核属性为 G位这样TLB 就不会被刷新出去。

设置我们3环的页G位有效--不被刷出TLB:

代码:

// 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
DWORD g_OldPte[2];
#pragma section("data seg", read, write)
_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 不会被 刷新出去:

当然 还可以强行更新 TLB 项,无视G位:

__asm invlpg ds: [0x41c000] //强行更新TLB项,无视G位

这时候 TLB 中就没有之前那个虚拟地址的TLB 虚拟项了。这时候就是正常的值了。

利用:inline Hook

前面 我们 hook 系统函数 systemfastcallentry 是修改 cr0 无视 WP位 页写保护。

现在我们可以使用 直接 修改 systemfastcallentry( ) 所在的pte;为 可写的状态;并且使用强行刷新TLB 将那个pte在TLB中的数据刷新

PTE(XXX)[0] =...;
PTE(XXX)[1] = ..;
__asm invlpg ds: [XXX] //强行更新TLB项,无视G位

最新文章

  1. css个人随笔,适合新手总结整理
  2. linux挂着U盘和光盘
  3. poj 1905Expanding Rods
  4. ProgressDialog使用总结
  5. 14交互活动:XHTML表单
  6. Enter直接登录
  7. ireport启动闪退问题
  8. EOJ-1708//POJ3334
  9. mapreduce运行机制
  10. 深度学习入门篇--手把手教你用 TensorFlow 训练模型
  11. Python爬虫(1):基础知识
  12. python vtk 通过回调函数监测键盘”Up”键动作,每按一次方向上键,actor变换一种颜色
  13. 2018/05/02 每日一学Linux 之 .bash_profile和.bashrc的区别
  14. laravel用crud修改产品items-新建resource controller和routing
  15. Spark学习之路 (十二)SparkCore的调优之资源调优
  16. squid介绍和作用
  17. javac编译时找不到文件的问题和运行项目找不到指定类问题
  18. 电脑蓝屏提示unexpected store exception的解决方法
  19. C语言中的可变参数函数
  20. Scala代码开发 metaTable(元表)

热门文章

  1. 封装tab切换事件
  2. Spring注解之@Component、@Controller、@Service、@Repository
  3. 虚拟机linux系统 硬盘/root路径扩容
  4. ZOJ-3524 拓扑排序+完全背包(好题)
  5. 让APK只包含指定的ABI(转)
  6. python_django_富文本
  7. linux php5.6 安装
  8. ( vant ) 新手踩坑
  9. vue 表单校验报错 &quot;Error: please transfer a valid prop path to form item!&quot;
  10. C/C++ 智能指针线程池