练习逆向XP内核2-9-9-12和10-10-12分页的MmIsAddressValid函数
前言:这篇笔记记录逆向XP内核MmIsAddressValid函数的学习
这个MmIsAddressValid函数就是判断对一个传入的线性地址是否有效,这里的有效指的就是判断可以将其转换为对应的物理地址,那么其中肯定就有对应的PDE PTE,如果都存在的话,并且P位有效等,那么也就是一个有效的地址
这个函数里面还判断了相关的PDE的PS位,是否为大页,还有PTE的PAT位,这个PAT位后面还走了一个跳转的流程,这个不知道具体是干什么的
然后还有一个重要的知识点,就是通过逆向这个函数,你会发现操作系统在找线性地址对应的物理页的时候,它的整体流程,通过C0300000页目录基址,C0000000页表基址来进行寻找
如何寻找MmIsAddressValid内核函数的方法
知识点:
1、XP系统下的2-9-9-12分页模式通过内核文件ntkrnlpa.exe来进行观察
2、XP系统下的10-10-12分页模式通过内核文件ntoskrnl.exe来进行观察
都是逆向可以用两个工具一个是ida,一个是windbg,windbg的话直接u MmIsAddressValid L40
即可,如下图所示
因为当前XP是10-10-12分页下的,所以拿内核文件ntoskrnl.exe来进行分析,这里通过IDA来进行分析,ALT+T来进行全局搜索字符串MmIsAddressValid,
如下图所示,我这里用的是全局搜索字符串,或者直接在左边函数列表中Ctrl+F来搜索也可以
.text:0040AEC6 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress) .text:0040AEC6 public MmIsAddressValid .text:0040AEC6 MmIsAddressValid proc near ; CODE XREF: sub_40AF1C+C↓p .text:0040AEC6 ; sub_4129D8+2F5B↓p ... .text:0040AEC6 .text:0040AEC6 VirtualAddress = dword ptr 8 .text:0040AEC6 .text:0040AEC6 ; FUNCTION CHUNK AT .text:0041DDA5 SIZE 00000007 BYTES .text:0040AEC6 ; FUNCTION CHUNK AT .text:0044F150 SIZE 00000019 BYTES .text:0040AEC6 .text:0040AEC6 mov edi, edi .text:0040AEC8 push ebp .text:0040AEC9 mov ebp, esp .text:0040AECB mov ecx, [ebp+VirtualAddress] .text:0040AECE mov eax, ecx .text:0040AED0 shr eax, 14h .text:0040AED3 mov edx, 0FFCh .text:0040AED8 and eax, edx .text:0040AEDA sub eax, 3FD00000h .text:0040AEDF mov eax, [eax] .text:0040AEE1 test al, 1 .text:0040AEE3 jz loc_41DDA5 .text:0040AEE9 test al, al .text:0040AEEB js short loc_40AF11 .text:0040AEED shr ecx, 0Ah .text:0040AEF0 and ecx, 3FFFFCh .text:0040AEF6 sub ecx, 40000000h .text:0040AEFC mov eax, ecx .text:0040AEFE mov ecx, [eax] .text:0040AF00 test cl, 1 .text:0040AF03 jz loc_41DDA5 .text:0040AF09 test cl, cl .text:0040AF0B js loc_44F150 .text:0040AF11 .text:0040AF11 loc_40AF11: ; CODE XREF: MmIsAddressValid+25↑j .text:0040AF11 ; MmIsAddressValid+44298↓j .text:0040AF11 mov al, 1 .text:0040AF13 .text:0040AF13 loc_40AF13: ; CODE XREF: MmIsAddressValid+12EE1↓j .text:0040AF13 pop ebp .text:0040AF14 retn 4 .text:0040AF14 MmIsAddressValid endp ... ... .text:0044F150 ; START OF FUNCTION CHUNK FOR MmIsAddressValid .text:0044F150 .text:0044F150 loc_44F150: ; CODE XREF: MmIsAddressValid+45↑j .text:0044F150 and eax, edx .text:0044F152 mov eax, [eax-3FD00000h] .text:0044F158 and ax, 81h .text:0044F15C cmp al, 81h .text:0044F15E jnz loc_40AF11 .text:0044F164 jmp loc_41DDA5 .text:0044F164 ; END OF FUNCTION CHUNK FOR MmIsAddressValid
10-10-12分页逆向过程
位运算的知识点:
.text:0040AEED shr ecx, 0Ah .text:0040AEF0 and ecx, 3FFFFCh
对于这两条,我一开始看不懂,为什么这样的位运算可以使得PDI*4096+PTI*4
,然后我自己想了下,应该是获取10-10-12的 10 和10的时候,此时 >> 10
,相当于少右移了2位,那么整体多左移了2位,那么对于PDI的话,其实就是右移了12位也就是2^(10+2)
那么是*4096
,而对于PTI的话就是右移了2位也就是2^(0+2)
次,那么*4
思考
从这个函数的入口可以看到mov edi,edi
的指令,好像没什么用,因为下面都没看到有使用该寄存器,实际上是用到的:
参考文章:https://blog.csdn.net/swanabin/article/details/17550897
很明显,两个字节的MOV EDI,EDI
指令什么事情也不做?
那么,就有两个问题:
第一,为什么不直接从函数体开始而要从这条什么都不做的指令开始呢?
第二,即使需要在函数一开始空出两个字节,为什么不直接使用两条NOP指令,而要使用这条MOV指令呢?
在网上查阅一些资料后,得到了答案:
对于第一个问题,答案是为了实现hot-patching技术,即运行时修改一个函数的行为。修改过程如下:把MOV EDI, EDI修改为一条短跳转指令(一条短跳转指令恰好两个字节),把MOV EDI, EDI上面的五个NOP修改为一条长跳转指令(一条长跳转指令恰好五个字节),短跳转指令跳到长跳转指令上,长跳转指令跳到修改后的函数体上。
这个指令可以用在与0环交互的时候,比如中断门就需要两个字节,刚刚好满足条件,后面驱动篇章实现去写拷贝监控的项目中就会用到
参考文章: https://www.cnblogs.com/zpchcbd/p/15949802.html
对于第二个问题,答案是为了提高效率。执行一条MOV指令比执行两条NOP指令花费更少的时间。
注意点
逆向的时候可以看到,偏移有些写的是sub ecx, 40000000h
和sub eax, 3FD00000h
,实际上转换下为:
sub ecx, 40000000h
-> add ecx, C0000000h
sub eax, 3FD00000h
-> add eax, C0300000h
2-9-9-12分页逆向过程
这个是后面学了2-9-9-12以后补上的
2-9-9-12分页模式通过内核文件ntkrnlpa.exe来进行观察
同样的还是用IDA来进行分析
.text:0043CA48 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress) .text:0043CA48 public MmIsAddressValid .text:0043CA48 MmIsAddressValid proc near ; CODE XREF: sub_41ADD4+2F↑p .text:0043CA48 ; sub_41AE26+29↑p ... .text:0043CA48 .text:0043CA48 var_8 = dword ptr -8 .text:0043CA48 var_4 = dword ptr -4 .text:0043CA48 VirtualAddress = dword ptr 8 .text:0043CA48 .text:0043CA48 mov edi, edi ; hot-patching技术 .text:0043CA4A push ebp .text:0043CA4B mov ebp, esp .text:0043CA4D push ecx .text:0043CA4E push ecx .text:0043CA4F mov ecx, [ebp+VirtualAddress] ; ecx = VirtualAddress 也就是压入的线性地址 .text:0043CA52 push esi ; 保存原来的esi,后面需要用到esi作为计算 .text:0043CA53 mov eax, ecx ; eax = VirtualAddress .text:0043CA55 shr eax, 12h ; VirtualAddress = VirtualAddress >> 18 .text:0043CA58 mov esi, 3FF8h ; esi = 0x3FF8 .text:0043CA5D and eax, esi ; VirtualAddress = VirtualAddress & 0x3FF8 相当于获取的是PDPTEI*8*512+PDI*8 .text:0043CA5F sub eax, 3FA00000h ; eax = PDPTEI*8*512+PDI*8+0xC0600000,相当于拿到了PDE的地址 .text:0043CA64 mov edx, [eax] ; 获取PDE结构地址中存储的值 .text:0043CA66 mov eax, [eax+4] ; 获取当前PDE结构中得下一个PDE结构地址中存储的值 .text:0043CA69 mov [ebp+var_4], eax ; 把第二个获取的PDE结构地址中的值存储到堆栈中 .text:0043CA6C mov eax, edx ; eax = 第一个获取的PDE结构地址中存储的值 .text:0043CA6E push edi .text:0043CA6F and eax, 1 ; 判断是否第一个获取的PDE结构地址中存储的值,就可以判断当前PDE结构P位是否有效 .text:0043CA72 xor edi, edi .text:0043CA74 or eax, edi ; 判断是否当前PDE结构中的值是否为空 .text:0043CA76 jz short loc_43CAD9 ; 如果为空则结束 .text:0043CA78 mov edi, 80h .text:0043CA7D and edx, edi ; 判断PDE是否为大页,也就是判断PS位,第7位 .text:0043CA7F push 0 .text:0043CA81 mov [ebp+var_8], edx ; 判断PS位的结果存储到堆栈中 .text:0043CA84 pop eax ; 清空eax .text:0043CA85 jz short loc_43CA8B ; 如果不是大页,PS位不为1,那跳转到0x43CA8B进行处理 .text:0043CA87 test eax, eax .text:0043CA89 jz short loc_43CADD ; 如果走到这里,那么就肯定会跳转到43CADD,意味着这个函数的结束 .text:0043CA8B .text:0043CA8B loc_43CA8B: ; CODE XREF: MmIsAddressValid+3D↑j .text:0043CA8B shr ecx, 9 ; 下面是PDE PS位0 物理页为4kb的情况的处理,VirtualAddress = VirtualAddress >> 9 .text:0043CA8E and ecx, 7FFFF8h ; ecx相当于获取的是PDPTEI*512*512*8+PDI*8*512+PTI*8 .text:0043CA94 mov eax, [ecx-3FFFFFFCh] .text:0043CA9A sub ecx, 40000000h ; ecx = C0000000+PDPTEI*512*512*8+PDI*8*512+PTI*8 .text:0043CAA0 mov edx, [ecx] ; 获得指定的PTE结构地址中的值 .text:0043CAA2 mov [ebp+var_4], eax .text:0043CAA5 push ebx .text:0043CAA6 mov eax, edx ; edx = PTE结构地址中的值 .text:0043CAA8 xor ebx, ebx .text:0043CAAA and eax, 1 ; 判断有效位P .text:0043CAAD or eax, ebx ; 判断当前PTE结构中的值有没有 .text:0043CAAF pop ebx .text:0043CAB0 jz short loc_43CAD9 ; 如果没有值的话,那么函数结束 .text:0043CAB2 and edx, edi ; 判断PTE的PAT位,第7位 .text:0043CAB4 push 0 .text:0043CAB6 mov [ebp+var_8], edx .text:0043CAB9 pop eax .text:0043CABA jz short loc_43CADD ; 如果PAT位为0则跳转 .text:0043CABC test eax, eax ; 这个不知道再判断什么,但是这里的会正常来说不会跳转,一直往下走 .text:0043CABE jnz short loc_43CADD .text:0043CAC0 and ecx, esi ; PDE的地址 & 3FF8 看不太懂 .text:0043CAC2 mov ecx, [ecx-3FA00000h] ; (PDE的地址 & 3FF8) + 0xC0600000,这个不知道获得的是什么结构体,老师没讲过 .text:0043CAC8 mov eax, 81h .text:0043CACD and ecx, eax .text:0043CACF xor edx, edx .text:0043CAD1 cmp ecx, eax ; 同样也会判断第7位和第0位 .text:0043CAD3 jnz short loc_43CADD .text:0043CAD5 test edx, edx .text:0043CAD7 jnz short loc_43CADD .text:0043CAD9 .text:0043CAD9 loc_43CAD9: ; CODE XREF: MmIsAddressValid+2E↑j .text:0043CAD9 ; MmIsAddressValid+68↑j .text:0043CAD9 xor al, al .text:0043CADB jmp short loc_43CADF .text:0043CADD ; --------------------------------------------------------------------------- .text:0043CADD .text:0043CADD loc_43CADD: ; CODE XREF: MmIsAddressValid+41↑j .text:0043CADD ; MmIsAddressValid+72↑j ... .text:0043CADD mov al, 1 .text:0043CADF .text:0043CADF loc_43CADF: ; CODE XREF: MmIsAddressValid+93↑j .text:0043CADF pop edi .text:0043CAE0 pop esi .text:0043CAE1 leave .text:0043CAE2 retn 4 .text:0043CAE2 MmIsAddressValid endp
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2020-02-20 反汇编:循环
2020-02-20 反汇编:函数嵌套调用