拾い物のコンパス

まともに書いたメモ

使えれば良いやradare2(静的解析編)

バイナリ関連の機能を一通り提供するフレームワークradare2,通称r2(d2はない模様)による静的解析をざっくりと紹介する.CLIベースの使い方はいろんなサイトが詳しくやっているから,Visual Modeの使い方を中心に解説する.

radare2について

radare2について軽く説明する.
radare2は64ビットオフセット対応の16進バイナリエディタとして,2006年から開発が始まった.途中でportable reversing frameworkになり,更に,いつの間にかradareからradare2へとバージョンアップしている.経緯は知らない.バイナリエディタとして使われているところを見たこともやったこともない・・・.
x86からxtensaなどのマニアックなアーキテクチャまで対応し,基数変換ツール(rax2)やアセンブラ(rasm2),バイナリ比較プログラム(radiff2)など細かい所まで提供してくれる,とても素晴らしいプラットフォーム!
といえば聞こえは良いが,現実には挙動にビックリな地雷を抱えているところがあり,全面的に信用して使うと痛い目にあうというのが正直なところ(個人的な感想).
今までに出会った例としては,デバッグ中のプログラムがセグフォを起こすと,出力が無限ループ起こした.他には,巨大なプログラムを解析しようとすると,関数フラグなどの収集が終わらない.この状態だとCtrl+cしても終了できない.Ctrl+zで停止させて,改めてkillする必要があった.まだ他にもある.

インストール

radare2をインストールしていない場合は,ubuntuならapt/apt-get install radare2,arch linuxならpacman -S radare2で簡単に見つかるはず.ただし,ubuntuのパッケージはバージョンが古いことがあり,機能の一部が実装されていない可能性もある.不安な人は自前ビルドするとよい.自前ビルドは

$ git clone https://github.com/radare/radare2
$ cd radare2 && sys/install.sh
$ sys/install.sh
rootでインストールしたくない人はホームディレクトリにインストールする方法もある.
$ sys/user.sh

で行う.

環境

$ uname -a
Linux poppycompass 4.7.6-1-ARCH #1 SMP PREEMPT Fri Sep 30 19:28:42 CEST 2016 x86_64 GNU/Linux
$ r2 -v
radare2 0.10.2-git 10613 @ linux-little-x86-64 git.0.10.1-156-gcb11996
commit: cb119968dd590fbb0719243eadd7344c7293b996 build: 2016-03-16

現行のバージョンは0.10.6(2016/10/26現在)だから,少し古いバージョンでの解説となる.
カーネルバージョンから,先日発表されたDirty COW(CVE-2016-5195)の餌食になりそうな雰囲気.この後無茶苦茶更新した.

解析対象

解析対象はカラフルな出力を行うプログラム.

/* color.c */
#include <stdio.h>

void red(void)
{
  printf("\x1b[31m");
  puts("red");
}
void blue(void)
{
  printf("\x1b[34m");
  puts("blue");
}
void green(void)
{
  printf("\x1b[32m");
  puts("green");
}
int main(void)
{
  int i=1;
  if (i) {
    red();
    blue();
    green();
  } else {
    return 1;
  }
  return 0;
}
/* E.O.F. */

変なif文が入っているのは,コードに分岐を作りたかったから.
コンパイルは,
$ gcc -o color color.c -Wall

解析

いよいよr2を起動する.r2の操作性を一言で表現するなら,vim + gdb.この辺りは素晴らしい.コマンド体系は独自すぎて少しわかりにくい.

$ r2 ./color
[0x00400450]>

といった感じのシェルが起動する.?でヘルプが見られる.
checksecのような情報が欲しいときは,

[0x00400450]> iI
pic      false
canary   false
nx       true
crypto   false
va       true
intrp    /lib64/ld-linux-x86-64.so.2
bintype  elf
class    ELF64
lang     c
arch     x86
bits     64
machine  AMD x86-64 architecture
os       linux
minopsz  1
maxopsz  16
pcalign  0
subsys   linux
endian   little
stripped false
static   false
linenum  true
lsyms    true
relocs   true
rpath    NONE
binsz    6605

今回はa(nalyze)コマンドで関数部のフラグを特定し,Visual Mode上で解析していく.最低限の解析のみならaa,プログラム中の文字列などを扱いたいなら,aaaコマンドを使う.ただし,stripされているプログラムだとaaaでは非常に時間がかかる.適宜使い分けるとよい.

[0x00400450]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[*] Use -AA or aaaa to perform additional experimental analysis.
[x] Construct a function name for all fcn.* (.afna @@ fcn.*)
fcns: 16
xref: 39
sect: 514
code: 590
covr: 114 %

[0x00400450]> afl # 解析した関数一覧を表示
0x00400000  60  2  sym.imp.__libc_start_main
0x00400400  23  3  sym._init
0x00400430  16  2  sym.imp.puts
0x00400440  16  2  sym.imp.printf
0x00400450  43  1  entry0
0x00400480  50  4  sym.deregister_tm_clones
0x004004c0  58  4  sym.register_tm_clones
0x00400500  28  3  sym.__do_global_dtors_aux
0x00400520  38  4  sym.frame_dummy
0x00400546  32  1  sym.red
0x00400566  32  1  sym.blue
0x00400586  32  1  sym.green
0x004005a6  50  4  sym.main
0x004005e0  101  4  sym.__libc_csu_init
0x00400650  2  1  sym.__libc_csu_fini
0x00400654  9  1  sym._fini

main関数から解析していく.

[0x00400450]> s sym.main # アドレス移動
[0x004005a6]> VV         # Visual Mode起動
[0x004005a6]> VV @ sym.main (nodes 4 edges 4 zoom 100%) BB-NORM mouse:canvas-y movements-speed:5                                 

                                              =-----------------------------------=
                                              | [0x4005a6]                        |
                                              |   ;-- main:                       |
                                              | (fcn) sym.main 50                 |
                                              | ; var int local_0h     @ rbp-0x0  |
                                              | ; var int local_4h     @ rbp-0x4  |
                                              | push rbp                          |
                                              | mov rbp, rsp                      |
                                              | sub rsp, 0x10                     |
                                              | mov dword [rbp - local_4h], 1     |
                                              | cmp dword [rbp - local_4h], 0     |
                                              | je 0x4005d1 ;[a]                  |
                                              =-----------------------------------=
                                                    t f
                                                .---' '-------------------.
                                                |                         |
                                                |                         |
                                          =----------------=      =----------------------=
                                          |  0x4005d1      |      |  0x4005bb            |
                                          | mov eax, 1     |      | call sym.red ;[b]    |
                                          =----------------=      | call sym.blue ;[c]   |
                                              v                   | call sym.green ;[d]  |
                                              |                   | mov eax, 0           |
                                              |                   | jmp 0x4005d6 ;[e]    |
                                              '------------.      =----------------------=
                                                           |          v
                                                           .----------'
                                                           |
                                                           |
                                                       =----------------=
                                                       |  0x4005d6      |
                                                       | leave          |
                                                       | ret            |
                                                       =----------------=

                            

上記のような表示になったと思う.分岐を起点としたブロックに分割されて,表示される.実際にはt(true),f(false)の線は色がついていて,非常に有り難い.vimと同様hjklで移動する.スペースキーを押すと,16進ダンプに跳ぶ.もう一回スペースキーを押すと戻る.
:を押すことでr2のコマンドを実行できる.sym.red関数をテキストとしてディスアセンブルする.

Press <enter> to return to Visual mode.
:> pdf@sym.main # pdf: 関数のディスアセンブル,'@'以降は引数に関数名やアドレスを与える
/ (fcn) sym.red 32
|           ; CALL XREF from 0x004005bb (sym.red)
|           0x00400546      55             push rbp
|           0x00400547      4889e5         mov rbp, rsp
|           0x0040054a      bf64064000     mov edi, str._e_31m         ; str._e_31m
|           0x0040054f      b800000000     mov eax, 0
|           0x00400554      e8e7feffff     call sym.imp.printf
|           0x00400559      bf6a064000     mov edi, 0x40066a
|           0x0040055e      e8cdfeffff     call sym.imp.puts
|           0x00400563      90             nop
|           0x00400564      5d             pop rbp
\           0x00400565      c3             ret

Visual Modeのままsym.redに移動したいときは

Press <enter> to return to Visual mode.
:> s sym.red<Enter><Enter>
[0x004005a6]> VV @ sym.red (nodes 1 edges 0 zoom 100%) BB-NORM mouse:canvas-y movements-speed:5                                  
                                                  =---------------------------=
                                                  | [0x400546]                |
                                                  | (fcn) sym.red 32          |
                                                  | push rbp                  |
                                                  | mov rbp, rsp              |
                                                  | mov edi, str._e_31m       |
                                                  | mov eax, 0                |
                                                  | call sym.imp.printf ;[a]  |
                                                  | mov edi, 0x40066a         |
                                                  | call sym.imp.puts ;[b]    |
                                                  | nop                       |
                                                  | pop rbp                   |
                                                  | ret                       |
                                                  =---------------------------=

uでmain関数に戻る.

終了

qを2回押して,元のプロンプトに戻り,Ctrl+dexitで終了.

最後に

radare2のVisual Modeでの解析を中心とした使い方をざっくり説明した.機能としてはもっと膨大であるが,そのへんの解説はbookやヘルプに譲りたい.objdumpよりも直感的なコードを提供してくれるため,静的解析には非常に心強い.
今年の9月に世界初のradare2カンファレンスr2con-2016が開催されたらしい.来年は是非行って,radare2は「ラダレツゥー」と読んでいいのか確かめたい.しかし,金と言語の壁が厚い.

参考

radare2レポジトリ: GitHub - radare/radare2: unix-like reverse engineering framework and commandline tools

端末出力の色変更方法: C言語でターミナルで表示される文字をカラー表示させる : Serendip - Webデザイン・プログラミング

radare2 book: http://www.radare.org/get/radare.pdf

Dirty COW: Dirty COW (CVE-2016-5195)