PE勉強会#3参加メモ

はじめに

PE勉強会(3)に参加してきました。学んだことを基に、数回に分けて実験したりメモを残したりしていきます。

参考リンク

本題に入る前に

先日作ったバイナリ編集ツールを色々更新しました。

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 読み取り専用のグローバルデータ領域

変数の種類によって適切なセクションに置かれていることが確認できました。

(メモ)

  • .bssに置かれる変数のアドレスが、宣言の順と逆なのは何か意味がある?
  • 初期値を設定していない変数(a)も.bssに置かれる。初期値は0に設定される?
ダンプして変数の値を眺めてみる

変数が置かれているアドレスがわかったので、ダンプしてその値を確認します。

自作ツールの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周りを整理したりする予定です。