シェルコードが置かれているアドレスを得る
シェルコード実行中にシェルコードが置かれているアドレスを得る方法についてのメモ。
callを使う
callを実行したとき、スタックにリターンアドレスとしてcallの次の命令のアドレスが積まれることを利用する。
/* geteip_call.s */ .intel_syntax noprefix .globl _start _start: jmp caller callee: jmp main caller: call callee main: pop ecx int3
アセンブルして対応するバイト列を確認してみる。
$ gcc -nostdlib geteip_call.s $ objdump -d a.out 08048098 <_start>: 8048098: eb 02 jmp 804809c <caller> 0804809a <callee>: 804809a: eb 05 jmp 80480a1 <main> 0804809c <caller>: 804809c: e8 f9 ff ff ff call 804809a <callee> 080480a1 <main>: 80480a1: 59 pop ecx 80480a2: cc int3
デバッグ用のint3命令を除くと、このコードの長さは9バイトである。 実行すると、ecxレジスタにcallの次の命令のアドレスがセットされる。
$ gdb -q a.out Reading symbols from /home/user/tmp/a.out...(no debugging symbols found)...done. (gdb) r Starting program: /home/user/tmp/a.out Program received signal SIGTRAP, Trace/breakpoint trap. 0x080480a3 in ?? () (gdb) i r ecx ecx 0x80480a1 134512801 (gdb) quit
fnstenvを使う
x87 FPU命令のfnstenvが書き出す環境情報に、直前に実行したFPU命令のアドレスが含まれることを利用する。
具体的にはfnstenvが書き出すデータの12-15バイト目にこのアドレスが入るので、fnstenvのオペランドとして[esp-12]
を指定し、pop命令により取り出す。
/* geteip_fnstenv.s */ .intel_syntax noprefix .globl _start _start: fnop fnstenv [esp-12] pop ecx int3
fnop命令は普通のnop命令と同じく何もしないFPU命令であるが、ここで使うFPU命令は何でもよい。
アセンブルして対応するバイト列を確認してみる。
$ gcc -nostdlib geteip_fnstenv.s $ objdump -d a.out 08048098 <_start>: 8048098: d9 d0 fnop 804809a: d9 74 24 f4 fnstenv [esp-0xc] 804809e: 59 pop ecx 804809f: cc int3
デバッグ用のint3命令を除くと、このコードの長さは7バイトである。 実行すると、ecxレジスタにfnop命令のアドレスがセットされる。
$ gdb -q a.out Reading symbols from /home/user/tmp/a.out...(no debugging symbols found)...done. (gdb) r Starting program: /home/user/tmp/a.out Program received signal SIGTRAP, Trace/breakpoint trap. 0x080480a0 in ?? () (gdb) i r ecx ecx 0x8048098 134512792 (gdb) quit