はじめに
書籍「実践バイナリ解析」第6章の終わりに、以下の練習問題がありました。
objdumpを混乱させるプログラムを記述してみよう。
という訳で、本記事ではobjdumpによる解析を妨げるHello Worldプログラムの作成を試みます。
方針
objdumpのような線形逆アセンブラは、解析対象のセクション内にデータが含まれていた場合、そのデータを誤って命令として認識してしまう可能性があります。
従って本記事では、.textセクションのmainシンボル内にデータを挿入してobjdumpによる解析を妨げられないかを試します。
実装
以下のプログラムを実装しました。
#include <stdio.h> int main(void){ char* a; __asm__("jmp HOGE \n\t" "HELLO: \n\t" ".string \"Hello World!\" \n\t" "HOGE: \n\t" "mov %0, OFFSET FLAT:HELLO \n\t" : "=r" (a) ); printf("%s\n", a); return 0; }
インラインアセンブラを用いて.string \"Hello World!\"
をコード内に挿入し、かつ挿入したデータを命令として実行しないようにjmp
命令を使用しています。
なお、上記プログラムはintel構文を使ってインラインアセンブリを記述しているので、コンパイル時には-masm=intel
オプションを追加する必要があります。
コンパイル&実行
コンパイル
$ gcc -masm=intel -o hello.elf hello.c
実行
$ ./hello.elf Hello World!
objdumpによる逆アセンブル
objdumpの実行
$ objdump -d -M intel hello.elf
実行結果(抜粋)
0000000000400526 <main>: 400526: 55 push rbp 400527: 48 89 e5 mov rbp,rsp 40052a: 48 83 ec 10 sub rsp,0x10 40052e: eb 0d jmp 40053d <HOGE> 0000000000400530 <HELLO>: 400530: 48 rex.W 400531: 65 6c gs ins BYTE PTR es:[rdi],dx 400533: 6c ins BYTE PTR es:[rdi],dx 400534: 6f outs dx,DWORD PTR ds:[rsi] 400535: 20 57 6f and BYTE PTR [rdi+0x6f],dl 400538: 72 6c jb 4005a6 <__libc_csu_init+0x46> 40053a: 64 21 00 and DWORD PTR fs:[rax],eax 000000000040053d <HOGE>: 40053d: 48 c7 c0 30 05 40 00 mov rax,0x400530 400544: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax 400548: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 40054c: 48 89 c7 mov rdi,rax 40054f: e8 ac fe ff ff call 400400 <puts@plt> 400554: b8 00 00 00 00 mov eax,0x0 400559: c9 leave 40055a: c3 ret 40055b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
HELLO
シンボル内に格納されているはずの"Hello World!"文字列が、誤って命令として解釈されました。
一方、HELLO
シンボル以外の部分は、コード内に.string \"Hellow World!\"
を挿入した影響を受けませんでした。
感想
objdumpによる逆アセンブルを妨げるのが元々の目的でしたが、結果としては.textセクション内にデータを挿入するだけで終わってしまいました。
「objdumpを混乱させる」ことに成功したかは微妙ですが、意外と簡単に.textセクション内にデータを挿入できたのは面白かったです。
参考サイト
GCCのインラインアセンブラの書き方 for x86 - OSのようなもの
gcc - Intel assembly syntax OFFSET - Stack Overflow