ELF解析のはじめ
linuxの実行バイナリであるELFファイルの解析の仕方のメモ
IBMのスライドを参考にした。
http://www-06.ibm.com/jp/linux/tech/doc/attachments/002cb129_elf_v1_0.pdf
サンプルELFの作成
まず、サンプルとなるプログラムを用意する。
// func.c #include <stdio.h> int global_num = 0xaa00; int func1( int i ) { return global_num + i; } int func2( int i ) { return global_num + i + i; }
//main.c #include<stdio.h> extern int global_num; extern int func1( int i ); extern int func2( int i ); int main( void ) { printf( "global_num = %04x\n", global_num ); printf( "func1( 0x11 ) = %04x\n", func1( 0x11 ) ); printf( "func2( 0x22 ) = %04x\n", func2( 0x22 ) ); }
$ gcc -O0 -g -c -o func.o func.c $ gcc -O0 -g -c -o main.o main.c $ gcc -o main func.o main.o
解析に入る前に
まず、objdumpを使って逆アセンブルとデータを書き出しておく。
$ objdump -M intel -S main > main.txt $ objdump -s main > main.data
解析
.textセクションの最初から実行されるということなのでそこを見てみる。
Disassembly of section .text: 08048320 <_start>: 8048320: 31 ed xor ebp,ebp 8048322: 5e pop esi 8048323: 89 e1 mov ecx,esp 8048325: 83 e4 f0 and esp,0xfffffff0 8048328: 50 push eax 8048329: 54 push esp 804832a: 52 push edx 804832b: 68 10 85 04 08 push 0x8048510 8048330: 68 a0 84 04 08 push 0x80484a0 8048335: 51 push ecx 8048336: 56 push esi 8048337: 68 42 84 04 08 push 0x8048442 804833c: e8 cf ff ff ff call 8048310 <__libc_start_main@plt> 8048341: f4 hlt 8048342: 66 90 xchg ax,ax 8048344: 66 90 xchg ax,ax 8048346: 66 90 xchg ax,ax 8048348: 66 90 xchg ax,ax 804834a: 66 90 xchg ax,ax 804834c: 66 90 xchg ax,ax 804834e: 66 90 xchg ax,ax
0x8048510, 0x80484a0, 0x8048442というのは
それぞれ__libc_csu_fini, __libc_csu_init, mainの関数ポインタのようだ。
それらを適当にスタックに積んだ後で
__libc_start_main@pltという関数を呼び出している。
__libc_start_main@pltというのはどうなっているかというと、
08048310 <__libc_start_main@plt>: 8048310: ff 25 14 a0 04 08 jmp DWORD PTR ds:0x804a014 8048316: 68 10 00 00 00 push 0x10 804831b: e9 c0 ff ff ff jmp 80482e0 <_init+0x2c>
0x804a014のポインタ先に間接ジャンプしているらしい。
よくわからないのでIBMのスライドを見てみると、共有ライブラリの関数を呼ぶ場合は
実行時に関数ポインタが書き込まれるとのことだ。
gdbで実行してみる。
$ gdb main (gdb) b *0x8048510 (gdb) b *0x80484a0 (gdb) b *0x8048442 (gdb) run Breakpoint 2, 0x080484a0 in __libc_csu_init () (gdb) info stack #0 0x080484a0 in __libc_csu_init () #1 0xb7e2d89a in __libc_start_main (main=0x8048442 <main>, argc=1, ubp_av=0xbfffebd4, init=0x80484a0, <__libc_csu_init>, fini=0x8048510 <__libc_csu_fini>, rtld_fini=0xb7fed5f0 <_dl_fini>, stack_end=0xbfffebcc) at libc-start.c:219 #2 0x08048341 in _start ()
__libc_csu_initが呼び出された。この関数が何をやっているのかはよくわからないので
次に進むとmainが呼び出されている。
main部分は簡単に読むことができた。