Windows虛擬地址轉物理地址(原理+源碼實現,附簡單小工具)

?

      ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?By?Lthis

上個月就想寫了,一直沒時間...網上大概搜了一下,原理與操作倒是一大堆,一直沒看到源碼實現,總得有人動手,這回輪到我了。東西寫得很爛,請大牛勿噴。一直覺得靠源碼的方式驅動學習是非常好的一種學習方法,比較直觀!聲明一下,本教程只有討論開啟PAE與關閉PAE兩種,至于PSE是否開啟沒有管...我的虛擬機默認PSE貌似是開啟滴?不知是不是寫的小工具有問題....對于x64下的等我有時間再寫吧。

東西都上傳在壓縮包中了,Codes文件夾下是工程源碼,Demo文件夾下是測試案例,Tool文件夾放的是小工具的Demo和源碼。

我的環境:開發環境(win7?sp1?x64?+?vs2013社區版?update5?+?wdk8.1

?? ???測試環境(vm10?+?win7?sp1?x86

一、先說說未開啟PAE的情況,祭出intel手冊的經典圖例:

?

這幅圖就是虛擬地址轉為物理地址的原理圖(4k頁面),看圖說話,用偽代碼描述一下:

?

1.Directory?Entry(PDE)???? =?PDBR[Directory];

?

2.Page-Table?Entry(PTE) =?PDE?+?Table?*?4;

?

3.Physical?Address? =?PTE?+?Offset;

?

由上可知,Linear?Address(線性地址)中的DirectoryTable其實就是個索引,在未開啟PAE的情況下,PDEPTE均是32bit4字節,所以要Table*4),以上只是原理上的描述,實際上,PDEPTE的后3位是屬性值,所以需要把后3位抹掉。

?

下邊上關鍵代碼,基本都步驟都寫了注釋了,有需要的可以封裝成函數。此外,本段代碼只是測試用,寫的很不規范,比如,在調用MmMapIoSpace應該調用MmUnMapIoSpace釋放內存。

?

            // 得到ring3傳入的虛擬地址size_t* pOutAddress = (size_t*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);VIRTUAL_ADDRESS virtualAddress = { 0 };virtualAddress.ulVirtualAddress = *pOutAddress;ULONG pdbr;_asm{mov eax,  cr3;mov pdbr, eax;}PHYSICAL_ADDRESS phyAddress = { 0 };phyAddress.LowPart = pdbr;PULONG pPdbr = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("pdbr = 0x%08X, 映射后的地址0x%p\n", pdbr, pPdbr));// pPdbr[ulDirBaseIdx] 頁目錄項ULONG ulDirBaseIdx = virtualAddress.stVirtualAddress.dirBaseIndex;ULONG ulDirIdx = virtualAddress.stVirtualAddress.dirIndex;KdPrint(("第一級,已找到頁目錄所在項:pPdbr[%d]:0x%08X", ulDirBaseIdx,pPdbr[ulDirBaseIdx]));ULONG ulDir = pPdbr[ulDirBaseIdx] & 0xFFFFF000;            // 抹去后3位得到真正的頁目錄項
ULONG ulDirPlus = ulDir + ulDirIdx * 4;                    // 頁表項phyAddress.LowPart = ulDirPlus;PULONG pDirPlus = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("第二級,已找到頁表項:ulDirPlus = 0x%08X, 映射后的地址0x%p\n", ulDirPlus, pDirPlus));ULONG ulPageTable = *pDirPlus & 0xFFFFF000;                // 抹去后3位得到真正的頁表項// 得到物理地址ULONG ulPhyAddress = ulPageTable + virtualAddress.stVirtualAddress.offset;// 映射為虛擬地址,獲取其值進行驗證phyAddress.LowPart = ulPhyAddress;PWCHAR pPhyAddress = (PWCHAR)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("虛擬地址:0x%08X, 對應物理地址:0x%08X, Value:%S\n", *pOutAddress, ulPhyAddress, pPhyAddress));// 傳出對應物理地址*pOutAddress = ulPhyAddress;

?

?

二、開啟PAE的情況

?

?

?

同樣是4k頁面的,偽代碼描述如下:

?

1.Dir.Pointer?Entry(PDPTE)? =?PDPTR[Directory?Pointer];

?

2.Director?Entry(PDE)? =?PDPTE?+?Directory?*?0x8;

?

3.Page-Table?Entry(PTE)? =?PDE?+?Table?*?0x8;

?

4.Physical?Address? =?PTE+Offset;

?

在開啟PAE的情況下,PDEPTE均是64bit8字節,所以要*8),同樣PDEPTE的后3位是屬性值,所以需要把后3位抹掉。

?

關鍵代碼如下:

            // 得到傳入的ring3層虛擬地址size_t* pOutAddress = (size_t*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);VIRTUAL_ADDRESS virtualAddress = { 0 };virtualAddress.ulVirtualAddress = *pOutAddress;ULONG pdbr;// 得到頁目錄指針物理地址
            _asm{mov eax,  cr3;mov pdbr, eax;}// 映射為虛擬地址以便取值PHYSICAL_ADDRESS phyAddress = { 0 };phyAddress.LowPart = pdbr;PULONG pPdbr = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("pdbr = 0x%08X, 映射后的地址0x%p\n", pdbr, pPdbr));// 定位頁目錄指針表并獲取頁目錄表物理頁地址// ulDirAddress 為頁目錄表物理頁地址ULONG ulPointerIdx = virtualAddress.stVirtualAddress.dirPointer;ULONG ulDirBaseAddress = pPdbr[ulPointerIdx];ulDirBaseAddress &= 0xFFFFF000;            // 中間物理地址// 定位頁表項ULONG ulDirAddress = ulDirBaseAddress + virtualAddress.stVirtualAddress.dirIndex * 0x8;phyAddress.LowPart = ulDirAddress;PULONG pPageTable = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);ULONG ulPageTable = *pPageTable;ulPageTable &= 0xFFFFF000;                 // 中間物理地址// 定位物理頁面ulPageTable += virtualAddress.stVirtualAddress.tableIndex * 0x8;phyAddress.LowPart = ulPageTable;PULONG pPageBase = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);ULONG ulPageBase = *pPageBase;ulPageBase &= 0xFFFFF000;// 得到物理地址ULONG ulPhyAddress = ulPageBase + virtualAddress.stVirtualAddress.offset;// 映射為虛擬地址,獲取其值進行驗證phyAddress.LowPart = ulPhyAddress;PWCHAR pPhyAddress = (PWCHAR)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("虛擬地址:0x%08X, 對應物理地址:0x%08X, Value:%S\n", *pOutAddress, ulPhyAddress, pPhyAddress));// 傳出對應物理地址*pOutAddress = ulPhyAddress;pIrp->IoStatus.Information = cout;

以上代碼步驟是參考安于此生的文章寫的,看不懂的可以先看看安于此生的文章《啟用PAE后虛擬地址到物理地址的轉換》

另附上小工具源碼,該工具用于檢測系統是否開啟PAEPSE等。

?

#define BUFFERSIZE    0x3000
char g_szMemInfo[BUFFERSIZE] = { 0 };// 以下code在 DriverEntry 中
    DWORD dwPE  = 0;                // Protection Enable    cr0[0]DWORD dwWP  = 0;                // Write Protect        cr0[16]DWORD dwPG  = 0;                // Paging                cr0[31]DWORD dwPAE = 0;                // 物理地址擴展            cr4[5]DWORD dwPSE = 0;                // Page Size Extension    cr4[4]DWORD dwCr0 = 0;DWORD dwCr4 = 0;// 注冊卸載函數pDriverObj->DriverUnload = driverUnload;_asm{pushad;mov eax, cr0;mov dwCr0, eax;// PE標志位and eax, 0x01;mov dwPE, eax;mov eax, cr0;// WP標志位and eax, 0x10000;mov dwWP, eax;mov eax, cr0;// PG標志位and eax, 0x80000000;mov dwPG, eax;// PAE//mov eax, cr4; 機器碼如下_emit 0x0F;_emit 0x20;_emit 0xE0;mov dwCr4, eax;and eax, 0x20;mov dwPAE, eax;// PSE_emit 0x0F;_emit 0x20;_emit 0xE0;and eax, 0x10;mov dwPSE, eax;popad;}KdPrint(("PE  = 0x%08X\r\n",dwPE));KdPrint(("WP  = 0x%08X\r\n",dwWP));KdPrint(("PG  = 0x%08X\r\n",dwPG));KdPrint(("PAE = 0x%08X\r\n",dwPAE));KdPrint(("PSE = 0x%08X\r\n",dwPSE));KdPrint(("Cr0 = 0x%08X\r\n",dwCr0));KdPrint(("Cr4 = 0x%08X\r\n",dwCr4));//----------------------------------------------------------------------------// PE標志位if (0 != dwPE){RtlStringCchCatNA(g_szMemInfo, BUFFERSIZE, "----------------------保護模式(PE=1)-------------------\r\n",BUFFERSIZE - sizeof("----------------------保護模式(PE=1)-------------------\r\n"));}else{RtlStringCchCatNA(g_szMemInfo,BUFFERSIZE ,"----------------------實地址模式(PE=0)-------------------\r\n",BUFFERSIZE - sizeof("----------------------實地址模式(PE=0)-------------------\r\n"));}//----------------------------------------------------------------------------// WP標志位if (0 != dwWP){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"內存寫保護(WP)開啟...\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"內存寫保護(WP)禁止...\r\n");}//----------------------------------------------------------------------------// PG標志位if (0 != dwPG){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"頁機制(PG)啟用\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"頁機制(PG)禁止\r\n");}//----------------------------------------------------------------------------// PAE標志位if (0 != dwPAE){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"物理地址擴展(PAE)已開啟\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"物理地址擴展(PAE)未啟用\r\n");}//----------------------------------------------------------------------------// PSE標志位if (0 != dwPSE){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"頁面大小擴展(PSE)已開啟\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"頁面大小擴展(PSE)未啟用\r\n");}KdPrint(("%s\r\n", g_szMemInfo));

?

最后,看看效果運行圖。Demo是在ring3層定義一個Unicoe字符串:“Lthis,然后將其虛擬地址傳入ring0層,ring0解析后傳出對應的物理地址。

開啟PAE下運行的效果:

?

?

?

?

未開啟PAE的運行效果:

?

附件地址:鏈接:http://pan.baidu.com/s/1kTENdnL 密碼:g5j7

?

轉載于:https://www.cnblogs.com/Lthis/p/4746795.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/397647.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/397647.shtml
英文地址,請注明出處:http://en.pswp.cn/news/397647.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python裝飾器的使用

借用裝飾器,我們可以批量的對老的函數進行改造或擴展老函數功能,比如需要對函數的接收參數進行過濾,Flash的url路由功能就是使用的這個方式 def dropoushu(): # 這一層函數可以去掉,如果去掉了,則使用checkjiou這種方…

7_文件上傳漏洞

文件上傳漏洞 當文件上傳時,若服務端腳本語言未對上傳的文件進行嚴格驗證和過濾,若惡意用戶上傳惡意的腳本文件時,就有可能控制整個網站甚至是服務器,這就是文件上傳漏洞。 權限 1.網站后臺權限:登陸了后臺&#xff0…

mysql數據庫如何實現分頁查詢_不同數據庫的分頁查詢實現方法總結

分頁查詢是數據庫查詢中經常用到的一項操作,對查詢出來的結果進行分頁查詢可以方便瀏覽。那么Oracle、SQL Server、MySQL是如何實現查詢的呢?本文我們就來介紹這一部分內容。首先我們先看一下SQL Server 數據庫中SQL語句查詢分頁數據的解決方案&#xff…

POJ - 3842 An Industrial Spy dfs(水)

題意:給你一串數字,最少一個,最多七個,問用這里面的數字能組成多少素數,不重復。 思路:之前還遍歷10000000的每一個素數,結果超時,后來發現直接dfs就可以了,只是標記一下做過的數。 …

飛機大戰小游戲1.0版本

小時候大家應該都玩過飛機大戰吧,這就是仿的一個飛機大戰,但是沒有寫的很全,只能玩一次,死掉之后需要刷新頁面玩第二次,話不說多,上代碼: 初始頁面: 整個的html代碼還是很少&#xf…

記一次Jquery獲取值的典型錯誤

直接上代碼: 代碼很簡單,通過Post的形式提交參數,但是發現提交的data總是空,昨晚有點納悶,今天一看才發現。。。 獲取值得時候的順序有問題,獲取值應該是在onclick事件中。 綜上:寫Jquery的時間…

android 調用java接口_android調用java的web service接口

android中通過webservice調用服務器端其實還是很簡單的,只要按部就班的按照下面步驟進行即可:(1)創建HttpTransportSE對象,該對象用于調用WebService操作代碼如下:HttpTransportSE ht new HttpTransportSE(SERVICE_URL);(2)創建SoapSerializ…

iOS: TableView如何刷新指定的cell 或section

/一個section刷新 NSIndexSet *indexSet[[NSIndexSet alloc]initWithIndex:2]; [tableview reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic]; //一個cell刷新 NSIndexPath *indexPath[NSIndexPath indexPathForRow:3 inSection:0…

Skype For Business 2015實戰系列14:創建Office Web App服務器場

Skype For Business 2015實戰系列14:創建Office Web App服務器場前面的操作中我們已經成功的安裝了Office Web App Server,今天我們將創建Office Web App服務器場。具體步驟如下:配置證書:登陸到OWA服務器,打開服務器管理器,點擊“…

https://cwiki.apache.org/confluence/display/FLINK/FLIP-24+-+SQL+Client

https://cwiki.apache.org/confluence/display/FLINK/FLIP-24-SQLClient轉載于:https://www.cnblogs.com/WCFGROUP/p/9214589.html

java ee me se_java EE ME SE有什么關系

1. Java SE(Java Platform,Standard Edition)。Java SE 以前稱為 J2SE。它允許開發和部署在桌面、服務器、嵌入式環境和實時環境中使用的 Java 應用程序。Java SE 包含了支持 Java Web 服務開發的類,為 Java Platform,Enterprise Edition(Jav…

Android第三夜

Paint的設置方法 setAntiAlias:這是畫筆的鋸齒效 setColor setARGB setAlpha setTextSize setStyle setStrokeWidth getColor getAlpha Canvas繪制常見圖形的方法 1,繪制直線 左上角是0.0點 drawLine(float startX,float startY,float stopX,float stopY…

JavaScript websocket 實例

實例: 即時通訊聊天室demo可以打開兩個頁面互相發送消息查看。 websocket.js /* 判斷瀏覽器是否內置了websocket */if (WebSocket in window) {websocket new WebSocket(ws://180.76.144.202:19910/websocket);}websocket->onerror onerror;websocket->onopen onopen…

SQL Server 2008 基礎

SQL Server 2008 基礎SQL流程TDS是一種協議,一系列描述兩個計算機間如何傳輸數據的規則。象別的協議一樣,它定義了傳輸信息的類型和他們傳輸的順序。總之,協議描述了“線上的位”,即數據如何流動。表格數據流協議是建立在TCP/IP N…

python異步處理請求_如何一次在python中發送異步http請求?

1)創建一個Queue.Queue對象2)根據您的喜好制作盡可能多的“工作”線程,從Queue.Queue讀取3)將作業提供給Queue.Queue工作線程將按照它們放置的順序讀取Queue.Queue從文件中讀取行并將它們放入Queue.Queue的示例import sysimport urllib2import urllibfrom Queue import Queueim…

如何通過Git GUI將自己本地的項目上傳至Github

ithud是一個程序員以后成長都會使用到的,先不說很多優秀的開源框架都在這上面發布,光是用來管理自己的demo都已經讓人感到很方便,用得也很順暢。而真正讓我下定決心使用github的原因是因為兩次誤操作,將自己所有的學習demo全都刪除…

lucene解決全文檢索word2003,word2007的辦法

在上一篇文章中 ,lucene只能全文檢索word2003,無法檢索2007,并且只能加載部分內容,無法加載全文內容。為解決此問題,找到了如下方法 POI 讀取word (word 2003 和 word 2007) 最近在給客戶做系統的時候,用戶…

【JSP筆記】第三章 JSP內置對象【上】

2019獨角獸企業重金招聘Python工程師標準>>> 1.內置對象簡介&#xff1a;JSP內置對象是WEB容器創建的一組對象&#xff0c;不使用new關鍵就可以是用的對象。 <% out.println(123); %> 2.九大內置對象&#xff1a; outrequestresponsesessionapplication Page …

自定義標簽 —— 實現時間轉換和輸出功能

第一步&#xff1a;導入jar包 jsp-api-2.2-sources.jar <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api --> <dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.…

laravel5 centos6.4下的配置體驗

1. 安裝lmnp環境: nginx version: nginx/1.6.0、 php 5.5.7 、 centos6.42. laravel-v5.1.4 一鍵安裝包&#xff0c;在使用composer 安裝時出現server 500的錯誤&#xff0c;改用了一鍵安裝包注意&#xff1a;1. 防火墻的端口的&#xff0c; 2. laravel目錄的用戶權限&#xff…