PE勉強会#3参加メモ
はじめに
PE勉強会(3)に参加してきました。学んだことを基に、数回に分けて実験したりメモを残したりしていきます。
参考リンク
- 主催者のblog. 当日使用した資料やtogetterまとめなど
- ATND
本題に入る前に
先日作ったバイナリ編集ツールを色々更新しました。
16進数を受け付けたり、オプションを増やしたりなどなど。
詳細は下記リンクへ。
http://code.google.com/p/ta-binary-edit/source/browse/
このツールを使って色々実験します。
セクション
前回の復習として、最初にPEの構造について学びました。変数やプログラムコードなどは種類に応じて複数あるセクションと呼ばれる領域に置かれます。
それを実験で確認してみました。
セクションの確認
最初にこんなコードを書いてみました。変数を宣言して、そのアドレスを表示させます。
PE勉強会#2の資料にも似たようなコードが載っています。
% cat test.c #include <stdio.h> int a ; int b = 0 ; int c = 0xfedcba98 ; const int d = 0 ; const int e = 0x01234567 ; int main( ) { printf( "int a : %p\n", &a ) ; printf( "int b = 0 : %p\n", &b ) ; printf( "int c = 0xfddcba98 : %p\n", &c ) ; printf( "const int d = 0 : %p\n", &d ) ; printf( "const int e = 0x01234567 : %p\n", &e ) ; printf( "sizeof( int ) = %x\n", sizeof( int ) ) ; printf( "e = %x\n", e ) ; return 0 ; }
コンパイルして実行します。
% gcc -o test.exe test.c % ./test.exe int a : 004050BC int b = 0 : 00405020 int c = 0xfddcba98 : 00402000 const int d = 0 : 00403064 const int e = 0x01234567 : 00403068 sizeof( int ) = 4 e = 1234567
続いてobjdumpを使ってPEファイル(test.exe)のセクション情報を見ます。
% objdump -h test.exe ./test.exe: file format pei-i386 Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000dd8 00401000 00401000 00000400 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA 1 .data 00000014 00402000 00402000 00001200 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .rdata 00000214 00403000 00403000 00001400 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .eh_fram 00000004 00404000 00404000 00001800 2**2 CONTENTS, ALLOC, LOAD, DATA 4 .bss 00000100 00405000 00405000 00000000 2**3 ALLOC 5 .idata 000003c8 00406000 00406000 00001a00 2**2 CONTENTS, ALLOC, LOAD, DATA 6 .CRT 00000018 00407000 00407000 00001e00 2**2 CONTENTS, ALLOC, LOAD, DATA 7 .tls 00000020 00408000 00408000 00002000 2**2 CONTENTS, ALLOC, LOAD, DATA
変数のアドレスとセクションのアドレス(VMA)をまとめるとこうなります。
変数 | セクション | 備考 |
---|---|---|
a, b | .bss | 初期値ゼロのグローバル変数領域 |
c | .data | 初期値を持つ(ゼロ以外)グローバル変数領域 |
d, e | .rdata | 読み取り専用のグローバルデータ領域 |
変数の種類によって適切なセクションに置かれていることが確認できました。
(メモ)
ダンプして変数の値を眺めてみる
変数が置かれているアドレスがわかったので、ダンプしてその値を確認します。
自作ツールのbinary_viewを使います。これはcsvで設定されたアドレスのデータを表示するツールです。
変数eの値を見ます。eのアドレスは0x403068です。.rdataのオフセット(.rdataの先頭アドレス)は0x403000で、eの.rdataの先頭からのオフセットは0x68です。
このアドレスはメモリ中でのアドレスです。text.exeファイルを覗こうとしているので、ファイル中のアドレスに変換します。objdumpの結果を見ると、ファイル中の.rdataのオフセットは0x1400であることがわかります。ここに0x68を足した0x1468がtest.exe中のeのアドレスです。
text.exeの結果よりsizeof( int )が4(byte)であることがわかっています。つまり、0x1468 - 0x146bにeの値が入っています。
そこでこのようなcsvを用意しました。アドレス0x1468 - 0x146bの値を表示します。
% cat view.csv
e,1468,146b
そしてbinary_viewの実行。-xオプションはcsvファイルに書かれている値が16進数であることを示します。
% binary_view -x view.csv test.exe e : 67 45 23 01
eの値が0x01234567であることが確認できました。(このマシンはリトルエンディアン方式なので低位バイトから 67 45 23 01となる)
binary_viewの動作を確認するためにも、念のため16進数ダンプして該当アドレスを眺めました。dumpというのは自作ツールでバイナリファイルを16進数ダンプします。(od使っても良かったんですが、せっかくツールを作ったので)
% dump test.exe | grep 1460 01460 : 66 6F 00 00 00 00 00 00 67 45 23 01 69 6E 74 20
0x1468 - 0x146bが0x01234567であることがここでも確認できました。
バイナリハック!
変数のアドレスがわかったので、今度はこの値を書き換えてみます。
binary_editという自作ツールを使います。これはcsvで設定されたアドレスの値を書き換えるツールです。
以下のcsvファイルを用意しました。eの値を0x89abcdefに書き換えます。(変更する値をを1アドレスずつ指定しないといけないのがこのツールの面倒なところ)
% cat edit.csv 1468,1468,ef 1469,1469,cd 146a,146a,ab 146b,146b,89
binary_editを実行し、新たに生成されたtest2.exeを実行します。binary_editの-xオプションはcsvファイルに書かれた値が16進数であることを示します。
% binary_edit -x edit.csv test.exe test2.exe % ./test2.exe int a : 004050BC int b = 0 : 00405020 int c = 0xfddcba98 : 00402000 const int d = 0 : 00403064 const int e = 0x01234567 : 00403068 sizeof( int ) = 4 e = 89abcdef
成功です! eの値が0x89abcdefに書き換えられています。
とっても小さい歩幅ですが、バイナリハックの第一歩を踏み出しました!
終わりに
今回(前回かも?)学んだセクションという知識を使って色々実験してみました(遊んでみました)。
やはり自分で色々考えながら手を動かすと理解が深まります。
実験に自作ツールを使っているので、みなさんには書いている内容がわかりづらいかもしれません。すみません。
次回以降のメモではobjdumpではなく16進数ダンプしてセクション情報(オフセット情報とか)を確認したり、Thunkなど.idata周りを整理したりする予定です。