天天看點

[繼續讨論]關于Windows PE和.net assembly的加載

1. SizeOfImage對Windows PE記憶體加載的影響

我開始建立起來的概念是Windows PE都會全部加載進記憶體執行。當那個評論中有人提到了RAR自解壓EXE。我當時是想當然地認為RAR自解壓EXE同樣也會全部加載進記憶體. 後來經其他人的指出,還有做試驗,證明即使實體記憶體不夠大同時沒有頁面檔案的情況下也能解壓一個很大的檔案。我真有點想不透是什麼原因。當時有一個網友gussing提到了SizeOfImage參數, 讓我有點啟發。後來經過進一步的檢視,才知道RAR自解壓EXE是Windows PE的一種特例。這個特别之處就在SizeOfImage參數上。用Windbg裝入一個35M的RAR自解壓EXE, 然後用RAMMap檢視其實體記憶體占用.發現其記憶體占用大約是0x00020000. 再用CFF explorer VII檢視其PE檔案, 果然SizeOfImage字段是0x00020000.

其他的Windows PE檔案呢,如ntdll.dll,其SizeOfImage是0x00127000, 其檔案大小是1,202,168, 十六進制是0x1257F8. 看來SizeOfImage剛好和檔案大小相比對,剛剛足以裝下這個ntdll.dll本身。再看Windows檔案夾下許多其他的EXE/DLL, 很多都是SizeOfImage與其檔案大小剛好相比對。

綜上所述, SizeOfImage決定了PE加載到記憶體裡的大小。

2. Windoes PE是用File mapping加載的

網友Ivony一直說這個觀點。現在經過證明了。上一張圖來說明問題:

[繼續讨論]關于Windows PE和.net assembly的加載

圖一

這個圖二可以幫組你了解File mapping是怎麼運作的。

[繼續讨論]關于Windows PE和.net assembly的加載

圖二

3. 許多Windows PE是全部加載進記憶體的

上面那個圖一已經告訴我們MSPAINT.EXE在記憶體裡的實體位址,而且上下卷動一下,你會發現每個實體記憶體頁都是Active. 就是都在記憶體裡。當然了,不是所有的Windows PE都全部加載進記憶體。因為這受SizeOfImage參數影響。

4. .net assembly(即.net PE)也是全部加載進記憶體的

首先.net PE的SizeOfImage也是與其檔案大小相比對的。這是前提。接下來看看實際的證據:

我的.net PE檔案大小27M左右:

[繼續讨論]關于Windows PE和.net assembly的加載

圖三

運作之後,用RAMMap檢視實體記憶體頁狀态:

[繼續讨論]關于Windows PE和.net assembly的加載

圖四

[繼續讨論]關于Windows PE和.net assembly的加載

圖五

這個檔案很大。記憶體頁有很多。上下翻動看了一下,除了前面有一些Standby之外,大部分是Active,就是說大部分在記憶體裡面. 但是為什麼會有Standby呢?開始還是不太明白。直到我看到了VMMap給出的圖:

[繼續讨論]關于Windows PE和.net assembly的加載

圖六

[繼續讨論]關于Windows PE和.net assembly的加載

圖七

看到.net PE的這些節沒有: header, .text, .rsrc, .reloc, 還有标記為Reserved的節沒有。對比了非托管的Windows PE和.net PE, 在記憶體映像上是有差别的。非托管的Windows PE基本是全部裝入記憶體,而.net PE的記憶體映像總要空幾段。在header和.text之間要空一段,.rsrc和.reloc之間要空一段。

5.  另外一個問題, Working set 為什麼隻有7-8M大呢?

這個.net PE大部分實際上已經進了記憶體。但是為什麼這個程序的Working set為什麼隻有7-8M大呢?

想起了Working set的定義: The working set of a program is a collection of those pages in its virtual address space that have been recently referenced.

然後又想起了圖二。有點明白是什麼回事情了。那就是每個程序建立的File view不一樣。這個File View對Working set的大小有影響。

還是系統地讀<Windows Internals>比較好.

這裡說的,和看到的可能并不是真相。還請達人指點一二。

繼續閱讀