2007年 11月 3日 (土)2010年 5月 8日 (土)Real UNIX MAGAZINE Day 第四回 カーネル／YUREX 探検隊

いまどきの Binary Hacks
前編首藤 一幸

Binary Hacks• 大好評！
日本語版

著者 (韓国語):

韓国語訳

타카바야시 사토루우카이 후미토시사토 유스케하마지 신이치로슈도 카즈유키日本語訳 (by OCN)
高林サトル
右カイ・フミトシ
佐藤ユウスケ
カバ紙シンイチロウ
首藤カズユキ日本語訳 (by Excite)

2006年 11月

2007年 7月

他カバー夜店Satoru
鵜飼フミトシ佐藤Yusuke
下馬だShinichiでシューもKazuyuki

ウェブ系：うたごえ検索 ウタゴエ(株)• はなうた歌って曲を検索。タタタ～♪
• PC 版のユーザ側は Flash で作ってある。

PC 版 うたごえ検索

録音した音声をサーバ側で解析ウェブ系を支える
バイナリ技術
オールドタイプの皆様に癒しを御提供Flash の音声フォーマット
• うたごえ検索: ブラウザ側の Flash Player で録音した音声を、サーバ側で解析。
– 録音結果ファイル: ○○.flv (Flash Video)• Nerrymoser という CODEC でエンコードされている。解析のために要デコード。
– ffmpeg も未サポート。
– 数千ドル (!!!) のコンバータを買うのか？？？

• Linux 用の flv2mp3 が見つかった！
これでデコードできるか！？

flv2mp3• Debian GNU/Linux for x86 用のバイナリ。ソースなし。
• アクロバティックな作り– Adobe が配布している Flash Player の共有ライブラリ
libflashplayer.so を使ってデコード。
音声デバイスへの出力を横取りする。

flv2mp3• Fedora Core 6 では落ちる！

– 僕らは Red Hat 系列, Fedora に慣れてるので、Fedora で使いたい！

このへん• バイナリアン や old type にとって、「Segmentation Fault は友達！」なにはともあれ GDB• ん？ libX11.so の中で落ちてる？

– libX11: X Window System の中心的なライブラリ

このへん逆アセンブル• % objdump –d /usr/lib/libX11.so.6

1つの関数

ret 命令で落ちてるret 命令で落ちるということは• 戻り先のアドレスが不正になっている。

– 戻り先アドレスは、スタックから pop する。

• GDB から、スタックポインタの値と、スタック上の値を調査。

スタックポインタベースポインタ
プログラムカウンタ

スタック
成長の方向

スタック上の値…
0x 08c09cb8

数値的に見て0x 49f86758 … コードのアドレス

0x bfacad58 … スタックのアドレス
0x 4a04ab24

スタックポインタスタックポインタのズレ？
ここで落ちてるスタック成長の方向

こうなっていれば、つじつまが合う。

…
0x 08c09cb8

数値的に見て0x 49f86758 … コードのアドレス
0x bfacad58 … スタックのアドレス
0x 4a04ab24

スタックポインタ

スタックポインタ ベース
ポインタへ pop
ベース
ポインタへ pop

• ままままさか、スタックポインタがズレてる！？

スタックポインタをズラしてみる

0x18 に変更
ここで落ちてる• ちょうど、直前でスタックポインタの値を調整している。
• 調整幅を変更– 1要素分多めに: 0x14 → 0x18

libX11.so をイジる
• 変更したい個所の、ファイル中の位置を調べる。
– % objdump –hd /usr/lib/libX11.so.6.2.0.text セクション中の位置:
0x49f86b21 – 0x49f60f90 =0x25b91
変更したい個所

0x49f86b21.text セクション自体のファイル中の位置: 0x14f90

変更したい個所のファイル中の位置:

0x14f90 + 0x25b91 = 0x3ab21

libX11.so を ×××• お好みのバイナリエディタで。

– Emacs の hexl モードとか beav とか。

0x18 に変更• イジった libX11 を使う。

– /usr/lib/libX11.so… を置き換え → 運が悪いと X が起動しない。
– 環境変数 LD_PRELOAD を指定して、変更版 libX11 を preload。
• env LD_PRELOAD=…/libX11.so.6 flv2mp3 …

flv2mp3 が動いた！
イジった libX11 を使用• めでたしめでたし！

ん？

libX11.so を ××× って、どうよ？
• きちんとコンパイルされて、整合がとれているはずの libX11.so を壊している。

– 通常の使用では、かえって問題が起きるはず。

• そもそも、なんでスタックポインタの値がズレるの？
– ありえない。

後編 ～ 真の解決へ ～ に続く2010年 5月 8日 (土)第四回 カーネル／YUREX 探検隊

いまどきの Binary Hacks
後編
首藤 一幸

なぜスタックポインタがズレるのか？
• この関数自体には、問題なさげ。

libX11.so
内の書き換えた関数

対応

この時点以前でズレてる 呼んでいる関数の中で何かがスタックポインタの変化を調査• ブレークポイントをところどころに設定。

PLT (Procedure Linkage Table) 中のioctl 関数用コードのアドレス

ioctl 呼び出し直前の状態

ioctl 呼び出し直後の状態
あってはいけないこと

call 命令の前後でスタックポインタの値が変化してる！

ioctl 関数の中で何が起きるのか• とりあえず、GDB から逆アセンブル。
メモリ上• よくよく眺めるために、コマンドラインから libc を逆アセンブル。

– 注: ioctl(2) はシステムコールだが、glibc は関数として提供する。

ライブラリ内ん？
flv2mp3 のプロセス空間 (メモリ) と libc (ライブラリ) で、ioctl 関数の内容が食い違っている！?

では、flv2mp3 が使う ioctl 関数はどこから来るのか？

• プロセス空間内で、ioctl は 0x804dfd0 に置かれている。
flv2mp3 のプロセスIDを調べ

0x804dfd0 番地の内容がどのファイル由来かを調べる• libc ではなく、flv2mp3 自身の中に ioctl 関数がある？

flv2mp3 内の ioctl 関数• flv2mp3 自身が ioctl を提供していることが判明。

メモリ上のものと同じ内容• Adobe 提供の libflashplayer.so 向けに、特殊な ioctl 関数を提供しているのだろう。
– たしかに、ioctl の引数によって色々と条件分岐している。
– 特定の引数に対して、特別な処理をしているのだろう。

flv2mp3 内の ioctl 関数• flv2mp3 内の ioctl 関数は何をしているか？
スタックポインタの値はなぜズレるのか？
• 処理を追う。
逆アセンブル• 末尾で、EAX レジスタに格納されているアドレスにジャンプしている。どこに飛んでいる？

flv2mp3 内の ioctl 関数• 末尾のジャンプ命令で、どこに飛ぶのか？
ジャンプ命令にブレークポイントを設定

ジャンプ先である EAX レジスタの中身を調査
ジャンプ先を逆アセンブル• どうも syscall 関数にジャンプするらしい。
– 呼び出し (call) ではなくてジャンプ (jmp)。
– つまり、syscall からの return をこの ioctl からの return ということにしてしまう。

flv2mp3 内の ioctl 関数• ioctl 関数から syscall 関数に直接ジャンプ。
– syscall は、任意のシステムコールを呼び出す関数:
syscall(システムコール番号, システムコールの引数, …)• syscall へのジャンプ直前のスタックを調べる:

スタック
成長の方向

…
0x

541b0x40x360x 49f86b1f

ioctl の種類
ファイル
ディスクリプタ

ioctl のシステムコール番号

ioctl からの戻り先アドレス

参考: ioctl の種類: FIONREAD

syscall のioctl の第２引数

第１引数

第３引数
第１引数

第２引数

flv2mp3 内の ioctl 関数• ioctl 関数の末尾では、syscall 関数を呼ぶために、引数の積み直しをしている。
(1)
(2)
(3)
(4)

スタック
成長の方向

ioctl 向けの積み方…
0x541b0x

40x 49f86b1f…

syscall 向けの積み方…
ioctl の種類
ファイル
ディスクリプタ
ioctl からの戻り先アドレス

(1)

(2)

即値 0x36(3)

EDX レジスタ(4)

ECX レジスタ0x541b0x40x36

0x 49f86b1f

ioctl のシステムコール番号
ioctl からの戻り先アドレス

flv2mp3 内の ioctl 関数を呼び出した側にしてみると• ioctl を呼んだつもりが syscall が実行される。
– ここまでは、いい。

• 積んだおぼえのない引数が１つ余分にスタックに積まれている！
– ioctl のシステムコール番号 0x36

• 呼び出し側では、後始末のしようがない。
– 注: 引数は、呼び出し側が積み、後始末する。
後始末: スタックポインタの復旧

flv2mp3 内 ioctl 関数の修正• そもそも、わざわざ引数を積み直してsyscall を実行せずとも、libc 標準の ioctlを呼べばいいんじゃね？
• flv2mp3 内の「ioctl」からlibc.so 内の「ioctl」を呼べるのか？
– 同じ名前。
– 呼べないかも。

• syscall 実行、という路線は変えない。

flv2mp3 内 ioctl 関数の修正• syscall 実行後に、適切にスタックポインタを補正する。
修正前のコード

修正後
(1)
(2)

(3)
(4)

(1) ioctl からの戻り先アドレスを ESI レジスタに保存する。
(2) ジャンプではなくて、syscall 関数を普通に呼び出す。
(3) syscall 向けに余分に積んだ引数の分、スタックポインタを補正する。
(4) ioctl からの戻り先アドレスにジャンプする。

flv2mp3 の修正• アセンブルして、書き込むべき機械語列を把握する。
アセンブリコードを書き込んだファイルを用意

アセンブル
機械語列を覗く11バイト

flv2mp3 の修正• 変更したい個所の、ファイル中の位置を調べる。
– % objdump –hd flv2mp3

ここから変更.text セクション中の位置:
0x804e0da – 0x804a520 =0x3bba22バイト書き込む余裕がある。
.text セクション自体のファイル中の位置: 0x2520

変更したい個所のファイル中の位置:
0x2520 + 0x3bba = 0x60da

flv2mp3 の修正• お好みのバイナリエディタで。

– 書き込む: 59 5e 6a 36 ff d0 83 c4 04 ff e6• 残りの 11 バイト分は、0x90 (NOP) でも書き込んでおく。
– これをやらないと、逆アセンブル時に困る:

不正命令

エラー

おかしなことにハッピーエンド• 改造版 libX11.so なしでもflv2 mp3 が動いた！

いまどきの Binary Hacks•ウェブ系でも大活躍！
– GDB– GNU binutils の objdump– x86 アセンブリコード• 含 calling convention (呼び出し規約)– ELF オブジェクト• .text セクションとか PLT とか– バイナリエディタ– dynamic linker/loader のオプション• 環境変数 LD_ほげほげ– /proc ファイルシステム• メモリマップ– システムコール・ライブラリ関数– gcc の各種オプション• -c とか –S とか –E とか– 勘