radare2 覚書
最近何かとCTFでお世話になっているradare2だが,どうもコマンドの物忘れがひどいので自分用の覚書としてここに残しておく.随時更新する.
redare2って何
OSSとして開発が進んでいるReverse Engineering Framework.時々動作に難はあるものの,対応しているアーキテクチャやファイルフォーマットの多さから重宝している*1.元々はフォレンジックツールとして開発が始まったそうだが,今ではバイナリ解析用に逆アセンブルやデバッグ機能も追加され,有用な機能を持ったツール群として radare2
に統合された.操作性はvim
,gdb
に近く馴染みやすい.素晴らしいね!CTFで利用する人も増えてきており,最近は標的型Malwareの解析やBlackHatの成果発表でも見かけるなど実用性も上がってきている模様.詳細は以下.
やりたいこと
基本的には図のように表層解析や静的解析で使えれば嬉しい.
具体的には,
表層解析
- ファイルサイズやファイルタイプの確認
- プログラムの保護機能の有無を確認(RELRO/SSP/Nxbit/ASLR/PIE)
- string情報の表示
静的解析
起動と初期動作
引数に解析したいプログラムのファイル名を指定して,radare2を起動する.
$ r2 <target_file> $ r2 -d <target_file> # デバッグ時にはオプションにdをつける
解析を終了する場合はq
コマンドでradare2を終了できる.例に使ったのはksnctfの村人A.
デバッグ時のradare shell起動はこんな感じ.尚,MacOSの場合はデバッグを有効化するためにコード署名が必要.
表層解析
対象プログラムの基本的な情報を表示
i: Information command
checksec
のような情報や,import,export,string情報はi: Information command*2を使う.radare2ではメインとなるコマンドに続いて,「何がしたいのか」をサブコマンド・オプションで指定することで1つの実行としている.例えば,バイナリの情報を調べたい場合はiI
コマンド(Binary info)で表示できる.
[0x08048500]> iI arch x86 baddr 0x8048000 binsz 5857 bintype elf bits 32 canary false sanitiz false class ELF32 crypto false endian little - 省略 -
radare2は1文字 <-> 1命令の一対一対応で,各々の文字に(基本的には)意味がある.
また,i
コマンドに限らず,各コマンドの末尾に?
を付けることでコマンドのヘルプを参照できる.
先程述べた,import情報はii
,export情報はiE
など,string情報はiz
などで確認できる.
[0x08048500]> ii [Imports] Num Vaddr Bind Type Name 1 0x08048464 WEAK NOTYPE __gmon_start__ 2 0x00000000 WEAK NOTYPE _Jv_RegisterClasses 3 0x08048474 GLOBAL FUNC putchar 4 0x08048484 GLOBAL FUNC fgets 5 0x08048494 GLOBAL FUNC __libc_start_main 6 0x080484a4 GLOBAL FUNC fopen 7 0x080484b4 GLOBAL FUNC printf 8 0x080484c4 GLOBAL FUNC puts 9 0x080484e4 GLOBAL FUNC strcmp 12 0x080484d4 GLOBAL FUNC __gxx_personality_v0 2 0x00000000 WEAK NOTYPE _Jv_RegisterClasses
[0x08048500]> iE [Exports] Num Paddr Vaddr Bind Type Size Name 046 0x000006e0 0x080486e0 GLOBAL FUNC 5 __libc_csu_fini 047 0x00000500 0x08048500 GLOBAL FUNC 0 _start 050 0x00000798 0x08048798 GLOBAL OBJ 4 _fp_hw 051 0x0000077c 0x0804877c GLOBAL FUNC 0 _fini 055 0x0000079c 0x0804879c GLOBAL OBJ 4 _IO_stdin_used 056 0x00000a00 0x08049a00 GLOBAL NOTYPE 0 __data_start 058 0x000007a0 0x080487a0 GLOBAL OBJ 0 __dso_handle 059 0x000008e4 0x080498e4 GLOBAL OBJ 0 __DTOR_END__ 060 0x000006f0 0x080486f0 GLOBAL FUNC 90 __libc_csu_init 062 ---------- 0x08049a04 GLOBAL NOTYPE 0 __bss_start 063 ---------- 0x08049a04 GLOBAL OBJ 4 stdin@@GLIBC_2.0 064 ---------- 0x08049a10 GLOBAL NOTYPE 0 _end 066 ---------- 0x08049a04 GLOBAL NOTYPE 0 _edata 069 0x0000074a 0x0804874a GLOBAL FUNC 0 __i686.get_pc_thunk.bx 070 0x000005b4 0x080485b4 GLOBAL FUNC 298 main 071 0x00000424 0x08048424 GLOBAL FUNC 0 _init
[0x08048500]> iz [Strings] Num Paddr Vaddr Len Size Section Type String 000 0x000007a4 0x080487a4 17 18 (.rodata) ascii What's your name? 001 0x000007b6 0x080487b6 4 5 (.rodata) ascii Hi, 002 0x000007bb 0x080487bb 21 22 (.rodata) ascii Do you want the flag? 003 0x000007d5 0x080487d5 16 17 (.rodata) ascii I see. Good bye. 004 0x000007e8 0x080487e8 8 9 (.rodata) ascii flag.txt
静的解析
コード解析のための初歩
a: Analyze command
radare2ではIDAと違い,関数解析や相互参照など高度な解析を自動で行ってくれないで,a: Analyze commandを実行する必要がある.
少しづつ改善されているが,難読化されたプログラムなどに対して高度な解析を自動化してしまうと,処理に相当な時間がかかるためこのような仕様になっている(?).
どうしても自動解析したい場合はradare2起動時に引数として-A
あるいは-AA
を追加すればよい.
[0x08048500]> aaaa [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Constructing a function name for fcn.* and sym.func.* functions (aan) [x] Type matching analysis for all functions (afta) [x] Emulate code to find computed references (aae) [x] Analyze consecutive function (aat) [0x08048500]> aaaaaaa An r2 developer is coming to your place to manually analyze this program. Please wait for it --press any key--
解析の程度はa
,aa(analyze all)
,aaa
,aaaa
とオプションを増やすことで対象を広げている.しかし,iI
コマンドの結果にstripped true
などがある場合は,時間がかかるため最低限のaa
コマンドが良い.この辺は表層解析の結果をみて臨機応変に使い分けすればOK.上の例ではaa
,aac
,aar
,aan
,afta
,aae
,aat
まで実行している.それぞれの内容はヘルプを参照しておくれ.ちなみにaaaaaaa
以上はジョークコマンドである.
この他にradare shell上でよく使うa
コマンドには以下の通り.
コマンド | 具体例 | 具体例の機能 |
---|---|---|
ax: analyze ref/Xref | axt | コードやデータの参照先を表示 |
af: analyze Functions | afl | 自動解析(af,aa,aaaなど)で取得した関数のリストを表示 |
カレントアドレスの移動と逆アセンブル
s: Seek command
自動解析で得られた関数や,特定のアドレスへカレントアドレスを移動する場合にはs: Seek commandを使う.カレントアドレスはradare shellのプロンプトに表示されている.カレントアドレスを移動せずに特定のコマンドを実行したい場合は<cmd> @ <address>
とすれば良い.
[0x08048500]> afl 0x08048424 3 48 sym._init 0x08048464 1 6 loc.imp.__gmon_start 0x08048474 1 6 sym.imp.putchar 0x08048484 1 6 sym.imp.fgets 0x08048494 1 6 sym.imp.__libc_start_main 0x080484a4 1 6 sym.imp.fopen 0x080484b4 1 6 sym.imp.printf 0x080484c4 1 6 sym.imp.puts 0x080484d4 1 6 sym.imp.__gxx_personality_v0 0x080484e4 1 6 sym.imp.strcmp 0x08048500 1 33 entry0 0x08048530 6 86 sym.__do_global_dtors_aux 0x08048590 4 36 sym.frame_dummy 0x080485b4 8 298 sym.main 0x080486e0 1 5 sym.__libc_csu_fini 0x080486f0 4 90 sym.__libc_csu_init 0x0804874a 1 4 sym.__i686.get_pc_thunk.bx 0x08048750 4 43 sym.__do_global_ctors_aux 0x0804877c 1 28 sym._fini [0x08048500]> s sym.main [0x080485b4]>
上に例は,自動解析でわかったmain関数(0x080485b4 8 298 sym.main
)へカレントアドレス([0x08048500]>
)の移動(s sym.main
)を行っている([0x080485b4]>
).
pd: print disassemble command
逆アセンブルについてはpd
コマンドを用いる.デフォルトは数十命令ぶんを逆アセンブルしてくれる.引数で命令数の指定もできる.pdf
コマンドは関数全体を逆アセンブルしてshellに表示してくれる.先程main関数へ移動したので実行してみるとこんな感じ*3.一部のスクショ.
また,disassembleより高級なdecompileを使用したい場合は,radare2のパッケージマネージャであるr2pmを使ってr2decをインストールできる.このデコンパイラは多数のアーキテクチャに対応しており,IDA買えず人権低めの自分は重宝している*4.標準でもpdc
コマンドでclangっぽくデコンパイル可能だが,このプラグインを導入したほうが可読性も高めゆえおすすめ.自分はradare2rcにe cmd.pdc = pdd
で存在を無かったことにしている.r2decを導入するとpdd
コマンドでデコンパイル結果がshell上に表示される.
グラフ機能などを備えたヴィジュアルモード
V: Visual mode command
IDAのようなグラフで見たい場合やTUIとして扱いたい場合はV: Visual mode commandを使う.操作の雰囲気はvimに近く,hjkl
で画面を移動したり,q
キーでradare shellに戻ったり,:
キーで一時的にradare shellが使えるなどなど.
V
コマンド
この表示方法で起動すると,Hexdump, disassemble, debugger, word-hexidecimal, etc...と様々な表示ができる.それぞれコマンドにより描画できる表示だがヴィジュアルモードを使うと切替が便利.p
またはP
キーで表示切替,数字
キーで対応するcall/jumpへ移動,o
で指定のオフセットへ移動,x
キーでaxt
コマンドのようにxref表示,v
キーで関数/変数の解析用UI表示,u
キーで操作した数字
またはo
キーからUndoする.VV
コマンド
こちらはIDAのようなグラフビュー関連の表示ができる.またV
コマンドからはSpace
キーによってこちらへ切替も可能.制御文による遷移の確認に役立つ.基本的な操作は上のモードと同じ.shift+d
キーでアセンブリも同時に表示が可能.V!
コマンド
radareでTUIのような操作ができる.それぞれのパネルへの移動はtab
キーやw
-->hjkl
,メニューの利用はm
キーを使う.パネルの分割やその他の操作方法は同様に?
で確認できる.
デバッグ
d: debug command
デバッグモードで起動した際には,デバッグが可能となる(それはそう).ブレークポイント置いて,continueして,ステップ実行...とかプログラムの挙動調査で使うやつ.その際はd: debug commandを使う.また具体例として,プログラムがパッキングされている場合*5などは,OEP(Original Entry Point)を探し出しメモリ上に展開されたソースを解析したりすることになる*6*7.そんなときにデバッグは有効.使えそうなコマンドを表にまとめておく.
- 実行フロー関連
コマンド | 機能 |
---|---|
dc | Breakpointの設置箇所までプログラムの実行(gdbのcontinue) |
dcu <address> | 指定したアドレスまで実行.e.g. dcu sym.main |
ds | ステップ実行(gdbのsi) |
dcr | 関数がstack frame returnになる,つまり抜けるまで実行 |
dr <register> | レジストリ内部の格納情報を表示 |
- Breakpoint関連
コマンド | 機能 |
---|---|
db <address> | 指定したアドレスにBreakpointを設置 |
dbc <address> <r2_cmd> | BP設置かつ実行されたときに使うr2コマンドの登録 |
drx <num> <addr> <len> <rwx> | 読み/書き/実行で指定アドレス範囲にアクセスしたときHBP*8設置 |
db- <address> | BPの削除 |
drx- <address> | HBPの削除 |
- メモリマップ関連
コマンド | 機能 |
---|---|
dm | プロセスのメモリマップを表示(gdbのvmmap) |
dmi <address | libname> |
読み込みのあったDLL symbolのリストを表示 |
- メモリダンプ関連
コマンド | 機能 |
---|---|
wtf <filename> <size> @<starting_address> |
指定アドレスから指定サイズ分の情報をダンプ |
dmd <filename> @<address> |
メモリマップの情報をダンプ |
そんなunpackingとかしない場合は,Vpp
コマンドでVisual debugger modeを使ったほうがサッとできる.
F2
でtoggle breakpoint,F4
でrun to cursor,F7
でsingle step,F8
でstep over,F9
でcontinueが使える.大変便利.
おわりに
とりあえず自分がよく使うコマンドを中心にまとめた.記事を書く過程で知らなかった機能や使い方の勉強にもなった.CTFやcrackme,降ってきた検体で精進する. radare2は自前のカンファレンスも開催しており各年のリポジトリに豊富な資料が残っている.radare2 bookの冊子体やswagを配布しているそうなので一度は行ってみたい...