这两天想做点坏事,也没啥,就是PTE欺骗啦。
其中涉及了VirtualAddress(VA)转化PhysicalAddress(PA)的生成原理。
于是网上找了些相关资料,很努力地看。
但看来看去,怎么和MmGetPhysicalAddress逆向结果不大一样啊。
这才发现,大部分现存的资料都很旧了。虽然应用原理还是差不多,但是已经不能被我们伸手党使用了。
于是决定逆向一下MmGetPhysicalAddress,再正向它,尝试C++实现之。
----_HARDWARE_PTE结构
代码:
lkd> dt _hardware_pte nt!_HARDWARE_PTE +0x000 Valid : Pos 0, 1 Bit +0x000 Write : Pos 1, 1 Bit +0x000 Owner : Pos 2, 1 Bit +0x000 WriteThrough : Pos 3, 1 Bit +0x000 CacheDisable : Pos 4, 1 Bit +0x000 Accessed : Pos 5, 1 Bit +0x000 Dirty : Pos 6, 1 Bit +0x000 LargePage : Pos 7, 1 Bit +0x000 Global : Pos 8, 1 Bit +0x000 CopyOnWrite : Pos 9, 1 Bit +0x000 Prototype : Pos 10, 1 Bit +0x000 reserved0 : Pos 11, 1 Bit +0x000 PageFrameNumber : Pos 12, 26 Bits +0x000 reserved1 : Pos 38, 26 Bits +0x000 LowPart : Uint4B +0x004 HighPart : Uint4B
代码:
typedef struct _HARDWARE_PTE_X86PAE { union { struct { ULONGLONG Valid:1; ULONGLONG Write:1; ULONGLONG Owner:1; ULONGLONG WriteThrough:1; ULONGLONG CacheDisable:1; ULONGLONG Accessed:1; ULONGLONG Dirty:1; ULONGLONG LargePage:1; ULONGLONG Global:1; ULONGLONG CopyOnWrite:1; ULONGLONG Prototype:1; ULONGLONG reserved0:1; ULONGLONG PageFrameNumber:26; ULONGLONG reserved1:26; }; struct { ULONG LowPart; ULONG HighPart; }; }; } HARDWARE_PTE_X86PAE, *PHARDWARE_PTE_X86PAE,MMPTE_HARDWARE, *PMMPTE_HARDWARE,_MMPTE_HARDWARE,HARDWARE_PTE,*PHARDWARE_PTE;
之前我做PTE结构时,使用ulong来做位域,无论是否强制结构体对齐,结果编译器硬要把这个结构识别为3 byte。汗死。
直到后面xIkUg大哥提供旧式结构体后,我才发现之间的差异。
不过xIkUg大哥提供的PTE结构指明PageFrameNumber:24;很奇怪。我在XP和2003上列表的结构都指明PageFrameNumber:26。所以,在实际应用时,大家还是用windbg看看自己的pte结构好了。免得出现意外。
----MmGetPhysicalAddress的IDA结果
代码:
;Microsoft Windows XP Professional Service Pack 3 [ver 5.1.2600] ;ntkrnlpa.exe ;MD5 : E7E72F0935D0F224768126B49CF2A9E8 .text:00430CD2 _MmGetPhysicalAddress@4 proc near ; CODE XREF: IoSetDumpRange(x,x,x,x)+22p .text:00430CD2 ; IoSetDumpRange(x,x,x,x)+62p ... .text:00430CD2 .text:00430CD2 BaseAddress = dword ptr 8 .text:00430CD2 .text:00430CD2 8B FF mov edi, edi .text:00430CD4 55 push ebp .text:00430CD5 8B EC mov ebp, esp .text:00430CD7 53 push ebx .text:00430CD8 56 push esi .text:00430CD9 57 push edi .text:00430CDA 8B 7D 08 mov edi, [ebp+BaseAddress] .text:00430CDD 8B CF mov ecx, edi .text:00430CDF C1 E9 12 shr ecx, 12h .text:00430CE2 81 E1 F8 3F 00 00 and ecx, 3FF8h .text:00430CE8 8B 81 00 00 60 C0 mov eax, [ecx+0C0600000h] .text:00430CEE 8B 89 04 00 60 C0 mov ecx, [ecx+0C0600004h] .text:00430CF4 BE 81 00 00 00 mov esi, 81h .text:00430CF9 8B D0 mov edx, eax .text:00430CFB 23 D6 and edx, esi .text:00430CFD 33 DB xor ebx, ebx .text:00430CFF 3B D6 cmp edx, esi .text:00430D01 75 1F jnz short loc_430D22 .text:00430D03 85 DB test ebx, ebx .text:00430D05 75 1B jnz short loc_430D22 .text:00430D07 0F AC C8 0C shrd eax, ecx, 0Ch .text:00430D0B C1 E9 0C shr ecx, 0Ch .text:00430D0E 8B CF mov ecx, edi .text:00430D10 C1 E9 0C shr ecx, 0Ch .text:00430D13 25 FF FF FF 03 and eax, 3FFFFFFh .text:00430D18 81 E1 FF 01 00 00 and ecx, 1FFh .text:00430D1E 03 C1 add eax, ecx .text:00430D20 EB 3F jmp short loc_430D61 .text:00430D22 ; --------------------------------------------------------------------------- .text:00430D22 .text:00430D22 loc_430D22: ; CODE XREF: MmGetPhysicalAddress(x)+2Fj .text:00430D22 ; MmGetPhysicalAddress(x)+33j .text:00430D22 83 E0 01 and eax, 1 .text:00430D25 33 C9 xor ecx, ecx .text:00430D27 0B C1 or eax, ecx .text:00430D29 74 24 jz short loc_430D4F .text:00430D2B 8B CF mov ecx, edi .text:00430D2D C1 E9 09 shr ecx, 9 .text:00430D30 81 E1 F8 FF 7F 00 and ecx, 7FFFF8h .text:00430D36 8B 91 04 00 00 C0 mov edx, [ecx+0C0000004h] .text:00430D3C 81 E9 00 00 00 40 sub ecx, -0C0000000h .text:00430D42 8B 01 mov eax, [ecx] .text:00430D44 8B C8 mov ecx, eax .text:00430D46 83 E1 01 and ecx, 1 .text:00430D49 33 F6 xor esi, esi .text:00430D4B 0B CE or ecx, esi .text:00430D4D 75 06 jnz short loc_430D55 .text:00430D4F .text:00430D4F loc_430D4F: ; CODE XREF: MmGetPhysicalAddress(x)+57j .text:00430D4F 33 C0 xor eax, eax .text:00430D51 33 D2 xor edx, edx .text:00430D53 EB 1F jmp short loc_430D74 .text:00430D55 ; --------------------------------------------------------------------------- .text:00430D55 .text:00430D55 loc_430D55: ; CODE XREF: MmGetPhysicalAddress(x)+7Bj .text:00430D55 0F AC D0 0C shrd eax, edx, 0Ch .text:00430D59 C1 EA 0C shr edx, 0Ch .text:00430D5C 25 FF FF FF 03 and eax, 3FFFFFFh .text:00430D61 .text:00430D61 loc_430D61: ; CODE XREF: MmGetPhysicalAddress(x)+4Ej .text:00430D61 33 C9 xor ecx, ecx .text:00430D63 0F A4 C1 0C shld ecx, eax, 0Ch .text:00430D67 C1 E0 0C shl eax, 0Ch .text:00430D6A 81 E7 FF 0F 00 00 and edi, 0FFFh .text:00430D70 03 C7 add eax, edi .text:00430D72 8B D1 mov edx, ecx .text:00430D74 .text:00430D74 loc_430D74: ; CODE XREF: MmGetPhysicalAddress(x)+81j .text:00430D74 5F pop edi .text:00430D75 5E pop esi .text:00430D76 5B pop ebx .text:00430D77 5D pop ebp .text:00430D78 C2 04 00 retn 4 .text:00430D78 _MmGetPhysicalAddress@4 endp
没关系,有前面清楚的PTE结构指引,这个函数就比较容易理解了。
以下就是它的C++实现:
代码:
struct VirtAddr1 { unsigned int PageOFF:12; unsigned int PageTable:20; }; struct VirtAddr2 { unsigned int PageOFF:12; unsigned int PageTableIndex:9; unsigned int PageLargeIndex:11; }; struct VirtAddr3 { unsigned int PageOFF:12; unsigned int PageTableIndex:9; unsigned int PageDirIndex:9; unsigned int PageDirPoint:2; }; MMPTE_HARDWARE* const PDE_BASE = (MMPTE_HARDWARE*)0xC0600000; //页目录表 MMPTE_HARDWARE* const PTE_BASE = (MMPTE_HARDWARE*)0xC0000000; //进程页表 PHYSICAL_ADDRESS GetPhysicalAddress(const unsigned long VirtualAddress) { const VirtAddr1* VA1 = (const VirtAddr1*)&VirtualAddress; const VirtAddr2* VA2 = (const VirtAddr2*)&VirtualAddress; MMPTE_HARDWARE PTE = *(PDE_BASE + VA2->PageLargeIndex); PHYSICAL_ADDRESS PA = {0,0}; if(!(PTE.Valid))return PA; if(PTE.LargePage) { PTE.PageFrameNumber += VA2->PageTableIndex; } else { PTE = *(PTE_BASE + VA1->PageTable); if(!(PTE.Valid))return PA; } PTE.reserved1 = 0; PA.HighPart = PTE.HighPart; PA.LowPart = PTE.LowPart; ((VirtAddr1*)(&PA.LowPart))->PageOFF = VA1->PageOFF; return PA; }
代码:
;Microsoft Windows Server 2003 Enterprise Edition Service Pack 2 [ver 5.2.3790] ;ntkrnlpa.exe ;MD5 : 20A327D41B0A5659AAFD0AA1AD98F433 .text:00439DE0 ; __int64 __stdcall MmGetPhysicalAddress(void *BaseAddress) .text:00439DE0 public _MmGetPhysicalAddress@4 .text:00439DE0 _MmGetPhysicalAddress@4 proc near ; CODE XREF: IoSetDumpRange(x,x,x,x)+1Ep .text:00439DE0 ; IoSetDumpRange(x,x,x,x)+5Dp ... .text:00439DE0 .text:00439DE0 var_8 = dword ptr -8 .text:00439DE0 BaseAddress = dword ptr 8 .text:00439DE0 .text:00439DE0 8B FF mov edi, edi .text:00439DE2 55 push ebp .text:00439DE3 8B EC mov ebp, esp .text:00439DE5 51 push ecx .text:00439DE6 51 push ecx .text:00439DE7 53 push ebx .text:00439DE8 8B 5D 08 mov ebx, [ebp+BaseAddress] .text:00439DEB 8B C3 mov eax, ebx .text:00439DED C1 E8 12 shr eax, 12h .text:00439DF0 25 F8 3F 00 00 and eax, 3FF8h .text:00439DF5 56 push esi .text:00439DF6 8D 88 00 00 60 C0 lea ecx, [eax+0C0600000h] .text:00439DFC 8B 31 mov esi, [ecx] .text:00439DFE 8B 51 04 mov edx, [ecx+4] .text:00439E01 57 push edi .text:00439E02 BF 81 00 00 00 mov edi, 81h .text:00439E07 89 75 F8 mov [ebp+var_8], esi .text:00439E0A 23 F7 and esi, edi .text:00439E0C 33 C0 xor eax, eax .text:00439E0E 3B F7 cmp esi, edi .text:00439E10 75 09 jnz short loc_439E1B .text:00439E12 85 C0 test eax, eax .text:00439E14 75 05 jnz short loc_439E1B .text:00439E16 8B 45 F8 mov eax, [ebp+var_8] .text:00439E19 EB 23 jmp short loc_439E3E .text:00439E1B ; --------------------------------------------------------------------------- .text:00439E1B .text:00439E1B loc_439E1B: ; CODE XREF: MmGetPhysicalAddress(x)+30j .text:00439E1B ; MmGetPhysicalAddress(x)+34j .text:00439E1B 8B 01 mov eax, [ecx] .text:00439E1D 8B 51 04 mov edx, [ecx+4] .text:00439E20 8B C8 mov ecx, eax .text:00439E22 83 E1 01 and ecx, 1 .text:00439E25 33 F6 xor esi, esi .text:00439E27 0B CE or ecx, esi .text:00439E29 74 4F jz short loc_439E7A .text:00439E2B 8B C8 mov ecx, eax .text:00439E2D 81 E1 80 00 00 00 and ecx, 80h .text:00439E33 56 push esi .text:00439E34 89 4D F8 mov [ebp+var_8], ecx .text:00439E37 59 pop ecx .text:00439E38 74 1C jz short loc_439E56 .text:00439E3A 85 C9 test ecx, ecx .text:00439E3C 75 18 jnz short loc_439E56 .text:00439E3E .text:00439E3E loc_439E3E: ; CODE XREF: MmGetPhysicalAddress(x)+39j .text:00439E3E 0F AC D0 0C shrd eax, edx, 0Ch .text:00439E42 8B CB mov ecx, ebx .text:00439E44 C1 E9 0C shr ecx, 0Ch .text:00439E47 25 FF FF FF 03 and eax, 3FFFFFFh .text:00439E4C 81 E1 FF 01 00 00 and ecx, 1FFh .text:00439E52 03 C1 add eax, ecx .text:00439E54 EB 33 jmp short loc_439E89 .text:00439E56 ; --------------------------------------------------------------------------- .text:00439E56 .text:00439E56 loc_439E56: ; CODE XREF: MmGetPhysicalAddress(x)+58j .text:00439E56 ; MmGetPhysicalAddress(x)+5Cj .text:00439E56 8B CB mov ecx, ebx .text:00439E58 C1 E9 09 shr ecx, 9 .text:00439E5B 81 E1 F8 FF 7F 00 and ecx, 7FFFF8h .text:00439E61 8B 91 04 00 00 C0 mov edx, [ecx+0C0000004h] .text:00439E67 81 E9 00 00 00 40 sub ecx, -0C0000000h .text:00439E6D 8B 01 mov eax, [ecx] .text:00439E6F 8B C8 mov ecx, eax .text:00439E71 83 E1 01 and ecx, 1 .text:00439E74 33 F6 xor esi, esi .text:00439E76 0B CE or ecx, esi .text:00439E78 75 06 jnz short loc_439E80 .text:00439E7A .text:00439E7A loc_439E7A: ; CODE XREF: MmGetPhysicalAddress(x)+49j .text:00439E7A 33 C0 xor eax, eax .text:00439E7C 33 D2 xor edx, edx .text:00439E7E EB 1F jmp short loc_439E9F .text:00439E80 ; --------------------------------------------------------------------------- .text:00439E80 .text:00439E80 loc_439E80: ; CODE XREF: MmGetPhysicalAddress(x)+98j .text:00439E80 0F AC D0 0C shrd eax, edx, 0Ch .text:00439E84 25 FF FF FF 03 and eax, 3FFFFFFh .text:00439E89 .text:00439E89 loc_439E89: ; CODE XREF: MmGetPhysicalAddress(x)+74j .text:00439E89 33 C9 xor ecx, ecx .text:00439E8B 0F A4 C1 0C shld ecx, eax, 0Ch .text:00439E8F C1 EA 0C shr edx, 0Ch .text:00439E92 C1 E0 0C shl eax, 0Ch .text:00439E95 81 E3 FF 0F 00 00 and ebx, 0FFFh .text:00439E9B 03 C3 add eax, ebx .text:00439E9D 8B D1 mov edx, ecx .text:00439E9F .text:00439E9F loc_439E9F: ; CODE XREF: MmGetPhysicalAddress(x)+9Ej .text:00439E9F 5F pop edi .text:00439EA0 5E pop esi .text:00439EA1 5B pop ebx .text:00439EA2 C9 leave .text:00439EA3 C2 04 00 retn 4 .text:00439EA3 _MmGetPhysicalAddress@4 endp
另外就是Vista的MiGetPhysicalAddress,计算过程都差不多,但多了更多的判断与跳转,还有一些无实际意义的计算,这个我很不明白是为什么。如果有牛人知道,请告知一下。
代码有点长,不贴了。看过Vista的MiGetPhysicalAddress,其中显示,reserved0这个位被使用了,但只做了一个判断,没有实际意义。
再者,XP与2003的MmGetVirtualForPhysical结果完全一样。而Vista多了一句“and eax, 0FFFFFFFCh”,也就是取到PTE放弃最后两位。但是想来想去,好像也没什么实际意义。
编译器开完全优化,编译出来的结果如下:
代码:
.text:000117B0 ; _LARGE_INTEGER __stdcall GetPhysicalAddress(const unsigned int VirtualAddress) .text:000117B0 ?GetPhysicalAddress@@YG?AT_LARGE_INTEGER@@K@Z proc near .text:000117B0 ; CODE XREF: Refresh(void *)+10p .text:000117B0 .text:000117B0 VirtualAddress = dword ptr 4 .text:000117B0 .text:000117B0 53 push ebx .text:000117B1 8B 5C 24 08 mov ebx, [esp+4+VirtualAddress] .text:000117B5 55 push ebp .text:000117B6 8B C3 mov eax, ebx .text:000117B8 C1 E8 15 shr eax, 15h .text:000117BB 56 push esi .text:000117BC 8B 34 C5 00 00 60 C0 mov esi, ds:0C0600000h[eax*8] .text:000117C3 8B CE mov ecx, esi .text:000117C5 57 push edi .text:000117C6 8B 3C C5 04 00 60 C0 mov edi, ds:0C0600004h[eax*8] .text:000117CD 83 E1 01 and ecx, 1 .text:000117D0 33 ED xor ebp, ebp .text:000117D2 33 C0 xor eax, eax .text:000117D4 33 D2 xor edx, edx .text:000117D6 0B CD or ecx, ebp .text:000117D8 74 61 jz short loc_1183B .text:000117DA 8B CE mov ecx, esi .text:000117DC 81 E1 80 00 00 00 and ecx, 80h .text:000117E2 0B CD or ecx, ebp .text:000117E4 74 27 jz short loc_1180D .text:000117E6 8B C3 mov eax, ebx .text:000117E8 C1 E8 0C shr eax, 0Ch .text:000117EB 25 FF 01 00 00 and eax, 1FFh .text:000117F0 B9 00 10 00 00 mov ecx, 1000h .text:000117F5 F7 E1 mul ecx .text:000117F7 03 C6 add eax, esi .text:000117F9 13 D7 adc edx, edi .text:000117FB 33 C6 xor eax, esi .text:000117FD 33 D7 xor edx, edi .text:000117FF 25 00 F0 FF FF and eax, 0FFFFF000h .text:00011804 83 E2 3F and edx, 3Fh .text:00011807 33 F0 xor esi, eax .text:00011809 33 FA xor edi, edx .text:0001180B EB 1E jmp short loc_1182B .text:0001180D ; --------------------------------------------------------------------------- .text:0001180D .text:0001180D loc_1180D: ; CODE XREF: GetPhysicalAddress(ulong)+34j .text:0001180D 8B CB mov ecx, ebx .text:0001180F C1 E9 0C shr ecx, 0Ch .text:00011812 8B 34 CD 00 00 00 C0 mov esi, ds:0C0000000h[ecx*8] .text:00011819 8B 3C CD 04 00 00 C0 mov edi, ds:0C0000004h[ecx*8] .text:00011820 8B CE mov ecx, esi .text:00011822 83 E1 01 and ecx, 1 .text:00011825 33 ED xor ebp, ebp .text:00011827 0B CD or ecx, ebp .text:00011829 74 10 jz short loc_1183B .text:0001182B .text:0001182B loc_1182B: ; CODE XREF: GetPhysicalAddress(ulong)+5Bj .text:0001182B 8B C6 mov eax, esi .text:0001182D 33 C3 xor eax, ebx .text:0001182F 83 E7 3F and edi, 3Fh .text:00011832 25 FF 0F 00 00 and eax, 0FFFh .text:00011837 33 C6 xor eax, esi .text:00011839 8B D7 mov edx, edi .text:0001183B .text:0001183B loc_1183B: ; CODE XREF: GetPhysicalAddress(ulong)+28j .text:0001183B ; GetPhysicalAddress(ulong)+79j .text:0001183B 5F pop edi .text:0001183C 5E pop esi .text:0001183D 5D pop ebp .text:0001183E 5B pop ebx .text:0001183F C2 04 00 retn 4 .text:0001183F ?GetPhysicalAddress@@YG?AT_LARGE_INTEGER@@K@Z endp
怎么说呢,光看MmGetPhysicalAddress实在是晕。但由C实现出来,原理异常清晰。
同时,解析过XP、2003、Vista以后,发现它们没有太大改动,那么,我们可以放心使用自己实现的GetPhysicalAddress喽。
最后感谢xIkUg。
胡乱写写,小小心得而已,欢迎拍砖。