搜尋

Windows文章如何

返回清單
切換到指定樓層
通知這文章過時或找檔案 發表主題

[其他] 【轉貼】教你如何寫出讓Windows XP用上4GB內存的程式,附程式+源碼

[複製連結]
1
SheepKingCN ( Lv.80 論壇達人 ) 發表於 2013-8-25 22:43:10 | 只看該作者 |只看大圖 回覆獎勵 |降序瀏覽 |閱讀模式
本文章最後由 SheepKingCN 於 2013-8-25 22:51 編輯

.
此為本人學習、無聊研究用,為了要備份文章,所以才發在這裡。
轉貼文章,我也不忘..改了一些文字語氣,讓文章閱讀起來..通順點XD

作者介紹:
名叫scdeny
是中國大陸人
也是IGS 國際遊戲安全組織的授課老師

作者在網路上的ID:
中國大陸-看雪學院-scdeny

此文章的發布時間:
2011-07-28

------------正文開始------------

先上圖,修補之後的,原來只有2.98G,現在是3.86G了

系统属性.png

任务管理器.png



去年7月入手小黑T410,到手就裝了4G的內存,WINDOWS 7的 補丁來的很快,很順利就用上了3.86G(糾結於剩下的140M哪裡去了?至今也沒搞明白,只知道主板沒有映射),而所謂的XP的種種補丁,不外乎就是Ramdisk,開啟PAE之類的,毫無用處,最可憐的是竟然被某網友的“開啟了PAE就能用到全部4G內存,系統屬性頁顯示還是2.98G是假的”一說給忽悠了一年,中國沒文化真可怕。 。 。就這麼將信將疑用了一年,中間也糾結過一段時間,沒有深入分析,近日越想越感覺不對勁,再來糾結糾結。 。 。
用WinDbg看看
  1. lkd> dd MmHighestPhysicalPage
  2. 8088b124  000bf7ff 000bf399 00000040 00000000
  3. lkd> dd MmNumberOfPhysicalPages
  4. 8088b128  000bf399 00000040 00000000 7fff0000
複製代碼
可見最高物理內存頁號MmHighestPhysicalPage值為bf7ff,物理內存總頁數MmNumberOfPhysicalPages值為bf399,換算成物理內存數0xbf399*0x1000=2.98G正好是系統屬性頁顯示的2.98G,改變這個值,系統屬性頁的值也會跟著變,是不是把這個值改了你就能用到更多的內存了呢,當然不是,任務管理器裡記錄的內存使用量確是真是的。
那是不是我的PAE沒有真正啟用呢?
那我們再用WinDbg看看
  1. lkd> !pte 80800000
  2.                     VA 80800000
  3. PDE at C0602020            PTE at C0404000
  4. contains 00000000008009E3  contains 0000000000000000
  5. pfn 800       -GLDA--KWEV   LARGE PAGE pfn 800
複製代碼
看吧,PDE和PTE裡面的物理地址00000000008009E3和0000000000000000都是64位的,而在沒有啟用PAE的系統裡,頁表項裡的物理地址是32位的。 (為什麼PTE裡是一串0呢?因為我們看的80800000這個虛擬地址是ntkrnlpa.exe的基地址,它當然是加載在物理內存的0地址的)
那麼是不是系統偷偷地在用我的4G內存了,而給我顯示出2.96G的假象呢?
再祭出我們的法寶WinDbg
  1. lkd> dd poi(MmPhysicalMemoryBlock)
  2. 8ad75c80  00000007 000bf3ab 00000001 0000009d
  3. 8ad75c90  00000100 000bf17c 000bf282 000000dd
  4. 8ad75ca0  000bf40f 00000060 000bf70f 00000008
  5. 8ad75cb0  000bf71f 0000004c 000bf7ff 00000001
複製代碼
這裡有兩個結構體:
  1. typedef struct _PHYSICAL_MEMORY_RUN {
  2.     PFN_NUMBER BasePage;
  3.     PFN_NUMBER PageCount;
  4. } PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;

  5. typedef struct _PHYSICAL_MEMORY_DESCRIPTOR {
  6.     ULONG NumberOfRuns;
  7.     PFN_NUMBER NumberOfPages;
  8.     PHYSICAL_MEMORY_RUN Run[1];
  9. } PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;
複製代碼
從上面可以看出,我的機器有7塊可用的內存,總共有bf3ab頁(為什麼這個數字跟上面看到的MmNumberOfPhysicalPages不符呢?),分別為1 -9d,100- bf17c,…,bf7ff,可見最大物理內存地址為bf7ff,還是與4G內存相去甚遠啊。 。 。
那麼是不是我的主板根本就不識別這麼大的內存呢? ?
那麼我們再做做實驗,用nt4的源代碼編譯一份NTLDR,把osloader.exe探測到的物理內存輸出一份,下面是通過中斷獲取的內存佈局圖,BIOS專家們都叫把它做E820圖
  1. Base  Size  Type
  2. 0   9E800  1
  3. 9E800  1800  2
  4. D2000  2000  2
  5. DC000  24000  2
  6. 100000  BF17C000  1
  7. BF27C000  6000  2
  8. BF282000  DD000  1
  9. BF35F000  12000  2
  10. BF371000  1000  4
  11. BF3F2000  1D000  2
  12. BF40F000  60000  1
  13. BF46F000  1F9000  2
  14. BF668000  80000  4
  15. BF6E8000  27000  2
  16. BF717000  8000  1
  17. BF71F000  4C000  1
  18. BF76B000  C000  4
  19. BF777000  3000  3
  20. BF77A000  7000  4
  21. BF781000  1000  3
  22. BF782000  9000  4
  23. BF78B000  1000  3
  24. BF78C000  13000  4
  25. BF79F000  60000  3
  26. BF7FF000  1000  1
  27. BF800000  800000  2
  28. E0000000  10000000  2
  29. FEAFF000  1000  2
  30. FEC00000  10000  2
  31. FED00000  400  2
  32. FED1C000  4000  2
  33. FED20000  70000  2
  34. FEE00000  1000  2
  35. FF000000  1000000  2
  36. 100000000  38000000  1
複製代碼
圖中type為1的就是分配給本機物理內存的地址,其他的為其他硬件所用,我們把內存地址挑出來:
  1. Base    Size
  2. 0      9E800
  3. 100000    BF17C000
  4. BF282000  DD000
  5. BF40F000  60000
  6. BF717000  8000
  7. BF71F000  4C000
  8. BF7FF000  1000
  9. 100000000  38000000
複製代碼
總數為F73AC800=3.86G,儘管4G以下的地址空間被硬件佔用了不少,主板並沒有放棄那塊內存嘛,只是把他們映射到了4G以上的空間,即100000000-138000000,看來是XP那傢伙太不地道,活生生把咱們使用這塊內存給掐掉了,故而產生了MmHighestPhysicalPage= BF7FF,無恥的傢伙!什麼? XP的內存機制不支持?不要為XP辯解,PAE技術早在Intel P6家族的CPU身上就已經開始使用了,Intel手冊第一卷3.3.6節關於PAE有如下表述:
Beginning with P6 family processors, the IA-32 architecture supports addressing of
up to 64 GBytes (2^36 bytes) of physical memory.
也就是說,從Intel P6家族的CPU開始,(PAE技術讓)IA-32架構的CPU就支持對64G的物理內存進行尋址, P6家族可是很老CPU了,奔二,奔三就屬於P6家族的,所以XP這個後來才發布的操作系統不可能連PAE都沒考慮進去吧。
既然那塊4G以上的內存地址被主板識別,NTLDR也探測到了,操作系統也支持,那我們為什麼還是用不到呢?到底是NTLDR沒有告訴ntkrnlpa.exe,還是ntkrnlpa.exe自己給我們截斷了?
這怎麼調試呢? Bochs?不行,我總共才4G內存,哪有那麼多內存分配給Bochs用呢,要有XP的ntos的源碼就好了,ntos的入口函數為
VOID KiSystemStartup(PLOADER_PARAMETER_BLOCK KissLoaderBlock)
在NTLDR向ntos交權的時候,會將內存描述鍊錶通過結構體參數LOADER_PARAMETER_BLOCK傳過去,這個結構體原型為...
  1. ypedef struct _LOADER_PARAMETER_BLOCK {
  2.     LIST_ENTRY LoadOrderListHead;
  3.     LIST_ENTRY MemoryDe​​scriptorListHead;
  4.     LIST_ENTRY BootDriverListHead;
  5. ULONG KernelStack;
  6. ……
  7. 後面太長,省略掉
  8. } LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK;
複製代碼
既然沒有Windows XP的源碼,那就用wrk將就一下吧,將wrk編譯的內核文件wrkx86.exe來替換ntkrnlpa.exe,系統肯定是起不來的,不過我們只需要在wrkx86.exe的入口點打印出NTLDR傳過來的內存描述鍊錶就好了,MEMORY_ALLOCATION_DESCRIPTOR的原型為
  1. typedef struct _MEMORY_ALLOCATION_DESCRIPTOR {
  2.     LIST_ENTRY ListEntry;
  3.     TYPE_OF_MEMORY MemoryType;
  4.     ULONG BasePage;
  5.     ULONG PageCount;
  6. } MEMORY_ALLOCATION_DESCRIPTOR, *PMEMORY_ALLOCATION_DESCRIPTOR;
複製代碼
於是我們很快得到了結果:
(我無法po圖,真是遺憾...)

咦! NTLDR貌似真的沒有把4G以上的地址傳過來啊,怎麼到FF000這塊內存就完了呢?
難道NTLDR私自把4G以上的地址給裁了?難道一切罪惡的源泉在NTLDR?在此我犯了個嚴重的錯誤,以為勝利在望,加班加點研究NTLDR,最好成功跳過NTLDR截去4G以上內存的代碼了,啟動發現XP依然顯示2.98G的可用內存,怎麼回事呢?回過頭來再分析NTLDR,才發現瞭如下的代碼
  1. if ( (_BYTE)BlUsePae_0 )
  2.     {
  3.       v10 = BlpAllocatePAETables();
  4.       if ( v10 )
  5.         return v10;
  6.     }
  7.     else
  8.     {
  9.       BlpTruncateDescriptors(0xFFFFFu);
  10. }
複製代碼
BlpTruncateDescriptors(0xFFFFFu)函數的功能就是設置內存描述鍊錶的最大頁面號為0xFFFFF,即截去4G以上的內存,原來我們編譯的wrkx86.exe不支持PAE,被NTLDR發現了,故而才調用BlpTruncateDescriptors截斷的,而我們的XP用的內核ntkrnlpa.exe是支持PAE的,那麼就不會截斷了,哎,馬虎啊。 。 。
那還是鎖定ntkrnlpa.exe分析吧,充分發揚廢寢忘食的精神,終於找到了一個可疑的函數ExVerifySuite,這不會就是驗證我們版本的函數吧,網上一查,發現有位“老生常談”早就發現了,他的文章在這裡
http://thxlp.wordpress.com/2008/ ... ndows%E5%92%8C4g%E4 %BB%A5%E4%B8%8A%E7%89%A9%E7%90%86%E5%86%85%E5%AD%98/
汗。 。 。 。差距啊,不過這位老大發現這麼久竟然不出補丁,拯救我們廣大百姓於水貨,哎。 。 。害我熬夜傷神這麼久。 。 。 。
不過這位“老生”的代碼不知道從哪裡搞的,nt4源碼裡沒有MiCheckPaeLicense這個函數,而windows2000的源代碼裡雖然有這個函數,但差別很大,wrk的源代碼裡也不是那樣的,反彙編XP的ntkrnlpa.exe,代碼如下
  1. int __usercall MiCheckPaeLicense<eax>(PLOADER_PARAMETER_BLOCK LoaderBlock<eax>)
  2. {
  3.   EndPage = 0;
  4.   LoaderBlock1 = LoaderBlock;
  5.   MaxPageCount = 0x100000u;
  6.   MaxPage = 0;
  7.   if ( ExVerifySuite(DataCenter) == 1 )
  8.   {
  9.     if (LoaderBlock->u.I386.VirtualBias )
  10.     {
  11.       MaxPageCount = 0x400000u;                 // booting /3gb: 16G
  12.       MaxPage = 0x400000u;
  13.     }
  14.     else
  15.     {
  16.       MaxPageCount = 0x1000000u;
  17.     }                                           // DataCenter: 64G
  18.   }
  19.   else
  20.   {
  21.     if ( MmProductType == 0x690057 || ExVerifySuite(Enterprise) != 1 )
  22.     {
  23.       if ( ExVerifySuite(ServerAppliance) == 1 )
  24.         MaxPageCount = 0x80000u;                // 2G
  25.       else
  26.         MaxPage = 0x100000u;                    // 4G
  27.     }
  28.     else
  29.     {
  30.       MaxPageCount = 0x800000u;// Advanced Server is permitted a maximum of 32gb
  31.     }
  32.   }
複製代碼
我實在是不知道這位高人的代碼來自哪裡,懇請各位高人給予指點。 。 。
從這段代碼裡可以看出,MiCheckPaeLicense函數會檢查操作系統的版本,如果是DataCenter,就允許使用64G內存,Advanced Server為32G,如果為精簡版則為2G,其他版本為4G,看來真是ntkrnlpa .exe在作怪,先別急著patch,驗證內存限制的還有一個地方,在MmAddPhysicalMemoryEx函數里也會調用ExVerifySuite這個函數,代碼如下:
  1. if ( ExVerifySuite(DataCenter) == 1 )
  2.   {
  3.     LimitPage = 0x1000000u;                     // DataCenter : 64G
  4.   }
  5.   else
  6.   {
  7.     if ( MmProductType == 0x690057 || (v9 = ExVerifySuite(Enterprise) == 1, LimitPage = 0x800000u, !v9) )// Advanced Server : 32G
  8.       LimitPage = 0x100000u;                    // Other : 4G
  9.   }
複製代碼
代碼都差不多,要patch的話兩個地方要一起改,至於怎麼改?代碼都在這麼裡,想怎麼改就怎麼改吧,只要兩個地方都改了就行,只要其中一個地方不改,ntos都會陰魂不散的把你多出來的內存吃掉…
看成果吧
  1. lkd> dd MmHighestPhysicalPage
  2. 8088b124  00137fff 000f7399 00000040 00000000

  3. lkd> dd MmNumberOfPhysicalPages
  4. 8088b128  000f7399 00000040 00000000 7fff0000

  5. lkd> !pte d0800000
  6.                     VA d0800000
  7. PDE at C0603420            PTE at C0684000
  8. contains 00000001004DF963  contains E15C080000000400
  9. pfn 1004df    -G-DA--KWEV   not valid
  10.                             Proto: E15C0800
複製代碼
數數這個地址1004DF963,9位啊,4GB以上了,不要被E15C080000000400這個地址嚇到了,64位,有這麼大的地址嗎?查查PTE的結構體就知道了,前面的幾位是標誌位
再看物理內存塊
  1. lkd> dd poi(MmPhysicalMemoryBlock)
  2. 8baa3c70  00000008 000f73ab 00000001 0000009d
  3. 8baa3c80  00000100 000bf17c 000bf282 000000dd
  4. 8baa3c90  000bf40f 00000060 000bf70f 00000008
  5. 8baa3ca0  000bf71f 0000004c 000bf7ff 00000001
  6. 8baa3cb0  00100000 00038000 0001000a 6c4d6d4d
複製代碼
看到了嗎,我的電腦機器現在有8塊可用的內存了,多了一個100000-138000,總共有f73ab頁了,0xf73ab*0x1000=3.86G,至於還有140M,主板沒映射,用不到了,能不能解決呢?希望各位牛人能夠給予指點。 。 。

後面部分比較倉促,主要是聽到重任到來的消息,沒時間仔細寫了,補丁沒寫完,估計一時半會完成不了了,倉促發帖,開始潛伏。 。 。

忙裡偷閒,補丁寫好了,趕緊傳上來共享,本機測試通過,如果使用過程中發現問題請給我留言。 。 。
——————————————————————————————————————————
最近忙死了,幾天沒上網了,更沒時間去研究這個,讓各位失望了。 。 。壇子裡的牛人們如果有時間去研究研究吧,MengXP執著的鑽研精神讓我佩服,離成功只有一步之遙了,希望大家能齊心協力,早日解決這些問題,我只能忙過這陣子再來了。 。 。
-------------------------------------------------- -------------
實在抱歉,上個版本出的太匆忙了,嚴重問題都沒有發現,下載這個版本XP64G20110805.rar的朋友請罵我,實在是疏忽大意,抱歉抱歉。 。 。 。
已經釋出了 XP64G20111113.rar
-------------------------------------------------- -------------------------------------------------- ------------------------------------------
終於有時間繼續研究一下了,發現原因主要在DMA,修改之後,USB存儲設備基本可以正常使用了,先上補丁,回頭再發技術帖...

注意: 此程式的編碼為簡體中文,如果你的系統是台灣-繁體中文,會顯示亂碼哦! 需要轉換Unicode碼,或者是使用Microsoft AppLocale

XP64G20111113.rar (17.46 KB, 下載次數: 25)

.


評分

參與人數 1威望 +2 收起 理由
〃愛樂〃 + 2 很給力!

檢視全部評分




大家正在看啥


收藏收藏 分享文章到FB上分享
回覆 使用道具 檢舉
複製專屬你的推廣連結:發至FB與各論壇宣傳:累積點數換GP商品 & 藍鑽
每五點閱率就可以兌換藍鑽積分或遊戲點卡 夢遊推廣文章換GP商品

你需要登入後才可以回覆 登入 | 加入會員

本版積分規則

Copyright (C) 2010-2020 夢遊電玩論壇

廣告合作:請直接聯繫我們,並附上您預刊登位置的預算。  

快速回覆 返回頂端 返回清單