首页
社区
课程
招聘
[原创]逆向分析MmIsAddressValid函数2-9-9-12分页
2023-8-12 12:05 1836

[原创]逆向分析MmIsAddressValid函数2-9-9-12分页

2023-8-12 12:05
1836

1、逆向分析XP系统2-9-9-12分页模式下,内核文件ntkrnlpa.exe中的MmIsAddressValid函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
Exported entry 685. MmIsAddressValid
.text:0043C928
.text:0043C928 ; =============== S U B R O U T I N E =======================================
.text:0043C928
.text:0043C928 ; Attributes: bp-based frame
.text:0043C928
.text:0043C928 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:0043C928 public _MmIsAddressValid@4
.text:0043C928 _MmIsAddressValid@4 proc near ; CODE XREF: IopIsAddressRangeValid(x,x)+2F↑p
.text:0043C928                               ; IopGetMaxValidMemorySize(x,x)+29↑p
.text:0043C928                               ; IoSetDumpRange(x,x,x,x)+56↑p
.text:0043C928                               ; IoFreeDumpRange(x,x,x,x)+4C↑p
.text:0043C928                               ; IopWriteDriverList(x,x,x,x)+8F↑p
.text:0043C928                               ; IopInvokeDumpIoCallbacks(x,x,x)+56↑p
.text:0043C928                               ; IopInvokeDumpIoCallbacks(x,x,x)+AB↑p
.text:0043C928                               ; sub_41B7E6+13↑p
.text:0043C928                               ; KeCapturePersistentThreadState(x,x,x,x,x,x,x,x)+49A↑p
.text:0043C928                               ; IopInvokeSecondaryDumpDataCallbacks(x,x,x,x,x,x,x,x,x)+BA↑p
.text:0043C928                               ; IopInvokeSecondaryDumpDataCallbacks(x,x,x,x,x,x,x,x,x)+120↑p
.text:0043C928                               ; KiPcToFileHeader(x,x,x,x)+2C↑p
.text:0043C928                               ; KiDumpParameterImages(x,x,x,x)+7A↑p
.text:0043C928                               ; KiScanBugCheckCallbackList()+3C↑p
.text:0043C928                               ; KiInvokeBugCheckEntryCallbacks()+50↑p ...
.text:0043C928
.text:0043C928 var_8= dword ptr -8
.text:0043C928 var_4= dword ptr -4
.text:0043C928 VirtualAddress= dword ptr  8
.text:0043C928
.text:0043C928 mov     edi, edi
.text:0043C92A push    ebp
.text:0043C92B mov     ebp, esp
.text:0043C92D push    ecx
.text:0043C92E push    ecx
.text:0043C92F mov     ecx, [ebp+VirtualAddress] ; 取出线性地址
.text:0043C932 push    esi
.text:0043C933 mov     eax, ecx
.text:0043C935 shr     eax, 12h              ; 线性地址右移18位,移除了12位物理页偏移和PTI的低6位
.text:0043C938 mov     esi, 3FF8h            ; 0000 0000 0000 0000 0011 1111 1111 1000
.text:0043C93D and     eax, esi              ; 与运算后,保留了2位PDPTI和9位PDI。最后3位为0的作用:1.移除PTI的高3位。2.PDI<<3。3.POPTI<<12
.text:0043C93F sub     eax, 3FA00000h        ; 运算结果 eax = 0xC0600000 + PDPTI*4KB + PDI*8
.text:0043C944 mov     edx, [eax]            ; edx = PDE低4字节
.text:0043C946 mov     eax, [eax+4]          ; eax = PDE高4字节
.text:0043C949 mov     [ebp+var_4], eax      ; 局部变量1 = PDE高4字节
.text:0043C94C mov     eax, edx              ; eax = PDE低4字节
.text:0043C94E push    edi
.text:0043C94F and     eax, 1                ; 取出PDE低4字节中的P位
.text:0043C952 xor     edi, edi              ; edi = 0
.text:0043C954 or      eax, edi              ; 判断P位是否为0
.text:0043C956 jz      short loc_43C9B9      ; if P==0,则 return 0
.text:0043C956
.text:0043C958 mov     edi, 80h              ; 1000 0000
.text:0043C95D and     edx, edi              ; 取出PDE低4字节中的PS位
.text:0043C95F push    0
.text:0043C961 mov     [ebp+var_8], edx      ; 局部变量2 = PDE低4字节中的PS位
.text:0043C964 pop     eax                   ; eax = 0
.text:0043C965 jz      short loc_43C96B      ; PS位 == 0,跳转到判断小页代码
.text:0043C965
.text:0043C967 test    eax, eax              ; 判断eax==0
.text:0043C969 jz      short loc_43C9BD      ; if PS位 == 1, 则 return 1
.text:0043C969
.text:0043C96B
.text:0043C96B loc_43C96B:                   ; CODE XREF: MmIsAddressValid(x)+3D↑j
.text:0043C96B shr     ecx, 9                ; 线性地址右移9位。
.text:0043C96E and     ecx, 7FFFF8h          ; 7FFFF8 = 0000 0000 0111 1111 1111 1111 1111 1000
.text:0043C96E                               ; 与运算后,保留2位PDPTI<<21,9位PDI<<12,9位PTI<<3
.text:0043C974 mov     eax, [ecx-3FFFFFFCh]  ; ecx-3FFFFFFC = 0xC0000000 + PDPTI*2MB + PDI*4KB + PTI*8; eax = PTE高4字节
.text:0043C97A sub     ecx, 40000000h
.text:0043C980 mov     edx, [ecx]            ; edx = PTE低4字节
.text:0043C982 mov     [ebp+var_4], eax      ; 局部变量1 = PTE高4字节
.text:0043C985 push    ebx
.text:0043C986 mov     eax, edx              ; eax = PTE低4字节
.text:0043C988 xor     ebx, ebx              ; ebx = 0
.text:0043C98A and     eax, 1                ; 取出PTE低4字节中的P位
.text:0043C98D or      eax, ebx              ; 判断P位是否为0
.text:0043C98F pop     ebx
.text:0043C990 jz      short loc_43C9B9      ; if P == 0, 则 return 0
.text:0043C990
.text:0043C992 and     edx, edi              ; 判断PTE低4字节中的PAT位
.text:0043C994 push    0
.text:0043C996 mov     [ebp+var_8], edx      ; 局部变量2 = PAT位
.text:0043C999 pop     eax
.text:0043C99A jz      short loc_43C9BD      ; if PAT == 0, 则 return 1
.text:0043C99A
.text:0043C99C test    eax, eax
.text:0043C99E jnz     short loc_43C9BD      ; 下面代码是PAT == 1的情况
.text:0043C99E
.text:0043C9A0 and     ecx, esi              ; PTE的低4字节线性地址 and 0000 0000 0000 0000 0011 1111 1111 1000
.text:0043C9A2 mov     ecx, [ecx-3FA00000h]
.text:0043C9A8 mov     eax, 81h
.text:0043C9AD and     ecx, eax
.text:0043C9AF xor     edx, edx
.text:0043C9B1 cmp     ecx, eax
.text:0043C9B3 jnz     short loc_43C9BD
.text:0043C9B3
.text:0043C9B5 test    edx, edx
.text:0043C9B7 jnz     short loc_43C9BD
.text:0043C9B7
.text:0043C9B9
.text:0043C9B9 loc_43C9B9:                   ; CODE XREF: MmIsAddressValid(x)+2E↑j
.text:0043C9B9                               ; MmIsAddressValid(x)+68↑j
.text:0043C9B9 xor     al, al
.text:0043C9BB jmp     short loc_43C9BF
.text:0043C9BB
.text:0043C9BD ; ---------------------------------------------------------------------------
.text:0043C9BD
.text:0043C9BD loc_43C9BD:                   ; CODE XREF: MmIsAddressValid(x)+41↑j
.text:0043C9BD                               ; MmIsAddressValid(x)+72↑j
.text:0043C9BD                               ; MmIsAddressValid(x)+76↑j
.text:0043C9BD                               ; MmIsAddressValid(x)+8B↑j
.text:0043C9BD                               ; MmIsAddressValid(x)+8F↑j
.text:0043C9BD mov     al, 1
.text:0043C9BD
.text:0043C9BF
.text:0043C9BF loc_43C9BF:                   ; CODE XREF: MmIsAddressValid(x)+93↑j
.text:0043C9BF pop     edi
.text:0043C9C0 pop     esi
.text:0043C9C1 leave
.text:0043C9C2 retn    4
.text:0043C9C2
.text:0043C9C2 _MmIsAddressValid@4 endp

2、总结3点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1. (PDE)线性地址>>18 & 3FF8h - 3FA00000h
.text:0043C935 shr     eax, 12h              ; 线性地址右移18位,移除了12位物理页偏移和PTI的低6位
.text:0043C938 mov     esi, 3FF8h            ; 3FF8h = 0000 0000 0000 0000 0011 1111 1111 1000
.text:0043C93D and     eax, esi              ; 与运算后,保留了2位PDPTI和9位PDI和3位0
                                            3FF8h 最后3位为0的作用:1.移除PTI剩余的高3位。2.PDI<<3 == PDI*8。3.PDPTI<<12 == PDPTI*4KB
                                            eax = PDPTI*4KB + PDI*8
.text:0043C93F sub     eax, 3FA00000h        ; 运算结果 eax = 0xC0600000 + PDPTI*4KB + PDI*8
 
2. (PTE)线性地址>>9 & 7FFFF8h - 3FFFFFFCh
.text:0043C96B shr     ecx, 9                ; 线性地址右移9位,移除了12位物理页偏移的低9位
.text:0043C96E and     ecx, 7FFFF8h          ; 7FFFF8 = 0000 0000 0111 1111 1111 1111 1111 1000
.text:0043C96E                               ; 与运算后,保留2位PDPTI,9位PDI,9位PTI,3位0
                                            7FFFF8h 最后3位为0的作用:
                                            1.移除物理页偏移的高3位。2.PDPTI<<21 == PDPTI*2MB。3.PDI<<12 == PDI*4KB。4.PTI<<3 == PTI*8
.text:0043C974 mov     eax, [ecx-3FFFFFFCh]  ; PTE高4字节的线性地址 = ecx-3FFFFFFC = 0xC0000000 + PDPTI*2MB + PDI*4KB + PTI*8
.text:0043C97A sub     ecx, 40000000h      
.text:0043C980 mov     edx, [ecx]       
                                         上面两条指令等价于 <==> mov edx, [ecx - 3FFFFFFCh - 4]    
                                             为什么 [ecx-3FFFFFFCh]是PTE高4字节,[ecx - 3FFFFFFCh - 4] 是PTE低4字节?
                                             首先,当前数据是按照小尾方式存储的,即高字节存储在高地址。
                                          其次,PTE是由8个字节组成,前4个字节是低位,存储在低地址。后4个字节是高位,存在高地址。
                                          -3FFFFFFCh == 0xC0000004,-40000000h == 0xC0000000
                                          所以,[ecx-3FFFFFFCh]是PTE高4字节,[ecx - 3FFFFFFCh - 4] 是PTE低4字节
  
     
 3.对比分析我的C源码解析PTE线性地址和内核文件中MmIsAddressValid函数有何区别
    我的c源码:
     // 拆分变量x的线性地址 2-9-9-12分页
    int lineAddress = (int)ptr_x;
    int PDPTI_x = lineAddress >> 30;
    int PDI_x = (lineAddress & 0x3FE00000) >> 21;
    int PTI_x = (lineAddress & 0x1FF000) >> 12;
    int offset_x = lineAddress & 0xFFF;
    // 获取变量x的pPTE
    pPET_x = 0xC0000000 + PDPTI_x * (2 << 21) + PDI_x * (2 << 12) + PTI_x * 8;
     
    MmIsAddressValid函数中的源码:
    PDE = 线性地址>>18 & 3FF8h - 3FA00000h
    PTE = 线性地址>>9 & 7FFFF8h - 3FFFFFFCh
         
    由此可见,该内核函数全是按位操作和减法运算,性能上要优于我们的C代码。

3、错误修复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
3. 解释一下上一篇文章当中PTE的高4字节和低4字节
错误版:
上一章C代码实现NULL挂载PTE中获取PDE的部分源码如下:
    // 读高2G内容:变量x的PTE
    // 0x00401120
    void __declspec(naked) ReadXPTE() {
 
        __asm {
            //  int 3;
 
            push eax;
 
            mov eax, dword ptr ds:[pPET_x];              // 取出全局变量的值
            mov eax, dword ptr ds:[eax];                    // 取出PTE的高4字节
            mov dword ptr ds:[PTE_x_high], eax;       // 将PTE的高4字节复制给全局变量PTE_x_high
 
            mov eax, dword ptr ds:[pPET_x];             // 取出全局变量的值
            mov eax, dword ptr ds:[eax+4];              // 取出PTE的低4字节
            mov dword ptr ds:[PTE_x_low], eax;       // 将PTE的低4字节复制给全局变量PTE_x_low
 
            pop eax;
            iretd;
        }
    }
    上述代码中[eax]是PTE高4字节的线性地址,[eax+4]是PTE低4字节的线性地址
     
         
    // 挂载PTE
    // 0x00401050
    void __declspec(naked) WriteNULLPTE() {
 
        __asm {
            //  int 3;
 
            push eax;
 
            mov eax, dword ptr ds:[PTE_x_high];         // 将PTE的高4字节挂载到NULL的高4字节位
            mov dword ptr ds:[0xC0000000], eax;
 
            mov eax, dword ptr ds:[PTE_x_low];          // 将PTE的低4字节挂载到NULL的低4字节位
            mov dword ptr ds:[0xC0000000+4], eax;
 
            pop eax;
            iretd;
        }
    }
    上述代码中[0xC0000000]是空指针的PTE的高4字节的线性地址,[0xC0000000+4]是空指针的PTE的低4字节的线性地址
         
   更正版:    
    // 读高2G内容:变量x的PTE
    // 0x00401120
    void __declspec(naked) ReadXPTE() {
 
        __asm {
            //  int 3;
 
            push eax;
 
            mov eax, dword ptr ds:[pPET_x];              // 取出全局变量的值
            mov eax, dword ptr ds:[eax];                    // 取出PTE低4字节
            mov dword ptr ds:[PTE_x_low], eax;        // 将PTE的低4字节复制给全局变量PTE_x_low
 
            mov eax, dword ptr ds:[pPET_x];             // 取出全局变量的值
            mov eax, dword ptr ds:[eax+4];              // 取出PTE高4字节
            mov dword ptr ds:[PTE_x_high], eax;      // 将PTE高4字节复制给全局变量PTE_x_high
 
            pop eax;
            iretd;
        }
    }
    上述代码中[eax]是PTE低4字节的线性地址,[eax+4]是PTE高4字节的线性地址
 
    // 挂载PTE
    // 0x00401050
    void __declspec(naked) WriteNULLPTE() {
 
        __asm {
            //  int 3;
 
            push eax;
 
            mov eax, dword ptr ds:[PTE_x_low];          // 将PTE的低4字节挂载到NULL的低4字节位
            mov dword ptr ds:[0xC0000000], eax;
 
            mov eax, dword ptr ds:[PTE_x_high];         // 将PTE的高4字节挂载到NULL的高4字节位
            mov dword ptr ds:[0xC0000000+4], eax;
 
            pop eax;
            iretd;
        }
    }
    上述代码中[0xC0000000]是空指针的PTE的低4字节的线性地址,[0xC0000000+4]是空指针的PTE的高4字节的线性地址
         
    错误原因已经在总结当中解释。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回