zoukankan      html  css  js  c++  java
  • 15_TLB中的G属性

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

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

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

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

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

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

    内存访问的步骤:

    1570534108746

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

    1570534475405

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

    图解:

    1570535549903

    代码:

    // 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 ", g_out);
    system("pause");
    }

    效果:

    1570536186160

    蓝屏:

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

    解决蓝屏:

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

    所以 保存好 原来的pte值;

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

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

    1570536902006

    这个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 ", g_out);
    system("pause");
    }

    之后的效果:

    1570537359279

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

    2 有G属性的TLB 项

    查看 pte 有无G位:

    1570537552949

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

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

    1570538464730

    代码:

    // 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 ", g_out);
    system("pause");
    }

    测试结果:

    果然 G位的TLB 不会被 刷新出去:

    1570538889473

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

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

    1570539042616

    这时候 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位


  • 相关阅读:
    ansible入门七(实战)
    ansible入门六(roles)
    ansible入门五
    ansible入门四(Ansible playbook基础组件介绍)
    ansible入门三(Ansible的基础元素和YAML介绍)
    ansible入门二(Ansible常见模块介绍)
    关于XMLHttpRequest对象的responseText属性
    使用WebStorm/Phpstorm实现remote host远程开发
    pageX、clientX、screenX、offsetX、layerX、x
    jQuery.innerWidth() 函数详解
  • 原文地址:https://www.cnblogs.com/leibso-cy/p/11719268.html
Copyright © 2011-2022 走看看