同样是看别人代码时发现的,作者使用了MmGetPhysicalAddress和MmMapIoSpace这两个函数,之前从来没看过这两个函数还以为是作者自己写的呢。后来查了一下WDK原来是有文档的函数。作者是用这个函数把缓存模型I/O的地址取物理地址之后再映射出虚拟地址,虽然我没发现这么做有什么意义,因为对于缓冲I/O模式来说,IRP中给出的缓冲区地址已经是I/O管理器进行复制之后的结果了,不需要再进行什么映射,我也没搞懂作者是要干吗,不过可以学习一下这两个函数的使用。
PHYSICAL_ADDRESS
MmGetPhysicalAddress(
IN PVOID BaseAddress
);
这个返回的就是直接的物理地址了。
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
可见 PHYSICAL_ADDRESS就是LARGE_INTEGER了。
来看一下这个函数的源码吧,来自WRK。可见是通过获取PTE来取得物理地址的。宏的内容没有跟进去看了,但是想想就可以知道实现方法了,无非就是分页机制的原理。
1 PHYSICAL_ADDRESS 2 MmGetPhysicalAddress ( 3 __in PVOID BaseAddress 4 ) 5 6 { 7 PMMPTE PointerPte; 8 PHYSICAL_ADDRESS PhysicalAddress; 9 10 if (MI_IS_PHYSICAL_ADDRESS(BaseAddress)) 11 { 12 PhysicalAddress.QuadPart = MI_CONVERT_PHYSICAL_TO_PFN (BaseAddress); 13 } 14 else 15 { 16 17 PointerPte = MiGetPdeAddress (BaseAddress); 18 if (PointerPte->u.Hard.Valid == 0) 19 { 20 KdPrint(("MM:MmGetPhysicalAddressFailed base address was %p", 21 BaseAddress)); 22 ZERO_LARGE (PhysicalAddress); 23 return PhysicalAddress; 24 } 25 26 if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) 27 { 28 PhysicalAddress.QuadPart = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) + 29 MiGetPteOffset (BaseAddress); 30 } 31 else 32 { 33 PointerPte = MiGetPteAddress (BaseAddress); 34 35 if (PointerPte->u.Hard.Valid == 0) 36 { 37 KdPrint(("MM:MmGetPhysicalAddressFailed base address was %p", 38 BaseAddress)); 39 ZERO_LARGE (PhysicalAddress); 40 return PhysicalAddress; 41 } 42 PhysicalAddress.QuadPart = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 43 } 44 } 45 46 PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT; 47 PhysicalAddress.LowPart += BYTE_OFFSET(BaseAddress); 48 49 return PhysicalAddress; 50 }
接下来看下这个函数
PVOID
MmMapIoSpace(
IN PHYSICAL_ADDRESS PhysicalAddress,
IN SIZE_T NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType
);
同样是一个在WDK中有文档的函数,作用是把一个物理地址映射出来一个虚拟地址。PVOID返回值就是得到的虚拟地址。NumberOfBytes是映射的长度。所以这两个函数可以很好的配合使用啊,我的想法是在A进程中获取一个虚拟地址对应的物理地址,然后在B进程中把这个物理地址映射出来就可以使用啦,这样就突破每个进程的独立地址空间的局限啦。
顺带再说下,对于Windows内存管理不了解的童鞋可以不明白为啥获得物理地址后不直接使用,因为对于我们来说是不能直接使用物理地址的,我们平时接触到的都是经过分段+分页机制转化后的虚拟地址,而唯一能接触到物理地址的地方我想就是CR3寄存器中保存的PDE的基址了。