Windows 9x系のメモリマップ、ヒープ管理についての調査メモ

木村屋です。この記事は私のブログからの転載です。
Windowsのメモリマップについて簡単に調べてみました。Windows 9x系のメモリマップ、ヒープ管理についての調査結果のメモをまとめたので備忘録として公開します。
Windows NT系とx64のWindowsのメモリ管理の調査については別途行う必要があると考えています。
以下は調査結果のメモです。

Windowsのメモリ管理は仮想アドレス空間を使って行われる。物理アドレス空間から仮想アドレス空間への切り替えはWindowsが担当しているため（ページング処理）、Windowsのアプリケーションを書くプログラマの目から見えるメモリは仮想アドレス空間である。物理アドレス空間にどの様にWindowsが展開しているのかなどはアプリケーションを作るプログラマは意識しなくても問題が無いようになっている。IA-32の物理アドレス空間と仮想アドレス空間（ページング）の管理の詳細についてはインテルの『IA-32 インテル® アーキテクチャー・ソフトウェア・デベロッパーズ・マニュアル、下巻 システム・プログラミング・ガイド』か『はじめて読む486―32ビットコンピュータをやさしく語る』などを参照のこと。32bitのWindowsのメモリ管理の詳細については『インサイド Microsoft Windows 第4版 上』の『第7章メモリ管理』を参照のこと。64bitのWindowsのメモリ管理の詳細については『インサイドWindows 第6版 下』の『第10章メモリ管理』を参照のこと。
32bitのWindowsの場合、仮想アドレス空間の限界は4GBである。
Windows 9x系ではメモリ空間の使用目的をアプリケーションとカーネルに分けている（アプリケーションが使えるメモリの限界は2GB。残りの2GBはWindowsのカーネルが使用する。0x80000000H以上のアドレスはカーネルが使用し、全プロセスで共有する）。
0x00000000H～0x003FFFFFHにはMS-DOS領域、Win16領域下位が読み込まれる。この領域は全プロセス共有。
0x00400000H～0x7FFFFFFFHにはWin32アプリケーションが読み込まれる。この領域にはモジュール、ヒープ、ローカルDLLが存在。ローカルDLLは0x10000000Hに読み込まれる。プロセスが読み込まれる位置はexeファイルのPEヘッダのIMAGE_OPTIONAL_HEADER32構造体のメンバであるImageBaseによって指定される。プロセスごとに個別に存在する。この空間はタスクが切り替わるとページングによって、丸ごと別のメモリ空間に切り替わる。
0x80000000H～0xBFFFFFFFHには、Win16領域、メモリマップドファイル、カーネルシステムDLL（kernel32.dll, user32.dll, gdi32.dll, advapi32.dll）が存在する。この領域は全プロセス共有。
0xC0000000H～0xFFFFFFFFHには仮想デバイスドライバ、ページテーブル、ページディレクトリが存在する。この領域は全プロセス共有。
0xC0000000H～0xC03FFFFFHにページテーブルが存在し、0xE1000000H～0xFFBDFFFFHにページシステム領域の先頭、システムPTE領域、非ページシステム領域が存在する。このカーネル空間にあるページングに関する領域を何らかの方法を使って読むことができれば、Windowsの物理アドレス空間と仮想アドレス空間との関係が一対一で検証できると思われる（詳細は不明）。
32bitのWindowsの物理アドレス空間と仮想アドレス空間のマッピングについては『インサイド Microsoft Windows 第4版 上』の『第7章メモリ管理』の『7.5 アドレス変換』に解説がある。
Win32アプリケーションは通常0x00400000H以前、0x80000000H以降の領域に書き込みを行えない。
exeファイルをロードすると0x00400000Hにプログラムモジュール（一般的なWindowsのexeファイル）が読み込まれる。
exeファイルがDLLを使用する場合、0x10000000H以降に各DLLが読み込まれる。DLLに関する情報はexeファイル内のPEヘッダの後のセクションヘッダに書きまれている。
セクションヘッダはIMAGE_SECTION_HEADER構造体として管理されており、セクションの数だけセクションヘッダが存在する。DLLを管理するセクションの名前は.idataである。
.idataはインポートする関数の情報を管理する。.idataはインポートセクションと呼ばれる。
インポートセクションにはDLL名、関数名、関数名を示すRVA、実行可能アドレスを示すRVAが書き込まれている。
インポートセクションの情報を元にWindowsのイメージローダーはexeファイルの実行に必要なDLLの情報を取得し、読み込むものと思われる（この点については、今後、調査する。イメージローダーについてはntdll.dllにLdrからはじまるネイティブAPIが存在するので、今後はこの点を調査予定）。
0x40000000H以降はVB、MFCなどのランタイムDLLやクリップボードの領域に使われている。すべてのWin32アプリケーションで共有していると思われる（詳細不明）。
Windows 9x系は複数のヒープ領域を持ち、一番はじめのヒープ領域はデフォルトヒープと呼ばれる。
ヒープは比較的小さなメモリブロックの集合体。基本的にサイズは1MB以下。ヒープ領域は領域が不足すると自動的に拡張を行いサブヒープを生成する比較的大きなメモリブロック。サイズは自由。論理的に最大2GBまで拡張が可能。
ヒープ領域内の各ヒープは双方向循環リンクリストを用いて管理されている。
Windows 95では各ヒープ領域のサイズは特別な場合を除き、1MBで固定されていた。Windows 98からは状況によって変わる（Windows 98の場合はメモリ管理を高速に行うため、重いプログラムの場合、2回目以降の起動で各ヒープ領域のサイズを大きくするなどの処理を行っているらしい。詳細は不明）。その為、Windows 98の場合、デフォルトヒープから次のヒープ領域のアドレスは絶対ではない（Windows MEの場合については未調査）。

Windows 9x系のメモリマップ、ヒープ管理の調査結果については以上です。
正確性を期した積もりですが誤りがあった場合は文責はすべて私にあります。
以上です。今後もWindowsに関する調査は続行します。続報があれば、また記事を追加致します。

**引用文献**
たにしげ 2000 Win32メモリマップ&ヒープ管理解説 ExGAME vol.1 BRAINSTORM 72-73.
UNYUN 2001 Win32 Buffer Overflow 概要 Win32メモリアーキテクチャ ハッカー・プログラミング大全 63
ディビット ソロモン、マーク ルシノビッチ、David Solomon、 Mark Russinovich 2005 7.4.2 x86システムアドレス空間レイアウト インサイド Microsoft Windows 第4版 上 (マイクロソフト公式解説書) 487
ディビット ソロモン、マーク ルシノビッチ、David Solomon、 Mark Russinovich 2005 7.5 アドレス変換 インサイド Microsoft Windows 第4版 上 (マイクロソフト公式解説書) 495
ディビット ソロモン、マーク ルシノビッチ、David Solomon、 Mark Russinovich 2005 ページテーブルとページテーブルエントリ インサイド Microsoft Windows 第4版 上 (マイクロソフト公式解説書) 502
EXEファイルの内部構造（PEヘッダ）（1_3）：CodeZine　http://codezine.jp/article/detail/412
PE(Portable Executable)ファイルフォーマットの概要 http://home.a00.itscom.net/hatada/mcc/doc/pe.html
APIより効率的なCランタイムルーチンを活用する方法がわかりたい http://www7a.biglobe.ne.jp/~tsuneoka/win32sub2/10.html
Monthly Research「Heap Exploitのこれまでと現状」 - FFRI http://www.ffri.jp/assets/files/monthly_research/MR201312_History%20and%20Current%20State%20of%20Heap%20Exploit_JPN.pdf

**転載元**
南関東開発機構 : Windows 9x系のメモリマップ、ヒープ管理についての調査メモ
http://blog.livedoor.jp/south_kanto_dm/archives/52097657.html