【轉】讓XP用上4G記憶體,有圖有真相,帶破解補丁

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

去年7月入手小黑T410,到手就裝了4G的記憶體,WINDOWS 7的破解補丁來的很快,很順利就用上了3.86G(糾結于剩下的140M哪裡去了?至今也沒搞明白,只知道主機板沒有映射),而所謂的XP的種種補丁,不外乎就是Ramdisk,開啟PAE之類的,毫無用處,最可憐的是竟然被某網友的「開啟了PAE就能用到全部4G記憶體,系統屬性頁顯示還是2.98G是假的」一說給忽悠了一年,沒文化真可怕。。。就這麼將信將疑用了一年,中間也糾結過一段時間,沒有深入分析,近日越想越感覺不對勁,再來糾結糾結。。。

用WinDbg看看

代碼:

lkd> dd MmHighestPhysicalPage 8088b124 000bf7ff 000bf399 00000040 00000000
lkd> dd MmNumberOfPhysicalPages 8088b128 000bf399 00000040 00000000 7fff0000

可見最高實體記憶體頁號MmHighestPhysicalPage值為bf7ff,實體記憶體總頁數MmNumberOfPhysicalPages值為bf399,換算成實體記憶體數0xbf399*0x1000=2.98G正好是系統屬性頁顯示的2.98G,改變這個值,系統屬性頁的值也會跟著變,是不是把這個值改了你就能用到更多的記憶體了呢,當然不是,工作管理員裡記錄的記憶體使用量確是真是的。

那是不是我的PAE沒有真正啟用呢?

那我們再用WinDbg看看

代碼:

lkd> !pte 80800000
                    VA 80800000
PDE at C0602020 PTE at C0404000 contains 00000000008009E3 contains 0000000000000000
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

代碼:

lkd> dd poi(MmPhysicalMemoryBlock)
8ad75c80  00000007 000bf3ab 00000001 0000009d 8ad75c90  00000100 000bf17c 000bf282 000000dd 8ad75ca0 000bf40f 00000060 000bf70f 00000008
8ad75cb0 000bf71f 0000004c 000bf7ff 00000001

這裡有兩個結構體:

代碼:

typedef struct _PHYSICAL_MEMORY_RUN {
    PFN_NUMBER BasePage;
    PFN_NUMBER PageCount;
} PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;

typedef struct _PHYSICAL_MEMORY_DESCRIPTOR {
    ULONG NumberOfRuns;
    PFN_NUMBER NumberOfPages;
    PHYSICAL_MEMORY_RUN Run[1];
} PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR; 

從上面可以看出,我的機器有7塊可用的記憶體,總共有bf3ab頁(為什麼這個數位跟上面看到的MmNumberOfPhysicalPages不符呢?),分別為1 -9d,100- bf17c,…,bf7ff,可見最大實體記憶體位址為bf7ff,還是與4G記憶體相去甚遠啊。。。

那麼是不是我的主機板根本就不識別這麼大的記憶體呢??

那麼我們再做做實驗,用nt4的原始程式碼編譯一份NTLDR,把osloader.exe探測到的實體記憶體輸出一份,下面是通過中斷獲取的記憶體佈局圖,BIOS專家們都叫把它做E820圖

代碼:

Base Size Type
0   9E800  1
9E800  1800  2
D2000  2000  2
DC000  24000  2
100000  BF17C000  1
BF27C000  6000  2
BF282000 DD000  1
BF35F000  12000  2
BF371000  1000  4
BF3F2000 1D000  2
BF40F000  60000  1
BF46F000 1F9000  2
BF668000  80000  4
BF6E8000  27000  2
BF717000  8000  1
BF71F000 4C000  1
BF76B000 C000  4
BF777000  3000  3
BF77A000  7000  4
BF781000  1000  3
BF782000  9000  4
BF78B000  1000  3
BF78C000  13000  4
BF79F000  60000  3
BF7FF000  1000  1
BF800000  800000  2
E0000000  10000000  2
FEAFF000  1000  2
FEC00000  10000  2
FED00000  400  2
FED1C000  4000  2
FED20000  70000  2
FEE00000  1000  2
FF000000  1000000  2
100000000  38000000  1

圖中type為1的就是分配給本機實體記憶體的位址,其他的為其他硬體所用,我們把記憶體位址挑出來:

代碼:

Base Size
0      9E800
100000    BF17C000 BF282000 DD000 BF40F000  60000
BF717000  8000
BF71F000 4C000 BF7FF000  1000
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傳過去,這個結構體原型為

代碼:

typedef struct _LOADER_PARAMETER_BLOCK {
    LIST_ENTRY LoadOrderListHead;
    LIST_ENTRY MemoryDescriptorListHead;
    LIST_ENTRY BootDriverListHead;
ULONG KernelStack;
…… 後面太長,省略掉
} LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK;

既然沒有XP的源碼,那就用wrk將就一下吧,將wrk編譯的內核檔wrkx86.exe來替換ntkrnlpa.exe,系統肯定是起不來的,不過我們只需要在wrkx86.exe的進入點列印出NTLDR傳過來的記憶體描述鏈表就好了,MEMORY_ALLOCATION_DESCRIPTOR的原型為

代碼:

typedef struct _MEMORY_ALLOCATION_DESCRIPTOR {
    LIST_ENTRY ListEntry;
    TYPE_OF_MEMORY MemoryType;
    ULONG BasePage;
    ULONG PageCount;
} MEMORY_ALLOCATION_DESCRIPTOR, *PMEMORY_ALLOCATION_DESCRIPTOR;

於是我們很快得到了結果:(無法上圖,遺憾)

咦!NTLDR貌似真的沒有把4G以上的位址傳過來啊,怎麼到FF000這塊記憶體就完了呢?

難道NTLDR私自把4G以上的位址給裁了?難道一切罪惡的源泉在NTLDR?在此我犯了個嚴重的錯誤,以為勝利在望,加班加點研究NTLDR,最好成功跳過NTLDR截去4G以上記憶體的代碼了,啟動發現XP依然顯示2.98G的可用記憶體,怎麼回事呢?回過頭來再分析NTLDR,才發現了如下的代碼

代碼:

if ( (_BYTE)BlUsePae_0 )
    {
      v10 = BlpAllocatePAETables();
      if ( v10 )
        return v10;
    }
    else
    {
      BlpTruncateDescriptors(0xFFFFFu);
}

BlpTruncateDescriptors(0xFFFFFu)函數的功能就是設置記憶體描述鏈表的最大頁面號為0xFFFFF,即截去4G以上的記憶體,原來我們編譯的wrkx86.exe不支援PAE,被NTLDR發現了,故而才調用BlpTruncateDescriptors截斷的,而我們的XP用的內核ntkrnlpa.exe是支援PAE的,那麼就不會截斷了,哎,馬虎啊。。。

那還是鎖定ntkrnlpa.exe分析吧,充分發揚廢寢忘食的精神,終於找到了一個可疑的函數ExVerifySuite,這不會就是驗證我們版本的函數吧,網上一查,發現有位「老生常談」早就發現了,他的文章在這裡

HTTP://thxlp.wordpress.com/2008/08/03/老生常谈-windows和4g以上物理内存/

汗。。。。差距啊,不過這位老大發現這麼久竟然不出補丁,拯救我們廣大百姓于水貨,哎。。。害我熬夜傷神這麼久。。。。

不過這位「老生」的代碼不知道從哪裡搞的,nt4源碼裡沒有MiCheckPaeLicense這個函數,而windows2000的原始程式碼裡雖然有這個函數,但差別很大,wrk的原始程式碼裡也不是那樣的,反彙編XP的ntkrnlpa.exe,代碼如下

代碼:

int __usercall MiCheckPaeLicense<eax>(PLOADER_PARAMETER_BLOCK LoaderBlock<eax>)
{
  EndPage = 0;
  LoaderBlock1 = LoaderBlock;
  MaxPageCount = 0x100000u;
  MaxPage = 0;
  if ( ExVerifySuite(DataCenter) == 1 )
  {
    if (LoaderBlock->u.I386.VirtualBias )
    {
      MaxPageCount = 0x400000u;                 // booting /3gb: 16G MaxPage = 0x400000u;
    }
    else
    {
      MaxPageCount = 0x1000000u;
    }                                           // DataCenter: 64G
  }
  else
  {
    if ( MmProductType == 0x690057 || ExVerifySuite(Enterprise) != 1 )
    {
      if ( ExVerifySuite(ServerAppliance) == 1 )
        MaxPageCount = 0x80000u;                // 2G else MaxPage = 0x100000u;                    // 4G
    }
    else
    {
      MaxPageCount = 0x800000u;// Advanced Server is permitted a maximum of 32gb
    }
  }

實在是不知道這位高人的代碼來自哪裡,懇請各位高人給予指點。。。

從這段代碼裡可以看出,MiCheckPaeLicense函數會檢查作業系統的版本,如果是DataCenter,就允許使用64G記憶體,Advanced Server為32G,如果為精簡版則為2G,其他版本為4G,看來真是ntkrnlpa.exe在作怪,先別急著patch,驗證記憶體限制的還有一個地方,在MmAddPhysicalMemoryEx函數裡也會調用ExVerifySuite這個函數,代碼如下:

代碼:

if ( ExVerifySuite(DataCenter) == 1 )
  {
    LimitPage = 0x1000000u;                     // DataCenter : 64G
  }
  else
  {
    if ( MmProductType == 0x690057 || (v9 = ExVerifySuite(Enterprise) == 1, LimitPage = 0x800000u, !v9) )// Advanced Server : 32G LimitPage = 0x100000u;                    // Other : 4G
  }

代碼都差不多,要patch的話兩個地方要一起改,至於怎麼改?代碼都在這麼裡,想怎麼改就怎麼改吧,只要兩個地方都改了就行,只要其中一個地方不改,ntos都會陰魂不散的把你多出來的記憶體吃掉...

看成果吧

代碼:

lkd> dd MmHighestPhysicalPage 8088b124 00137fff 000f7399 00000040 00000000

lkd> dd MmNumberOfPhysicalPages 8088b128 000f7399 00000040 00000000 7fff0000 lkd> !pte d0800000 VA d0800000 PDE at C0603420 PTE at C0684000 contains 00000001004DF963 contains E15C080000000400 pfn 1004df -G-DA--KWEV not valid Proto: E15C0800

數數這個位址1004DF963,9位啊,4G以上了,不要被E15C080000000400這個位址嚇到了,64位,有這麼大的位址嗎?查查PTE的結構體就知道了,前面的幾位是標誌位

再看實體記憶體塊

代碼:

lkd> dd poi(MmPhysicalMemoryBlock)
8baa3c70  00000008 000f73ab 00000001 0000009d 8baa3c80  00000100 000bf17c 000bf282 000000dd 8baa3c90 000bf40f 00000060 000bf70f 00000008
8baa3ca0 000bf71f 0000004c 000bf7ff 00000001
8baa3cb0  00100000 00038000 0001000a 6c4d6d4d

看到了嗎,我的機器現在有8塊可用的記憶體了,多了一個100000-138000,總共有f73ab頁了,0xf73ab*0x1000=3.86G,至於還有140M,主機板沒映射,用不到了,能不能解決呢?希望各位牛人能夠給予指點。。。

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

忙裡偷閒,補丁寫好了,趕緊傳上來共用,本機測試通過,如果使用過程中發現問題請給我留言。。。

——————————————————————————————————————————

最近忙死了,幾天沒上網了,更沒時間去研究這個,讓各位失望了。。。 罎子裡的牛人們如果有時間去研究研究吧,MengXP執著的鑽研精神讓我佩服,離成功只有一步之遙了,希望大家能齊心協力,早日解決這些問題,我只能忙過這陣子再來了。。。

—————————————————————

實在抱歉,上個版本出的太匆忙了,嚴重問題都沒有發現,下載這個版本XP64G20110805.rar的朋友請罵我,實在是疏忽大意,抱歉抱歉。。。。

———————————————————————————————————————————————-

終於有時間繼續研究一下了,發現原因主要在DMA,修改之後,USB存放裝置基本可以正常使用了,先上補丁,回頭再發技術帖

下載位址:http://yunpan.cn/Q7pgJbr4Sz5m2 (提取碼:e85a)


文章轉自:http://bbs.pediy.com/showthread.php?t=137830



發表評論?

2 條評論。

  1. 偏偏就買了一個1g + 2g的記憶體條。。

  2. 修改硬體好怕怕的。我直接裝了64位的系統了。

發表評論


无觅相关文章插件,快速提升流量