ハッカーが見るメモリの世界 スタック・ヒープ・text・data・bssを解説

ペネトレーションテスト&バグバウンティ

パソコンやスマホの中で動いているプログラム。その中で「メモリ」はとても大事な役割をしています。そこで、ハッカーやプログラマーがよく見る「メモリの地図(メモリマップ)」について説明します 。

※イメージです。

なぜメモリマップが重要なのか

Linuxのプログラムを解析したり、CTFで脅威の極端をついたり、ゼロデイエクスプロイトを開発するために、メモリマップの理解は必須です。
これは「プログラムがどのようにメモリを使っているか」を解明する所で、脅威の発生ポイントや、防御技術の配置を理解するカギでもあります。

 

メモリマップとは

プログラムが実行されると、Linuxのメモリ上に次のような領域が割り当てられます。
 
メモリマップ全体像(簡易図解)
 
 

各メモリ領域の役割と特徴

textセクション

ここには、「実行されるプログラムの中身(プログラムの命令にあたる機械言語 )」が入っています。たとえば、「Aを計算してBを出す」などの手順がここに書かれていて、パソコンはこの命令を読んで実行しています。
これは読み取り専用(read only)です。NXビットにより、データ領域に不正なコードが書き込まれて実行されるのを防ぎます。 (勝手に書きかえることはできません。 )

dataセクション

プログラムを動かすとき、最初から値が決まっている変数(たとえば int x = 5;)など初期化されたグローバル変数 は、このエリアに入ります。実行中に書き換えることもできます。 
 

bssセクション

int y; のように、最初に値がない未初期化のグローバル変数 はこのエリアに置かれます。プログラムが始まると、自動的に「0」に初期化されます。 
 

ヒープ (heap)

malloc() や new を使って、必要なときにメモリを借りる動的メモリを確保する場所です。メモリを多く使うゲームやアプリでよく使われます。
ただし、使ったらちゃんと free() や delete で返さないと、メモリがムダに残ってしまい「メモリリーク」という問題になります。
 
 

スタック (stack)

スタックは、「一時的なデータ」をしまう場所です。関数の引数やローカル変数、戻り先のアドレスなどが入ります。
お弁当箱を積み重ねるように「後から入れたものを先に取り出す(LIFO)」のルールで動いています。入れすぎると「スタックオーバーフロー」になり、プログラムが壊れることもあります。
  
 

メモリマップとエクスプロイトの関係

メモリマップを知らないと、攻撃されるポイントが分からないからです。
 

具体的な例として

スタックオーバーフロー攻撃
バグでスタックに入りきらないデータを入れると、隣のデータ(リターンアドレス)を上書きできます。
それを悪用すると、好きな命令を実行させることができる!
 
ヒープオーバーフロー
malloc などで確保したヒープに、大きすぎるデータを入れると、他のヒープ領域を壊せます。
これを使って、重要な構造体を書き換える → 任意の関数を実行する。
 
.text領域の実行制限(NXビット)
スタックやヒープに悪いコードを入れても、実行ができないようにブロックされます。
しかし、攻撃者は「Return-Oriented Programming(ROP)」のような回避手段を使い、.text にある既存の命令を「部品」としてつなげて、意図した動作をさせる可能性があります。、 
 

どう守るのか

OSやコンパイラは、スタックカナリやNXビット、ASLRなどの技術でこのメモリマップを守っています。
 
 

ハッカーが見るメモリの世界:スタック・ヒープ・text・data・bssを解説のまとめ

ハッカーがメモリを操る理由は、このメモリマップをよく見て、どこに問題があるかを調べます。
たとえば、ヒープやスタックの使い方にミスがあると、そこからプログラムを乗っ取られることもあります。
この「メモリの世界」を理解することが、安全なプログラムを作る第一歩となります。