はじめに
この記事は、実機にメモリダンプを行い、中身がどうなっているのかを勉強する目的で投稿しています。投稿者は初心者であるため、誤解していることがあればコメントをお願いします。メモリダンプについてはFTK Imager、解析にはVolatility3を使用しています。
再度言いますが、初心者です。どうか温かい目で見守ってください。
今回やること
前回までは、メモリダンプ解析というマクロ的視点で記事を書いてきましたが、今回はプロセスのアドレス空間というミクロ的視点についてもまとめていきたいと思います。
物理アドレスと仮想アドレス
アドレスには大きく分けて二つの種類があります。実際のメモリの場所を示す物理アドレスと、CPUが使う論理的なアドレスである仮想アドレスです。
プロセスはそれぞれ独立した仮想アドレス空間を持っています。仮想アドレス空間はメモリ上に実在する領域ではなく、OSが管理する論理的な空間です。
また、プロセスは必ずしも物理メモリ上に全て存在するわけではなく、使用中のページがメモリに、使われていないページがディスクに置かれる場合があります。
ページとはディスクからメモリに読み込む単位のことで、通常4KBで構成されています。
仮想アドレス空間の構造はこんな感じです。
低位アドレスから高位にかけて説明します。
- テキスト:プログラムをコンパイルしたもの(機械語)が入っています
- データ:初期値がついている変数が保存されます
- BSS:初期値なしの変数が保存されます
- ヒープ:C言語のmalloc()で確保可能な領域です
- スタック:変数のパラメータ、リターンアドレス、ベースポインタ、ローカル変数が保存される領域です
- 引数と環境変数:関数の引数などの情報が保存されます
スタックは高位のアドレスから低位のアドレスにかけて領域を確保していき、ヒープは低位から高位にかけて領域を確保します。
0xc000000から0xffffffffは使用するOSによって大きさが異なりますが、基本的にカーネルが使う領域のため、使用禁止になっています。(画像はLinux x86 32bit)
プロセス生成からCPU処理までの流れ
プロセスが生成されるとOSがそのプロセスに対して仮想アドレス空間を生成します。
大事なことなので二回言いますが、仮想アドレス空間はメモリ上に実在しない論理的な空間です。
CPUは仮想アドレス空間内のテキスト領域にある命令を一つ読み実行、一つ読み実行を繰り返していきます。
命令の読み込み(命令フェッチ)
初回の読み込みは、ほぼページフォールトが起こり、それにより物理メモリに機械語がページ単位で読み込まれます。
その後は、物理メモリ上に機械語のページが存在する限り、CPUがテキスト領域に対応した機械語を読むことができます。具体的には、機械語(命令)を読むとき、CPUが仮想アドレスを生成し、MMUで変換後、対応する機械語が入っているメモリの物理アドレスにアクセスするという感じです。
機械語(命令)を読みに行くことを命令フェッチといいます。
命令の実行(データアクセスを必要とする場合)
機械語を読んだCPUが命令実行のため、データにアクセスしようとすると、仮想アドレスを生成します。
CPUは、仮想アドレス空間上で生成された仮想アドレスしか知らず、物理メモリのアドレスを意識することはありません。(CPUは仮想アドレス空間上で動作します)
仮想アドレスはMMUで変換され物理アドレスと対応します。
そしてCPUが物理メモリ上のデータにアクセスできます。
データが物理メモリ上になければ、ページ単位でその都度読み込まれます。
機械語(命令)を読むときと、その命令を実行してデータにアクセスするときは別々のアクセスです。
それぞれ独立して仮想アドレスを生成しMMU変換後、物理アドレスからメモリにアクセスしています。
※命令の内容によっては、上記のように2回アクセスする場合やそれ以上、または1回だけアクセスする場合があります。(命令実行にデータアクセスを必要としない場合などは、命令フェッチだけの1回のみのアクセスらしい)
今回はこのくらいにしておきます。自分にとってはなかなか理解が難しい内容でした。次回は前回言ったようにメモリダンプ内にあるレジストリ関係の情報について触れてみたいと思います。
参考文献
