zoukankan      html  css  js  c++  java
  • TLB机制

     Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

    TLB

    1. CPU寻址模式

    2. TLB

    3. 缓存

    4. shadowwalk技术

    5.TLB感知实验

    6.全局页

    1. CPU寻址模式

      之前在分页时介绍过这张图,里面分析过其对应的寻址模式:

      1)CPU先尝试从TLB找到物理地址;

      2)如果TLB中不存在对应的物理地址,则手动计算出物理地址;

      3)之后再从缓存中尝试获取物理地址对应的数据;

      4)如果缓存中没有,则去物理内存中找到相应地址来读取对应的数据。

      

    2. TLB

      TLB与缓存要区分清楚,TLB是通过线性地址找物理地址的,缓存是通过物理地址找数据的。

      TLB中以页为单位来存储的,缓存直接按照字节来进行存储的,要区分他俩之间的关系,不要混为一谈。

     

    3. 缓存

      以三级缓存为例,当一级缓存满了之后会往二级缓存中存储,二级满了会往三级缓存中存储,三级缓存定期备份到物理内存中。

      

     

    4. shadowwalk技术

      有很多游戏等会存在CRC校验,其读取的是数据TLB,但执行的是指令TLB,因此我们保留数据TLB,修改指令TLB,这样就实现了过CRC校验。

      shadowwalk等工具就是利用TLB的两张表分离实现过CRC校验的。

     

    5.TLB感知实验

      1)实验大体步骤

        ① 准备两个地址,在不同的页上;

        ② 向零地址挂上TLB,

        ③ 读取数据,加载到TLB中;

        ④ 再向0地址挂另一个物理页的PTE;

        ⑤ 我再读零地址,如果读出来的还是原来的数据,则证明存在TLB。

      2)实验代码:

        如下,我们利用windbg创建调用门:eq 8003f048 0040ec00`00081005

    // 123.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <windows.h>
    #include <stdlib.h>
    
    char* p = NULL;
    char* p1 = NULL;
    int temp = 0;
    int temp1 = 0;
    
    // eq 8003f048 0040ec00`00081005
    void __declspec(naked)test(){
        _asm{
    
            pushfd;
            pushad;
            push fs;
            mov ax,0x30;
            mov fs,ax;
            // 挂p位的
            mov eax,dword ptr ds:[p]; // 取出p的地址
            shr eax,9; // 由移9位
            and eax,0x7FFFF8; // 
            add eax,0xc0000000;
            // 取出pte    
            mov ebx,dword ptr [eax]; 
            mov ecx,[eax+4];
            // 往0地址挂
            mov dword ptr ds:[0xc0000000],ebx;
            mov dword ptr ds:[0xc0000004],ecx;
            // 加载到tlb中
            mov eax, dword ptr ds:[0];
            //int 3;
            //取出值
            mov temp,eax;
    
            /*---------------*/
    
            // 挂p1的
            mov eax,dword ptr[p1]; // 取出p1的地址
            shr eax,9; // 由移9位
            and eax,0x7FFFF8; // 
            add eax,0xc0000000;
            // 取出pte
            mov ebx,dword ptr [eax]; 
            mov ecx,[eax+4];
            // 往0地址挂
            mov dword ptr ds:[0xc0000000],ebx;
            mov dword ptr ds:[0xc0000004],ecx;
            // 加载到tlb中
            mov eax, dword ptr ds:[0];
            // 取出值
            mov temp1,eax;
            //int 3;
    
            pop fs;
            popad;
            popfd;
            retf;
        }
    }
    
    int main(int argc, char* argv[])
    {
        // 分配内存
        p = (char*)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        p1 = (char*)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        char buf[]={0,0,0,0,0x48,0};
        printf("%x,p1=%x,p=%x
    ",test,p1,p);
        system("pause");
        temp = 100;
        temp1 = 200;
        *(int*)p = 0x1000;
        *(int*)p1 = 0x2000;
    
        _asm{
            call fword ptr buf;
        }
        printf("%x,%x	
    ",temp,temp1);
        printf("hello world!
    ");
        system("pause");
        return 0;
    }

      3)实验结果:

        实验结果如下,可以发现第二次虽然我们在0地址处手工挂靠了物理页,但其因为第一次保存在TLB缓存当中,当第二次再开始读取的时候,通过TLB获取第一个PTE的线性地址,因此读到的是第一个。

        因此通过这个实验你就可以感知到TLB缓存的存在,下面我们学习如何刷新TLB缓存。

        

       4)TLB刷新

        如何刷新TLB呢?其如果刷新cr3,则就刷新TLB,因此我们如果想刷新,写上 mov eax,cr3; mov cr3,eax即可。

        

     

    6.全局页

      1)将其修改为全局页

        如果将页置为全局页,则需要修改PTE的第8位,G位,表示全局页。

        

        因此我们在写入PTE前,使用 or ebx,0x100将该位置1,哪怕再刷新CR3也没有效果。

        

      2)通过cr4来禁止修改全局页

        cr4存在一个PGE位,当该位为1,则允许使用全局页,现在我们将该位关掉。

        

        因为在vc6.0环境下不支持cr4的修改,因此我们借助IDA来直接硬编码:

    // cr4 PGE位关闭全局页
    
    __emit 0x0f; // mov eax,cr4;
    __emit 0x20;
    __emit 0xE0;
    
    mov ecx,0x80;
    not ecx;
    and eax,ecx;
    
    __emit 0x0f; // mov cr4,eax;
    __emit 0x22;
    __emit 0xe0; 

      之后我们发现及时设置全局页,其也是无效的,会被置换出来

      

      其实CPU中存在一个强制刷新地址的指令,哪怕是全局页表也会被刷新

      invlpg dword ptr ds:[0],使用该条指令则会强制刷新缓存

    全部试验代码如下:

    // 123.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <windows.h>
    #include <stdlib.h>
    
    char* p = NULL;
    char* p1 = NULL;
    int temp = 0;
    int temp1 = 0;
    
    // eq 8003f048 0040ec00`00081005
    void __declspec(naked)test(){
        _asm{
    
            pushfd;
            pushad;
            push fs;
            mov ax,0x30;
            mov fs,ax;
            // 挂p位的
            mov eax,dword ptr ds:[p]; // 取出p的地址
            shr eax,9; // 由移9位
            and eax,0x7FFFF8; // 
            add eax,0xc0000000;
            // 取出pte    
            mov ebx,dword ptr [eax]; 
            mov ecx,[eax+4];
            // 往0地址挂
            xor ebx,0x100;
            mov dword ptr ds:[0xc0000000],ebx;
            mov dword ptr ds:[0xc0000004],ecx;
            // 加载到tlb中
            mov eax, dword ptr ds:[0];
            //int 3;
            //取出值
            mov temp,eax;
    
            mov eax,cr3;
            mov cr3,eax;
            /*---------------*/
    
            // cr4 PGE位关闭全局页
            /*
            __emit 0x0f; // mov eax,cr4;
            __emit 0x20;
            __emit 0xE0;
    
            mov ecx,0x80;
            not ecx;
            and eax,ecx;
    
            __emit 0x0f; // mov cr4,eax;
            __emit 0x22;
            __emit 0xe0;
            */
    
    
            // 挂p1的
            mov eax,dword ptr[p1]; // 取出p1的地址
            shr eax,9; // 由移9位
            and eax,0x7FFFF8; // 
            add eax,0xc0000000;
            // 取出pte
            mov ebx,dword ptr [eax]; 
            mov ecx,[eax+4];
            // 往0地址挂
            mov dword ptr ds:[0xc0000000],ebx;
            mov dword ptr ds:[0xc0000004],ecx;
            // 加载到tlb中
            invlpg dword ptr ds:[0];
            mov eax, dword ptr ds:[0];
            // 取出值
            mov temp1,eax;
            //int 3;
            pop fs;
            popad;
            popfd;
            retf;
        }
    }
    
    int main(int argc, char* argv[])
    {
        // 分配内存
        p = (char*)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        p1 = (char*)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        char buf[]={0,0,0,0,0x48,0};
        printf("%x,p1=%x,p=%x
    ",test,p1,p);
        system("pause");
        temp = 100;
        temp1 = 200;
        *(int*)p = 0x1000;
        *(int*)p1 = 0x2000;
    
        _asm{
            call fword ptr buf;
        }
        printf("%x,%x	
    ",temp,temp1);
        printf("hello world!
    ");
        system("pause");
        return 0;
    }
  • 相关阅读:
    @终极解密输入网址按回车到底发生了什么
    jgitflow-maven-plugin报错:The authenticity of host can't be established.
    java log4j2日志行号不显示问题
    Prometheus监控之grafana常用模板编号记录
    DM数据守护
    使用IntelliJ IDEA 配置Maven(入门)
    IntelliJ IDEA lombok插件的安装和使用
    idea svn连接https报错问题: E230001: Server SSL certificate verification failed: certificate issued
    SVN安装后,右键不显示SVN菜单项
    IntelliJ IDEA怎么配置svn,集成svn方法
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12738275.html
Copyright © 2011-2022 走看看