漲姿勢系列之——核心環境下記憶體對映函式

Ox9A82發表於2016-06-02

同樣是看別人程式碼時發現的,作者使用了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的基址了。

相關文章