逆向分析系统函数MmIsAddressValid(XP系统 10-10-12分页)
引言: 由于不能直接在代码中操作物理地址,因此系统提供了2个特殊的线性地址用于间接操作PDE和PTE。 PDT的线性地址 = 0xC0300000 + PDI*4 PTT的线性地址 = 0xC0000000 + PDI*4KB + PTI*4
.text:0040AF41 nop
.text:0040AF42 nop
.text:0040AF43 nop
.text:0040AF44 nop
.text:0040AF45 nop
.text:0040AF45
.text:0040AF46 ; Exported entry 685. MmIsAddressValid
.text:0040AF46
.text:0040AF46 ; =============== S U B R O U T I N E =======================================
.text:0040AF46
.text:0040AF46 ; Attributes: bp-based frame
.text:0040AF46
.text:0040AF46 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:0040AF46 public _MmIsAddressValid@4
.text:0040AF46 _MmIsAddressValid@4 proc near ; CODE XREF: MiMakeSystemAddressValidPfn(x)+C↓p
.text:0040AF46 ; MiDecrementShareCount(x)-493↓p
.text:0040AF46 ; MmFlushSection(x,x,x,x,x)+69↓p
.text:0040AF46 ; MiMakeSystemAddressValidPfnWs(x,x):loc_41ACA8↓p
.text:0040AF46 ; MiSegmentDelete(x)+D94B↓p
.text:0040AF46 ; MmPurgeSection(x,x,x,x)+E9B↓p
.text:0040AF46 ; MiMakeSystemAddressValidPfnSystemWs(x)+31↓p
.text:0040AF46 ; MiGatherMappedPages(x,x)+84↓p
.text:0040AF46 ; MiMovePageToEndOfStandbyList(x)+16↓p
.text:0040AF46 ; MmDbgCopyMemory(x,x,x,x,x)+87↓p
.text:0040AF46 ; MiSessionCommitImagePages(x,x)+19↓p
.text:0040AF46 ; MiRestoreTransitionPte(x)+20↓p
.text:0040AF46 ; MiCanFileBeTruncatedInternal(x,x,x,x)+2CEAC↓p
.text:0040AF46 ; MiWaitForInPageComplete(x,x,x,x,x,x)+2BC9F↓p
.text:0040AF46 ; MiMakeSystemAddressValidPfnSystemWs(x)+2B004↓p ...
.text:0040AF46
.text:0040AF46 VirtualAddress= dword ptr 8
.text:0040AF46
.text:0040AF46 ; FUNCTION CHUNK AT .text:0041EDB7 SIZE 00000007 BYTES
.text:0040AF46 ; FUNCTION CHUNK AT .text:0044F166 SIZE 00000019 BYTES
.text:0040AF46
.text:0040AF46 mov edi, edi
.text:0040AF48 push ebp ; mov edi, edi 是一种hot-patching
.text:0040AF49 mov ebp, esp
.text:0040AF4B mov ecx, [ebp+VirtualAddress] ; 取出线性地址
.text:0040AF4E mov eax, ecx
.text:0040AF50 shr eax, 14h ; 取出线性地址的高12位
.text:0040AF53 mov edx, 0FFCh ; 12位 111111111100
.text:0040AF58 and eax, edx ; 保留线性地址的高10位(PDI),将剩余2位置零(eax<<2) -> eax = PDI*4
.text:0040AF5A sub eax, 3FD00000h ; 通过位运算结果发现,该指令执行后的结果 = 0xC0300000+eax
.text:0040AF5F mov eax, [eax] ; 取出PDE
.text:0040AF61 test al, 1 ; 判断PDE的P位
.text:0040AF63 jz loc_41EDB7 ; P位!=1,则跳转到结束,返回0
.text:0040AF63
.text:0040AF69 test al, al ; 判断PDE的最高位是否为1
.text:0040AF6B js short loc_40AF91 ; 结果为负,表示PS==1,则跳转到结束,返回1
.text:0040AF6B
.text:0040AF6D shr ecx, 0Ah ; 取出线性地址的高22位
.text:0040AF70 and ecx, 3FFFFCh ; 通过位运算结果发现,该指令执行后的结果=PDI>>12 + PEI>>2 = PDI*4096+PTI*4 = ecx
.text:0040AF76 sub ecx, 40000000h ; 通过位运算结果发现,该指令执行后的结果 = 0xC0000000+ecx
.text:0040AF7C mov eax, ecx
.text:0040AF7E mov ecx, [eax] ; 取出PTE
.text:0040AF80 test cl, 1 ; 判断PTE的P位
.text:0040AF83 jz loc_41EDB7 ; P位!=1,则跳转到return
.text:0040AF83
.text:0040AF89 test cl, cl
.text:0040AF8B js loc_44F166 ; 判断PTE的PAT位,跳转后还有一层判断,有效返回1,无效返回0
.text:0040AF8B
.text:0040AF91
.text:0040AF91 loc_40AF91: ; CODE XREF: MmIsAddressValid(x)+25↑j
.text:0040AF91 ; MmIsAddressValid(x)+4422E↓j
.text:0040AF91 mov al, 1 ; 若线性地址有效,则通过eax返回1
.text:0040AF91
.text:0040AF93
.text:0040AF93 loc_40AF93: ; CODE XREF: MmIsAddressValid(x)+13E73↓j
.text:0040AF93 pop ebp
.text:0040AF94 retn 4
.text:0040AF94
.text:0040AF94 _MmIsAddressValid@4 endp
位运算分析:
.text:0040AF50 shr eax, 14h ; 取出线性地址的高12位
.text:0040AF53 mov edx, 0FFCh ; 12位 111111111100
.text:0040AF58 and eax, edx ; 保留线性地址的高10位(PDI),将剩余2位置零(eax<<2) -> eax = PDI*4
.text:0040AF5A sub eax, 3FD00000h ; 通过位运算结果发现,该指令执行后的结果 = 0xC0300000+eax
.text:0040AF50 shr eax, 14h ; eax==线性地址,将线性地址右移十进制20位,假设线性地址eax的所有位都是1
右移20位后的eax == 00000000000000000000111111111111
edx == 00000000000000000000111111111100
and eax, edx:00000000000000000000111111111100 -> 取出10位PDI,低两位为0表示PDI<<2,即eax == PDI*2^2
3FD00000h == 00111111110100000000000000000000
sub eax, 3FD00000h == 11000000001100000000111111111111 -> 运算结果
0xC0300000 == 11000000001100000000000000000000
运算结果:11000000001100000000111111111111 == 0xc0300000 + eax == 0xc0300000 + PDI*4
.text:0040AF6D shr ecx, 0Ah ; 取出线性地址的高22位
.text:0040AF70 and ecx, 3FFFFCh ; 通过位运算结果发现,该指令执行后的结果=PDI>>12 + PEI>>2 = PDI*4096+PTI*4 = ecx
.text:0040AF76 sub ecx, 40000000h ; 通过位运算结果发现,该指令执行后的结果 = 0xC0000000+ecx
.text:0040AF6D shr ecx, 0Ah ; ecx==线性地址,将线性地址右移十进制10位,假设线性地址ecx的所有位都是1
右移10位后的ecx == 00000000001111111111111111111111
3FFFFCh == 00000000001111111111111111111100
and ecx, 3FFFFCh == 00000000001111111111111111111100 -> 前10位PDI相当于左移12位,即PDI*2^12,低10位PTI相当于左移2位,即PTI*2^2
40000000h == 01000000000000000000000000000000
.text:0040AF76 sub ecx, 40000000h == 11000000001111111111111111111100 -> 运算结果
0xC0000000 == 11000000000000000000000000000000
运算结果:11000000001111111111111111111100 == 0xC0000000 + ecx == 0xC0000000 + PDI*4096 + PTI*4
总结: 系统函数MmIsAddressValid判断一个线性地址是有效: 首先通过线性地址的公式找到对应的PDE和PTE,然后判断PDE的P位和PS位,再判断PTE的P位和PAT位
逆向还原代码(未上机测试):
BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
{
dword PDI = (VirtualAddress >> 20) & 0FFCh;
dword PDE = *(dword*)(PDI - 3FD00000h);
// 判断PDE的P位
byte PDE_P = (byte)PDE & 0b00000001;
if (PDE_P != 1) {
return 0;
}
// 判断PDE的PS位
byte PDE_PS = (PDE>>7) & 1;
if (PDE_PS == 1) {
return 1;
}
// 判断PTE的P位
dword PTI = (VirtualAddress >> 10) & 3FFFFCh;
dword PTE = *(dword*)(PTI - 40000000h);
byte PTE_P = (byte)PTE & 0b00000001;
if (PTE_P != 1) {
return 0;
}
// 判断PTE的PAT位
byte PDE_PS = (PTE>>7) & 1;
if (PDE_PS == 1) {
if (){
return 0;
}
else {
return 1;
}
return 1;
}
return 1;
}