zoukankan      html  css  js  c++  java
  • X64下MmIsAddressValid的逆向及内存寻址解析

    标 题: 【原创】X64下MmIsAddressValid的逆向及内存寻址解析
    作 者: 普通朋友
    时 间: 2015-10-21,20:03:52
    链 接: http://bbs.pediy.com/showthread.php?t=205143

    在内核编程时,经常会用到MmIsAddressValid来检测地址是否有效,结合之前学过的虚拟地址到物理地址之间的转化,所以发一篇对该函数的逆向以及代码还原,x86的资料论坛以及网络有很多了,所以这里楼主只谈一下Win7 x64下的MmIsAddressValid过程分析

      要检测地址是否有效以及逆向MmIsAddressValid,还是得先从 x64下线性地址的格式入手


    点击图片以查看大图

图片名称:	1.jpg
查看次数:	18
文件大小:	40.0 KB
文件 ID :	100940

    为了方便起见,楼主只说一下最普通的4k分页的情况,其他的可以举一反三
    从这张图上,可以看到虽然线性地址有64位,但实际只用了48位,高16位其实是符号拓展位, 根据这高16位也可以做一个简单的内存地址是否有效判断(后面逆向会谈到)

    从上面这张图,可以看到线性地址被拆开成了五个部分, 还有四张表分别是:
    PML4T : 大小为4k ,每项8 字节 ,每一项指向PDPT的首地址
    PDPT  : 大小为4k ,每项8 字节 , 每一项指向PD的首地址
    PD  : 大小为4k ,每项8 字节 , 每一项指向PT的首地址
    PT: 大小为4k ,每项8 字节 , 每一项存放一个物理页

    如果从编程的角度来说,这四张表其实就是四个数组,数组的每一项可以看做是一个指针
    线性地址被拆开成了五个部分,前四个部分都可以看做是数组的下标

    举个例子,比如线性地址的39-47位,可以看做是一个Pml4t的下标Index,那么在代码里相当于
    Pml4t[Index * 8]这样的寻址
    其他的数组的访问依此类推

    最后在PT的数组里找到物理页后,再加上线性地址的低12位,便是最终的物理地址

    点击图片以查看大图

图片名称:	2.jpg
查看次数:	9
文件大小:	91.6 KB
文件 ID :	100941

    上面这张图是每一张表项的结构图,其中比较重要的是第0位,也就是P位,用于检测所指的页面或页表当前是否加载到了物理存储器中 ,p = 0即为无效

    了解了理论,再来手工解析一下
    随便写一个程序如下:
    名称:  3.jpg
查看次数: 0
文件大小:  5.7 KB

    字符串地址在0000000140092000
    字符串内容是NoteBook

    首先,对该虚拟地址做一个格式转化
    0     101       000000000        010010010       000000000000
    0      5        0          0x92              0
    由低到高分成了五个部分,前四个是四个数组的下标,最后的0是偏移

    第一步,找到该进程的CR3的值,也就是第一个表PML4T的首地址
    点击图片以查看大图

图片名称:	4.jpg
查看次数:	2
文件大小:	18.1 KB
文件 ID :	100943


    地址在4e37b000 处   ,注意,该地址是物理地址 ,并且根据格式,低十二位需要清0

    第二步,找到该进程PDPT 的首地址,根据之前的下标,得到在PML4T[0]处:
    名称:  5.jpg
查看次数: 1
文件大小:  17.8 KB
    对齐后,PDPT的首地址在4d1cc000处

    第三步,找到该进程PDT的首地址,根据之前的下标,得到在PDPT [5]处:
    名称:  6.jpg
查看次数: 0
文件大小:  18.2 KB

    对齐后,PDT的首地址在4d8cd000处


    第四步,找到该进程PT的首地址,根据之前的下标,得到在PDT [0]处:
    名称:  7.jpg
查看次数: 0
文件大小:  18.5 KB

    对齐后,PT的首地址在4de4e000处

    第五步,找到对应的物理页,根据之前的下标,得到在PT[0x92]处:
    名称:  8.jpg
查看次数: 0
文件大小:  17.5 KB

    对齐后,数据物理页在4cdfa000处

    最后一步,得到完整的物理地址:
    点击图片以查看大图

图片名称:	9.jpg
查看次数:	4
文件大小:	20.5 KB
文件 ID :	100948

    和程序中的字符串内容一样

    说了这么多,进入逆向MmIsAddressValid

    .text:00000001400AD930 _MmIsAddressValid proc near             .text:000000014000FB6E
    .text:00000001400AD930                                         
    .text:00000001400AD930                 mov     rax, rcx
    .text:00000001400AD933                 sar     rax, 48        
                                                     ;取得线性地址的   高16位
    .text:00000001400AD937                 inc     rax
    .text:00000001400AD93A                 cmp     rax, 1
    .text:00000001400AD93E                 ja      loc_1400AD9D3   
                                     ; 高16位要么全0, 要么全1 ,加一后大于1则不合法,直接返回false
    .text:00000001400AD944                 mov     rax, rcx
    .text:00000001400AD947                 mov     rdx, 0FFFFF6FB7DBED000h 
                                                         ; PML4T 的虚拟地址
    .text:00000001400AD951                 shr     rax, 39        
                                                       ; 将虚拟地址右移39位
    .text:00000001400AD955                 and     eax, 1FFh       
                                                       ; 拿到pml4数组的下标
    .text:00000001400AD95A                 test    byte ptr [rdx+rax*8], 1 
                                                     ; 检测PML4T项p位
    .text:00000001400AD95E                 jz      short loc_1400AD9D3 
                                                      ; p=0 则直接返回false
    .text:00000001400AD960                 mov     rax, rcx
    .text:00000001400AD963                 mov     rdx, 0FFFFF6FB7DA00000h
    .text:00000001400AD96D                 shr     rax, 27         
                                                    ; 右移30位 ,再 乘 8 ,相当于右移27位
    .text:00000001400AD971                 and     eax, 1FFFF8h    
                                                    ; 8字节对齐 得到PDPT的偏移
    .text:00000001400AD976                test    byte ptr [rax+rdx], 1
                                                   ; 检测PDPT项的p位 rax+rdx=PDPT的首地址
    .text:00000001400AD97A                jz      short loc_1400AD9D3
    .text:00000001400AD97C                 mov     rdx, -0FFFFF6FB40000000h
    .text:00000001400AD986                 mov     rax, rcx
    .text:00000001400AD989                 shr     rax, 18        
                                                      ; 右移21位,再乘8 ,相当于右移18位
    .text:00000001400AD98D                 and     eax, 3FFFFFF8h  
                                                       ;得到PDT的偏移
    .text:00000001400AD992                 sub     rax, rdx      
                                                     ; rax = rax + 0FFFFF6FB40000000h  
    .text:00000001400AD995                 mov     rdx, [rax]    
                                                    ;此时rax指向PDT中的 某一项
    .text:00000001400AD998                 test    dl, 1          
                                                      ; 检测PDT项p位
    .text:00000001400AD99B                 jz      short loc_1400AD9D3
    .text:00000001400AD99D                 test    dl, dl
    .text:00000001400AD99F                 js      short loc_1400AD9D6 
                                                         ; 是否开启PSE,是的话直接返回真
    .text:00000001400AD9A1                 shr     rcx, 9         
                                                        ; 右移12位,再乘 8 ,相当于右移9位
    .text:00000001400AD9A5                 mov     rax, 7FFFFFFFF8h ; 8字节对齐
    .text:00000001400AD9AF                 and     rcx, rax    
    .text:00000001400AD9B2                 mov     rax, -0FFFFF68000000000h
    .text:00000001400AD9BC                 sub     rcx, rax
    .text:00000001400AD9BF                 mov     rax, [rcx]  
                                                       ;此时RCX指向PT的的某一项
    .text:00000001400AD9C2                 test    al, 1
    .text:00000001400AD9C4                 jz      short loc_1400AD9D3
                                                       ; 检测PT项的P位
    .text:00000001400AD9C6                 mov     r8b, 80h
    .text:00000001400AD9C9                 and     al, r8b
    .text:00000001400AD9CC                 cmp     al, r8b
    .text:00000001400AD9CF                 setnz   al            
                                                      ; 检测PT项的PAT位是否存在,不存在返回真
    .text:00000001400AD9D2                 retn
    .text:00000001400AD9D3 ; ---------------------------------------------------------------------------
    .text:00000001400AD9D3
    .text:00000001400AD9D3 loc_1400AD9D3:                          
    .text:00000001400AD9D3                                         
    .text:00000001400AD9D3                 xor     al, al
    .text:00000001400AD9D5                 retn
    .text:00000001400AD9D6 ; ---------------------------------------------------------------------------
    .text:00000001400AD9D6
    .text:00000001400AD9D6 loc_1400AD9D6:                         _
    .text:00000001400AD9D6                 mov     al, 1
    .text:00000001400AD9D8                 retn
    .text:00000001400AD9D8 _MmIsAddressValid endp


    可以看出,函数也是将线性地址进行了拆分,取得表中每一项的值后,依次进行判断 ,主要是针对P位


    将以上代码做一个等价还原后如下:
    bool _MmIsAddressValid(void *pAddress)
    {
      BYTE* pMl4e = (BYTE *)0x0FFFFF6FB7DBED000;
      BYTE* pDPTE = (BYTE *)0x0FFFFF6FB7DA00000;
      BYTE* pDE = (BYTE *)0x0FFFFF6FB40000000;
      BYTE* pTE = (BYTE *)0x0FFFFF68000000000;
      BYTE* curItem;

      ULONG_PTR ulAddress = (ULONG_PTR)pAddress;

      ulAddress = ((LONG_PTR)ulAddress>>48) + 1;

      if (ulAddress <= 1)      //只要是合法地址,必然不会超过1
      {

        ulAddress = (ULONG_PTR)pAddress;
        ulAddress = ulAddress >> 39;
        ulAddress = ulAddress & 0x1ff;

        if ((pMl4e[ulAddress * 8] & 1) == 0)  //检测pMl4T项的P位
          return false;

        ulAddress = (ULONG_PTR)pAddress;
        ulAddress = (ulAddress >> 30) << 3;
        ulAddress = ulAddress & 0x1FFFF8;
        if ((pDPTE[ulAddress] & 1) == 0)  //检测PDPT项的P位
          return false;

        ulAddress = (ULONG_PTR)pAddress;
        ulAddress = (ulAddress >> 21) << 3;
        ulAddress = ulAddress & 0x3FFFFFF8;
        curItem = pDE + ulAddress;

        if ((*(LONG_PTR*)curItem & 1) == 0)  //检测PDT项的P位
          return false;
        if ((*(LONG_PTR*)curItem & 0xff) >= 0)    //PDT的PSE被置位,直接返回TRUE (2mb分页)
        {
          ulAddress = (ULONG_PTR)pAddress;
          ulAddress = (ulAddress >> 12) << 3;
          ulAddress = ulAddress & 0x7FFFFFFFF8;
          curItem = pTE + ulAddress;
          if ((*(LONG_PTR*)curItem & 1) == 0)  //检测PT项的P位
            return false;

          char itemTmp = (char)*(LONG_PTR*)curItem;
          itemTmp = itemTmp & 0x80;
          return (itemTmp == (char)0x80) ? false : true; //检测PT项的PAT位
        }else
          return true;
      }
        return false;
    }  

    jpg 改 rar
  • 相关阅读:
    Gson通过借助TypeToken类来解决这个问题
    学习心得
    java反射机制及Method.invoke方法(转载)
    IntentService源码分析
    android中一个app中的activity启动另外一个aar包中的activity
    android 动态加载
    eclispe的快捷键
    android sqlite数据库升级
    [C++] any number to binary (Bit manipulation)
    [C++] Sign and magnitude,Ones' complement and Two's complement
  • 原文地址:https://www.cnblogs.com/kuangke/p/5619302.html
Copyright © 2011-2022 走看看