-
-
[原创]逆向分析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虚拟机自动化脱壳的方法
赞赏
他的文章
看原图