シェルコードが置かれているアドレスを得る

シェルコード実行中にシェルコードが置かれているアドレスを得る方法についてのメモ。

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

関連リンク