第1章 総論
バッファオーバーフローを理解するための基礎知識

ヒープ

C/C++言語は、標準ライブラリを通じてもしくは言語そのものの演算子として、メモリブロックを動的に確保・解放する機能を備えている。malloc() と free()、new と delete がそれにあたる。
動的メモリブロックは「ヒープ」と呼ばれる仕組みで実現されている。

動的なメモリ割当

次の一連の図に、ヒープを用いてのメモリブロックの動的確保・解放の様子を示す。なお、実際のコンパイラや実行時ライブラリは、もう少し複雑なことを行っている。ここでは原理を示す。

(1) ヒープを用いた動的メモリブロックを獲得

図1-16: ヒープを用いた動的メモリブロック獲得

(2) もうひとつの動的メモリブロックを獲得

図1-17: もうひとつの動的メモリブロックの獲得

(3) 動的メモリブロックの解放

図1-18: 動的メモリブロックの解放

(4) さらに別の動的メモリブロックを獲得

図1-19: さらに動的メモリブロックの獲得

 

空きブロックの管理

ヒープのメモリ領域の中では、使用中のブロックと空きブロックが把握・管理されている。空きブロックの管理には双方向リンクの構造が用いられることが多い。空きブロックどうしがそれぞれ双方向のリンクで結ばれ、これらのリンク途中へのノードの挿入や除去の操作が行われる。

例えば、pointer = malloc (6000) の呼び出しに対しては、空きブロックのリンクの中から6000バイトを収容可能な大き過ぎない空きブロックが割り当てられるか、大きな空きブロックの一部が切り出されて6000バイトの空きブロックが作られ、これが使用中ブロックのリンクへ挿入される。free (pointer) の呼び出しに対しては、当該ブロックが使用中ブロックのリンクから取り外され、空きブロックのリンクへ挿入される。メモリ領域の中で空きブロックどうしが隣接するときは、より大きな空きブロックに併合されることもある。

図1-20: 空きブロックどうしが双方向リンクで結ばれている実装が多い

 

リトルエンディアン

C/C++言語プログラムに対する攻撃の中には、スタックやヒープのメカニズムに攻撃者が外部から干渉する手口がある。これらについて、具体的に何が起っているかを把握するにはメモリ内容の観察が不可欠である。メモリ内の二進数の値を解釈する際には、バイトの格納順序を意識する必要がある。システムによっては、「リトルエンディアン」という方式を採用しているからである。典型的には intel アーキテクチャが該当する。

リトルエンディアン方式では、複数バイトからなる二進数がメモリに格納される際、バイトが下位の桁から上位の桁へ向かって並べられる。例えば、0xA9876543という32ビット整数値は、アドレスの若い方から順に、[0x43, 0x65, 0x87, 0xA9]という4バイトの並びとしてメモリに置かれる。

図1-21: リトルエンディアン方式を用いたメモリ格納

バイトの格納順序のもうひとつの方式が「ビッグエンディアン」である。ビッグエンディアン方式では、複数バイトからなる二進数がメモリに格納される際、バイトが上位の桁から下位の桁へ向かって並べられる。

図1-22: ビッグエンディアン方式を用いたメモリ格納

メモリ内容を観察する際は、対象のシステムがリトルエンディアン方式とビッグエンディアン方式のどちらを用いているかを見極めた上で値を解釈する必要がある。