自動でバグを見つける!
プログラム解析と動的バイナリ計装
カジュアルTechスシ
2020年5月28日
サイボウズ・ラボ株式会社 内田公太
1
/13
自己紹介
• 研究員 at サイボウズ・ラボ
• サイボウズ本社に2014年新卒入社
• Hazama→SRE
• 2020年1月にラボへ転籍
• カフェ部(酒)担当
• 紅茶も好きです
2
/13
研究分野
• 計算機科学の教育
• 「OSを作る」ことを通してCS教育
• 教育用OS「MikanOS」の作成
• プログラム解析
• プログラムの動作を調べる
• バグを見つける
• 今日の主題
3
/13
バッファーオーバーフロー
• バッファーオーバーランとも
• 問題:次のプログラムに潜むバグを指摘せよ
(制限時間30秒)
int main() {
char* p = malloc(10);
for (int i = 0; i < 10; ++i) {
p[i] = '0' + i;
}
p[10] = '0';
printf("p = %sn", p);
}
4
/13
静的解析
• プログラムを動かさずに解析
• 代表的なツール:Lint
int main() {
char* p = malloc(10);
for (int i = 0; i < 10; ++i) {
p[i] = '0' + i;
}
p[10] = '0';
printf("p = %sn", p);
}
• pのヌルチェックをしていない
• pの末尾を超えて書き込んでいる
• pをfreeしていない
5
バッファーオーバーフロー
/13
malloc()の戻り値
10バイト
バッファーオーバーフロー
6
'0' '1' '2' '3' '4' '5' '6' '7' '8' '9' NUL
/13
動的解析
• プログラムを動かして解析
• 代表的なツール:GDB
• 実際の値で正確な検査ができる
• バイナリさえあれば動かせる
• マルウェアの解析
• ソースコードの情報は使えない
• この条件付きjmpはifかwhileか?
00000000004004a0 <main>:
4004a0: sub rsp,0x8
4004a4: mov edi,0xa
4004a9: call 400470 <malloc@plt>
4004ae: mov esi,0x400684
4004b3: mov BYTE PTR [rax],0x30
4004b6: mov BYTE PTR [rax+0x1],0x31
4004ba: mov BYTE PTR [rax+0x2],0x32
4004be: mov BYTE PTR [rax+0x3],0x33
…
7
/13
バイナリ計装(今日の主題)
• Binary Instrumentation
• 実行ファイルに検査コードを埋め込む
• 代表的なツール:Intel Pin
• 一般に,実行ファイルに機械語を埋め
込むとアドレスがずれる
• →再アセンブルが必要
• Intel Pinはそれをやってくれる
00000000004004a0 <main>:
4004a0: sub rsp,0x8
4004a4: mov edi,0xa
4004a9: call 400470
…
8
/13
DBIでバッファーオーバーフローを発見
• 動的バイナリ計装:実行時にバイナリ計装する
• 検出方針:
• mallocの引数と戻り値を記録しておき
• メモリアクセス時にアクセス先アドレスを検査
int main() {
char* p = malloc(10);
for (int i = 0; i < 10; ++i) {
p[i] = '0' + i;
}
p[10] = '0';
printf("p = %sn", p);
}
引数と戻り値を記録
メモリアクセスを検査
9
/13
自作解析ツールの出力
$ ../../../pin -t obj-intel64/MyPinTool.so -- ./a.out
===============================================
This application is instrumented by MyPinTool
===============================================
Found out-of-bounds memory write at f2f01a (IP=4004e2)
p = 0123456789
===============================================
MyPinTool analysis results:
Heap Objects:
f2f010: size=0xa
f2f030: size=0x400
===============================================
10
/13
自作解析ツールの出力
$ ../../../pin -t obj-intel64/MyPinTool.so -- ./a.out
===============================================
This application is instrumented by MyPinTool
===============================================
Found out-of-bounds memory write at f2f01a (IP=4004e2)
p = 0123456789
===============================================
MyPinTool analysis results:
Heap Objects:
f2f010: size=0xa
f2f030: size=0x400
===============================================
解析対象アプリの出力
11
/13
mallocを置き換える
0000000000400470 <malloc@plt>:
400470: jmp QWORD PTR [rip+0x200baa]
400476: push 0x1
40047b: jmp 400450 <_init+0x28>
…
もとのプログラム
検査用malloc
malloc()をラップ
サイズとアドレスを記録
RTN_ReplaceSignature()
Intel Pinの機能で関数置換
heap_objs
12
/13
メモリアクセスを検査
00000000004004a0 <main>:
4004a0: sub rsp,0x8
4004a4: mov edi,0xa
4004a9: call 400470 <malloc@plt>
…
4004da: mov BYTE PTR [rax+0x8],0x38
4004de: mov BYTE PTR [rax+0x9],0x39
4004e2: mov BYTE PTR [rax+0xa],0x0
4004e6: xor eax,eax
4004e8: call 400480 <__printf_chk@plt>
もとのプログラム
INS_MemoryOperandCount()
INS_InsertCall()
CheckOverflow()
指定した命令のメモリ参照の個数
指定した命令の直前に関数呼び出しを挿入
heap_objs
メモリアドレスが
範囲内であることを検査
13

自動でバグを見つける!プログラム解析と動的バイナリ計装