第二話:メモリマップから見るコードとスタックの場所

(このノートは最後まで無料で読めます。投げ銭方式です)

今回はメモリマップの見方のお話です。

まずは第零話の「ブレイクポイント」の章と同じく、main()関数のところにブレイクポイントを設置して実行します。EIPがmain()関数の最初の命令の行を指します。

そこで[View]メニューから[Memory Map]を選択。


別のウィンドウにメモリマップが表示されます。

これは何かというと。このプログラムに与えられた仮想アドレス空間です。

例えば1行目が何を表しているのかというと、「00010000」(Address)というアドレスから00010000分(Size)は「Heap」(Contains)であり、読み取りと書き込みの権限(Access)がある。という感じです。RWはReadableとWritableの略。

仮想アドレス空間については詳しく説明しようとするとハマるので簡単に言いますと、32ビット版Windowsでは、(物理的にどのくらいの容量のメモリが刺さっているのかにかかわらず)1つのプログラム(プロセス)には2の32乗ビット、つまり4GBの仮想アドレス空間が割り当てられます。プログラムはこの空間の中で実行するコードを展開したり変数に入れる値を書き込んだりいろいろするわけです。

ただし、実際にプログラムが自由に使える領域は半分の2GBです。メモリマップの最後の行を見ると、アドレスが80000000、サイズが7FFF0000の空間は「Kernel memory」に割り当てられていることが分かります。つまり後ろの2GBはカーネルが使っているのでプログラム自身は使えません。

これが64ビット版Windowsになると、理論上は2の64乗ビットで16E(エクサ)Bになります。が、実際には8TBしか使われていません。

コードの場所

さて、アセンブラコードに一度戻りましょう。(ウィンドウの名前は「CPU」です)
プログラムソースはsub()関数→main()関数の順に書かれているので、アセンブラコードもそのような並びになります。sub()関数の先頭のアドレスはここでは「00401000」です。(人によって違う場合があるので自分のものを確認してください)

メモリマップで00401000がどこに当てはまるか見てみましょう。

「main_sub」というオーナーの「Code」である。といえますね。main_subはexeファイルの名前です。

なんとなく分かると思いますが、main_sub.exeのアセンブラコードはこの場所に展開されます。

スタックの場所

もう一つこのシリーズで重要なのは「スタック(Stack)領域」です。第零話にもちらりと出てきました。詳しくは後の章で書きますが、簡単に言うと変数(ローカル変数)を読み書きしたり、レジスタの値を一時的に退避させたりする場所です。ここでは「0012D000」というアドレスから始まっています。

ここでCPUウィンドウに戻ってスタックのペインを見てみると・・。

「0012FF44」となってますね。main()関数を実行し始める前に使っちゃっているので、スタック領域の先頭である「0012D000」ではありませんが、スタック領域はサイズが00003000なので、0012D000から0012FFFFです。0012FF8Cも含まれていますね。

さて、ここでスタックセグメントの「Access」を見てみますと、RWで読み書き可、になっていますね。実行権限はありません。

このシリーズの最後で説明するつもりですが、昔ながらの「バッファオーバーフローを利用した任意のコード実行」はこのスタック領域を使って行われます。

例えば、main()関数の最初の命令は「PUSH EBP」でマシン語が「55」ですよね。
ローカル変数を「55」にすれば、スタック領域のどこかに「55」が書き込まれるわけですね。うまいことEIPがそこを指すようにすれば、プログラムは「PUSH EBP」を実行します。「55」を自分が実行したい命令のマシン語にしておけば、それを実行できるというわけです。

そこで最近のOSでは、そもそもスタック領域の実行権限をなくしてしまうという対策をとっています。DEP(Data Execution Prevention:データ実行防止)と呼ばれる方法です。(スタック領域に限らずデータが書き込まれる領域を対象としています)
Windowsでは、XP SP2から実装されています。

「スタック領域にコードを書いてそれを実行」という手法は、DEPその他の対策が当たり前になってきたためOSや(そのOS上で動く)アプリケーションに対しては減っています。が、制御システムやファームウェアなどではやられどころがまだまだありそうな手法です。

話がそれましたが、メモリマップから見るコードとスタックの場所のお話でした。

次回は、DEPの話が出たついでに、これもOSによるセキュリティ対策であるASLR(アドレス空間配置のランダム化)について書こうと思います。これもね、デバッガ使って見ると一目瞭然なんですよね。

(本稿はここで終わりです。ためになったという方、他のも読みたい!という方、投げ銭していただけると嬉しいです。)

ここから先は

0字

¥ 100

この記事が気に入ったらサポートをしてみませんか?