Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
HappyNewYear勉強会
@potetisensei
自己紹介
● 小池悠生
● 灘校パソコン研究部部長
● CTF
– 普段はEpsilonDeltaとして
– 一応binjaリーダー
– Exploitationが専門です
– 引退視野
前回の反省
初心者向けではなかった!
前回の反省
● 完全に想定ミス
– 皆さんそもそもアセンブラを読んだことがない?
– 問題解説という段階ではなかった
– 飛ばしていくつもりだったけど流石に暴走だった
● 今日はバイナリを歩きましょう
アセンブラ
● 今日はx86アーキテクチャを使う
– 多分みなさんx86(_64)のパソコンだから
● C言語
– アセンブラを学ぶ上で重要
– 教養として知っておいたほうが恥ずかしくない
アセンブラ
● 読む“disassembler”と書く“assembler”
– 今日教えるのはアセンブラの書き方ではない
– コンパイラが吐き出したアセンブラを読む
● コンパイラのアセンブラにはパターンがある
● プログラムが自動で吐き出し...
アセンブラ
● 覚えなければならないこと
– 命令
● そんな全命令覚える必要はない
● 慣れればググれます
– メモリ
– レジスタ
● 分かって
– ディスアセンブラ/デバッガの使い方
● 使って覚えるしか無いでしょう
● 今日伝えたいこと
– ある程度の知識
– 自分で勉強するための方法
– 読む上で何が重要か(※個人の見解)
機械語とアセンブラ
● 機械語
– CPUが実際に解釈、実行する命令列
– 16進数の数(0x00~0xff)の並びで表される
– 人が昔これを“そのまま”書いていたというのは有名
– 人間のすることじゃない
● ではどうすれば人間向きなのか?
機械語とアセンブラ
● 命令列が数値なのがいけないのではないか?
– なら命令に名前を振って見やすくしては?
– 一緒に命令の引数も見やすくしよう
– という発想がアセンブラ
– つまりアセンブラは機械語の表示方法とみなせる
– (これは方便な...
アセンブラの登場人物
● メモリ(memory)
– データを記憶する場所
– 実行する機械語列やデータ等全ての情報がここにある
– 後でデバッガでどのようになってるか確認しましょう
アセンブラの登場人物
● レジスタ(register)
– 簡単に言ってしまえばアセンブラにおける変数
– 要はこれも数値を記憶するもの
– メモリと何が違う?
● 値の操作などはほとんどこれを経由して行われる
● アクセスがメモリよりも速い ...
アセンブラの登場人物
● レジスタ(register)
– eax, ebx, ecx, edx, esp, ebp, edi, esi, eip, ...などがある
– それぞれ用途が違う
– 4byteの数値を記憶できる(0x0000000...
アセンブラの登場人物
● 命令(instruction)
– CPUに解釈、実行される操作(そのまま)
– opcode (operand1), (operand2)
– 例: “ret”, “push eax”など
– 今からこれを読んでいき...
何もしないプログラム
● 初めにdo-nothingというプログラムを読みましょう
– 元となったソースコードはdo-nothing.c
– 自分でコンパイルしてもいいです
● 最適化オプションは使用しないでください
● 64bitの環境ならg...
何もしないプログラム
何もしないプログラム
ELF32というファイルフォーマットで
i386というアーキテクチャ向けの実行ファイルである
何もしないプログラム
サブルーチン名(関数のようなもの)
何もしないプログラム
機械語列が配置されるメモリアドレス
何もしないプログラム
配置されてる機械語
何もしないプログラム
機械語に対応するアセンブラ表記
何もしないプログラム
● main関数のサブルーチンを見てみましょう
– /<main>:と入力して探しましょう
– 何もしない関数なのにいくつか命令が!
何もしないプログラム
● 分かったこと
– なんとなくのobjdumpの見方
– mainしか記述してないのに色々サブルーチンがある
● Cにおいてはmainからプログラムはスタートしますが
– アセンブラでは何からスタートする?
何もしないプログラム
● エントリーポイント?
– 命令の実行が開始されるアドレス
– readelf -h do-nothingで調べてみましょう
何もしないプログラム
何もしないプログラム
● エントリーポイント?
– 命令の実行が開始されるアドレス
– readelf -h do-nothingで調べてみましょう
– 0x80482f0らしい
– objdumpを使って80482f0がどこか調べてみましょう...
何もしないプログラム
何もしないプログラム
● エントリーポイント?
– 命令の実行が開始されるアドレス
– readelf -h do-nothingで調べてみましょう
– 0x80482f0らしい
– objdumpを使って80482f0がどこか調べてみましょう...
何もしないプログラム
● まとめ
– 実行はエントリーポイントと呼ばれる所から始まる
– 関数はそのままサブルーチンになる
– mainの前に色々サブルーチンが実行される
● これらはmainを実行するための準備です
● 従って見る必要がないの...
メモリに代入するプログラム
● 次にassignmentというプログラムを読みましょう
– 元となったソースコードはassignment.c
– 出来れば自分でコンパイルしないでください
● コンパイラによって吐かれる命令が変わり厄介です
– ...
メモリに代入するプログラム
メモリに代入するプログラム
● 今度は全ての命令をしっかり読んでいきます
– Cのソースコードと照らし合わせるとわかりやすいはず
メモリに代入するプログラム
push %ebp
mov %esp,%ebp
sub $0x10,%esp
後で説明しますが、関数の先頭には必ずついています。
 ebpとespにはメモリアドレスが入っている、
            ということだ...
メモリに代入するプログラム
movl $0x1,-0x4(%ebp)
movは代入命令です。
メモリやレジスタに、
定数やメモリ、レジスタの値をコピーします。
先ほど述べたようにebpにはメモリアドレスが入っていて、
ここではebp-4が指すメ...
メモリに代入するプログラム
addl $0x2,-0x4(%ebp)
addは加算命令です。
メモリやレジスタに、
定数やメモリ、レジスタの値を加算します。
ここではebp-4が指すメモリに2を加算していることから、
Cのコードのvar += ...
メモリに代入するプログラム
mov -0x4(%ebp),%eax
ebp-4が指すメモリの中身をeaxにコピーします。
(%reg)という表記は常に「メモリの中身」を意味します。
メモリに代入するプログラム
imul $0x64,%eax,%eax
mulは乗算命令です。
今回の様にoperandが3つある場合には
operand3 = operand1(定数) * operand2
というように、3つめのoperand...
メモリに代入するプログラム
mov -0x4(%ebp),%ecx
mov $0x66666667,%edx
mov %ecx,%eax
imul %edx
ebp-4が指すメモリの中身をecxに代入、
0x66666667をedxに代入、
e...
メモリに代入するプログラム
mov -0x4(%ebp),%ecx
mov $0x66666667,%edx
mov %ecx,%eax
imul %edx
edx = var * 0x66666667 / 0x100000000;
eax =...
メモリに代入するプログラム
mov -0x4(%ebp),%ecx
mov $0x66666667,%edx
mov %ecx,%eax
imul %edx
edx = var * 2/5; (∵ 0x66666667 ÷ 0x10000000...
メモリに代入するプログラム
mov -0x4(%ebp),%ecx
mov $0x66666667,%edx
mov %ecx,%eax
imul %edx
edx = var * 2/5; (∵ 0x66666667 ÷ 0x10000000...
メモリに代入するプログラム
mov -0x4(%ebp),%ecx
mov $0x66666667,%edx
mov %ecx,%eax
imul %edx
よって、これらはvarの2/5と3/5を求める命令列です。
メモリに代入するプログラム
sar %edx
sar, shrは右シフト命令。
operandが1つの場合には、
operand1 >>= 1; (⇔ operand1 /= 2;
operandが2つの場合には、
operand2 >>= o...
メモリに代入するプログラム
mov %ecx,%eax
sar $0x1f,%eax
sub %eax,%edx
subは減算命令です。
ecxにはvarの値が入っていたから、
edx -= var >> 31をしていることになります。
var...
メモリに代入するプログラム
mov %edx,%eax
mov %eax,-0x4(%ebp)
edxの値、var * 1/5をvarに代入します。
よって、これらの命令群でvar /= 5が行われています。
今回は乗算によって除算が行われまし...
メモリに代入するプログラム
● デバッガで確認しましょう
– 命令を解説するより、実際に動かした方が早い
– 動かしつつレジスタやメモリの状態を見れる
– Linuxにはgdbと呼ばれるGNUのデバッガがあります
user@user:$ gdb...
メモリに代入するプログラム
メモリに代入するプログラム
● デバッガの基本
– ブレークポイントを仕掛けてプログラムを中断
– ステップ実行で逐次実行
– コマンドでレジスタやメモリの値を確認、変更
メモリに代入するプログラム
● break mainでmain関数の先頭にブレークポイント
● runで実行
– 当然main関数の先頭で止まる
● コマンドは省略可
– b main, rなど
メモリに代入するプログラム
● disasなんかも出来る
メモリに代入するプログラム
● imul %edxの後のレジスタを確認したいなら
– b *0x08048413でアドレスをブレーク
– continue(c)でブレークするまで実行
– ブレークしたらinfo registers
メモリに代入するプログラム
● eaxとedxだけ確認したいみたいな時
– pコマンドで値を表示
● 本来はp 1+1とか電卓的な役割
– $regでレジスタを参照
– p $eaxで10進法表記でeaxを表示
– p/x $edxで16進法表...
メモリに代入するプログラム
● sar %edx後のedxの値を確認
– ちょうどそこでブレークしているからステップ実行
– stepi(si)で1行だけ実行できる
メモリに代入するプログラム
● 最終的なvarの値を確認したい
– b *0x08048421で最後の代入の後でブレーク
– cでブレークするまで実行
– xコマンドでメモリの中身が確認できます
メモリに代入するプログラム
● xコマンドのフォーマット
– x/(format)で指定した書式で値を表示
– x/dwでword(4byte)サイズで10進数表記
– x/xgでgiga word(8byte)サイズで16進数表記
– サイズ...
メモリに代入するプログラム
● まとめ
– mov命令で代入できる
– offset(%reg)は%reg+offsetが指すメモリの中身
– 四則演算はadd, sub, mul, divでできる
● 主にこれらにはeaxとedxが利用されま...
関数を呼び出すプログラム
● 次にcall-funcというプログラムを読みましょう
– objdump -d call-func してください
– mainのサブルーチンを見てみましょう
関数を呼び出すプログラム
● call <foo>がfoo関数を呼んでいそう?
– 関数の呼び出しを見る時はスタックを意識します
今日のテーマ(最重要)
スタックと関数
スタック
● データ構造の一種
– Push: 新しいデータを積むこと
– Pop: 一番上のデータを取り出す
スタック
● コンパイラはCのコードをアセンブラで表現する
– コンパイラを作る人の気持ちになってください
– アセンブリ命令作る人の気持ちにもなるとなお良し
● Cの関数を表現する上で必要なことはなにか?
– ローカル変数用の領域は呼び出しご...
スタック
● それってスタックが使えるのでは?
– 関数を呼び出す時に引数と呼び出した位置をpush
– 関数からreturnする際にpopしてその位置に戻る
– 呼び出しの入れ子や再帰にも対応できる
コードの10行目から3行目の関数を呼ぶ時、...
スタック
● でもどうやってプログラム上でスタックを表現する?
– メモリならいくらでもある
– 上底と下底の位置で擬似的に表現できるんじゃ?
スタック
11行目
11行目
15行目
3行目
20行目
10行目
上底
下底
メモリ
スタック
● でもどうやってプログラム上でスタックを表現する?
– メモリならいくらでもある
– 上底と下底の位置で擬似的に表現できるんじゃ?
– それらの位置はレジスタに記憶させればいい
● → espとebp
– esp ・・・ exten...
スタック
● つまり
– 関数を呼び出す時には戻る位置をpushする
● espが指すアドレスに位置を入れてespの値をdec
– 関数からreturnする時はpopして位置を変える
● espが指すアドレスから値を取ってespの値をinc
スタック
● ついでにローカル変数用のメモリ領域を取りたい
– 呼び出しごとに必要ならスタック上に取るのが自然
– 関数を呼び出した時にスタックの中に取っては?
● 少し余分にespをdecすればいいこと
– これで全ての問題をクリア出来た!
イメージ図
関数fooへの引数
戻りアドレス
fooのローカル変数
関数putsへの引数
戻りアドレス
関数を呼び出すプログラム
● これを踏まえてfoo関数の呼び出し部分を見てみます
movl $0x80484e0,(%esp)
call 804841d <foo>
関数を呼び出すプログラム
● これを踏まえてfoo関数の呼び出し部分を見てみます
movl $0x80484e0,(%esp)
call 804841d <foo>
引数(char*=アドレス)をスタックにpush
関数を呼び出すプログラム
● これを踏まえてfoo関数の呼び出し部分を見てみます
movl $0x80484e0,(%esp)
call 804841d <foo>
戻るためのアドレスをスタックにpushして関数fooにjmpする
関数を呼び出すプログラム
8048439: movl $0x80484e0,(%esp)
8048440: call 804841d <foo>
esp
関数を呼び出すプログラム
8048439: movl $0x80484e0,(%esp)
8048440: call 804841d <foo>
0x80484e0 esp
関数を呼び出すプログラム
8048439: movl $0x80484e0,(%esp)
8048440: call 804841d <foo>
0x80484e0
0x8048445 esp
関数を呼び出すプログラム
● movl $0x80484e0,(%esp)はpushではないのでは?
– 確かにmovだけではpushにならない
● 「push A」 = 「sub $0x4, %esp; mov A, (%esp)」
– ポイ...
関数を呼び出すプログラム
● fooの引数参照
– 戻りアドレスと引数をpushしてfooが呼び出された
– 引数の参照を何で行う?
● イチイチpopするのは非効率
● メモリとして参照したほうが賢い
● アドレスをregisterで記憶する...
イメージ図
関数fooへの引数
fooのローカル変数
関数barへの引数
戻りアドレス
イメージ図
関数fooへの引数
fooのローカル変数
関数barへの引数
戻りアドレス
esp
イメージ図
関数fooへの引数
fooのローカル変数
関数barへの引数
戻りアドレス
esp
ebp
関数を呼び出すプログラム
● fooの引数参照
– これでebp+offsetで引数のアドレスが求められそう
– でも複数回関数が呼ばれるとマズイ
● ebpの値を呼び出すごとに変える必要あり
● return時には元の関数に合う様戻さないとい...
イメージ図
関数fooへの引数
戻りアドレス
fooのローカル変数
関数putsへの引数
戻りアドレス
元のebpの値
元のebpの値
関数を呼び出すプログラム
● 実際の呼び出し過程
– 引数をpush
– callにより戻りアドレスをpushし呼び出し先へjmp
– 元のebpの値をpush
– ebpをespの値に設定
– espから必要な分値を引く
関数を呼び出すプログラム
● 実際のreturn過程
– espをebpの値に設定
– ebpへ元のebpの値をpop
– 戻りアドレスへjmp(ret命令)
– 必要であれば引数をpop
関数を呼び出すプログラム
● デバッガで確認しましょう
– gdb ./call-func -q
– b fooでfoo関数を設定
– rで実行
– スタックの中身を表示してみてください
● x/xw $espでしたね
● x/8xw $esp...
関数を呼び出すプログラム
● ひと目でローカル変数の領域がどこか分かりますか?
– 冒頭のsub $0x18,%espから24byteだと分かる
– つまり下絵の初め6つがローカル変数用の領域
– 残り2つはそれぞれ前のebpとreturn a...
関数を呼び出すプログラム
● fooの引数はなんでしょう?
– ソースコードから、char*であることは分かる
– gdbで確認してみましょう
– 引数はebp+8なのでx/xw $ebp+8
– 表示された値はchar*だからこれもアドレス
...
メモリに代入するプログラム
● まとめ
– 関数の呼び出しは一種のスタック操作になっている
– ebpで引数やローカル変数を参照して効率化している
– スタックのイメージがexploitationでは重要になる
演習
● problemというファイルを読んでください。
– /dev/nullに書き込んでいる内容を答えとします
– 少し難しいかもしれません
● 今までの内容をよく思い出しましょう
演習
● Hint1
– main関数がない!
– 難読化(?)っぽいのがかかってる
– stripと言い、gccの標準機能です
● サブルーチン名は人間用の情報なので削除可能
– libc_start_mainの第1引数はmainのアドレスです
演習
● Hint2
– 呼ばれる標準関数はpltセクションにかいてあります
– objdumpで「セクション .plt の逆アセンブル:」を確認
– ファイルに書き込みを行う関数はどれ?
● Hint2
– 呼ばれる標準関数はpltセクション...
演習
● Hint3
– fwriteの引数はなんでしょうか?
– 第1引数がファイルへ書き込むデータです
– どうやら
lea 0x20(%esp),%eax
mov %eax,(%esp)
のeaxが第1引数らしい
– lea命令とは一体?
演習
● Hint4
– lea命令はメモリのアドレスの代入です
● lea 0x20(%esp),%eaxならeax = esp+0x20
– esp+0x20とは一体...
● 実は最適化でローカル変数をespで参照しています
● なのでe...
演習
● 答え
– “THIS_IS_FLAGGGGx00”
演習
● まとめ
– objdumpによる逆アセンブルを学んだ
– 簡単なデバッガの使い方を学んだ
自分で勉強するには
● とにかくバイナリを読みましょう
– 僕はCTFをしまくった
– 自分でコンパイルしたプログラムなどがオススメ
● 分からなくなったらソースコードを見ればいい
● forやwhileはどうなるの?ifはどうなる?switc...
意識すると良いこと
● C言語ではどのように対応するのか
– ほとんどのバイナリはC, C++からコンパイルされる
– つまりバイナリをCのコードで表すことが出来るはず
– 読みながらCのコードに直していくのもアリ
● スタックの状況
– これ...
御静聴ありがとうございました
Prochain SlideShare
Chargement dans…5
×

Happy New Year勉強会

2 858 vues

Publié le

Happy New Year勉強会
混乱しない様に少し誤魔化そうと思った所がいくつかあったけど結局口頭では正しいことを解説してしまった

Publié dans : Alimentation
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici

Happy New Year勉強会

  1. 1. HappyNewYear勉強会 @potetisensei
  2. 2. 自己紹介 ● 小池悠生 ● 灘校パソコン研究部部長 ● CTF – 普段はEpsilonDeltaとして – 一応binjaリーダー – Exploitationが専門です – 引退視野
  3. 3. 前回の反省 初心者向けではなかった!
  4. 4. 前回の反省 ● 完全に想定ミス – 皆さんそもそもアセンブラを読んだことがない? – 問題解説という段階ではなかった – 飛ばしていくつもりだったけど流石に暴走だった ● 今日はバイナリを歩きましょう
  5. 5. アセンブラ ● 今日はx86アーキテクチャを使う – 多分みなさんx86(_64)のパソコンだから ● C言語 – アセンブラを学ぶ上で重要 – 教養として知っておいたほうが恥ずかしくない
  6. 6. アセンブラ ● 読む“disassembler”と書く“assembler” – 今日教えるのはアセンブラの書き方ではない – コンパイラが吐き出したアセンブラを読む ● コンパイラのアセンブラにはパターンがある ● プログラムが自動で吐き出しているので当たり前 ● 中でも理解しやすいのがC言語のコンパイラ
  7. 7. アセンブラ ● 覚えなければならないこと – 命令 ● そんな全命令覚える必要はない ● 慣れればググれます – メモリ – レジスタ ● 分かって – ディスアセンブラ/デバッガの使い方 ● 使って覚えるしか無いでしょう
  8. 8. ● 今日伝えたいこと – ある程度の知識 – 自分で勉強するための方法 – 読む上で何が重要か(※個人の見解)
  9. 9. 機械語とアセンブラ ● 機械語 – CPUが実際に解釈、実行する命令列 – 16進数の数(0x00~0xff)の並びで表される – 人が昔これを“そのまま”書いていたというのは有名 – 人間のすることじゃない ● ではどうすれば人間向きなのか?
  10. 10. 機械語とアセンブラ ● 命令列が数値なのがいけないのではないか? – なら命令に名前を振って見やすくしては? – 一緒に命令の引数も見やすくしよう – という発想がアセンブラ – つまりアセンブラは機械語の表示方法とみなせる – (これは方便なので真に受けない)
  11. 11. アセンブラの登場人物 ● メモリ(memory) – データを記憶する場所 – 実行する機械語列やデータ等全ての情報がここにある – 後でデバッガでどのようになってるか確認しましょう
  12. 12. アセンブラの登場人物 ● レジスタ(register) – 簡単に言ってしまえばアセンブラにおける変数 – 要はこれも数値を記憶するもの – メモリと何が違う? ● 値の操作などはほとんどこれを経由して行われる ● アクセスがメモリよりも速い → 高速化
  13. 13. アセンブラの登場人物 ● レジスタ(register) – eax, ebx, ecx, edx, esp, ebp, edi, esi, eip, ...などがある – それぞれ用途が違う – 4byteの数値を記憶できる(0x00000000 ~ 0xffffffff) – 後で1つずつ確認しましょう
  14. 14. アセンブラの登場人物 ● 命令(instruction) – CPUに解釈、実行される操作(そのまま) – opcode (operand1), (operand2) – 例: “ret”, “push eax”など – 今からこれを読んでいきます
  15. 15. 何もしないプログラム ● 初めにdo-nothingというプログラムを読みましょう – 元となったソースコードはdo-nothing.c – 自分でコンパイルしてもいいです ● 最適化オプションは使用しないでください ● 64bitの環境ならgcc -m32オプションを付けること ● エラーが出る場合 – apt-get install libc6:i386とかでどうにかなる user@user:$ objdump -d do-nothing | less
  16. 16. 何もしないプログラム
  17. 17. 何もしないプログラム ELF32というファイルフォーマットで i386というアーキテクチャ向けの実行ファイルである
  18. 18. 何もしないプログラム サブルーチン名(関数のようなもの)
  19. 19. 何もしないプログラム 機械語列が配置されるメモリアドレス
  20. 20. 何もしないプログラム 配置されてる機械語
  21. 21. 何もしないプログラム 機械語に対応するアセンブラ表記
  22. 22. 何もしないプログラム ● main関数のサブルーチンを見てみましょう – /<main>:と入力して探しましょう – 何もしない関数なのにいくつか命令が!
  23. 23. 何もしないプログラム ● 分かったこと – なんとなくのobjdumpの見方 – mainしか記述してないのに色々サブルーチンがある ● Cにおいてはmainからプログラムはスタートしますが – アセンブラでは何からスタートする?
  24. 24. 何もしないプログラム ● エントリーポイント? – 命令の実行が開始されるアドレス – readelf -h do-nothingで調べてみましょう
  25. 25. 何もしないプログラム
  26. 26. 何もしないプログラム ● エントリーポイント? – 命令の実行が開始されるアドレス – readelf -h do-nothingで調べてみましょう – 0x80482f0らしい – objdumpを使って80482f0がどこか調べてみましょう ● /80482f0 で検索出来ます
  27. 27. 何もしないプログラム
  28. 28. 何もしないプログラム ● エントリーポイント? – 命令の実行が開始されるアドレス – readelf -h do-nothingで調べてみましょう – 0x80482f0らしい – objdumpを使って80482f0がどこか調べてみましょう ● /80482f0 で検索出来ます – _startというサブルーチンからバイナリは始まる
  29. 29. 何もしないプログラム ● まとめ – 実行はエントリーポイントと呼ばれる所から始まる – 関数はそのままサブルーチンになる – mainの前に色々サブルーチンが実行される ● これらはmainを実行するための準備です ● 従って見る必要がないのです
  30. 30. メモリに代入するプログラム ● 次にassignmentというプログラムを読みましょう – 元となったソースコードはassignment.c – 出来れば自分でコンパイルしないでください ● コンパイラによって吐かれる命令が変わり厄介です – objdump -d assignment | less – サブルーチンmainを見ましょう ● 準備用の他のルーチンは見なくても大丈夫です。
  31. 31. メモリに代入するプログラム
  32. 32. メモリに代入するプログラム ● 今度は全ての命令をしっかり読んでいきます – Cのソースコードと照らし合わせるとわかりやすいはず
  33. 33. メモリに代入するプログラム push %ebp mov %esp,%ebp sub $0x10,%esp 後で説明しますが、関数の先頭には必ずついています。  ebpとespにはメモリアドレスが入っている、             ということだけ覚えてください。
  34. 34. メモリに代入するプログラム movl $0x1,-0x4(%ebp) movは代入命令です。 メモリやレジスタに、 定数やメモリ、レジスタの値をコピーします。 先ほど述べたようにebpにはメモリアドレスが入っていて、 ここではebp-4が指すメモリに1を代入しています。 Cのコードのvar = 1に対応する命令であると分かります。 すなわち、ebp-4がvarのメモリアドレスということです。
  35. 35. メモリに代入するプログラム addl $0x2,-0x4(%ebp) addは加算命令です。 メモリやレジスタに、 定数やメモリ、レジスタの値を加算します。 ここではebp-4が指すメモリに2を加算していることから、 Cのコードのvar += 2に対応する命令です。
  36. 36. メモリに代入するプログラム mov -0x4(%ebp),%eax ebp-4が指すメモリの中身をeaxにコピーします。 (%reg)という表記は常に「メモリの中身」を意味します。
  37. 37. メモリに代入するプログラム imul $0x64,%eax,%eax mulは乗算命令です。 今回の様にoperandが3つある場合には operand3 = operand1(定数) * operand2 というように、3つめのoperandが代入先です。 operandが1つの場合には、 edx:eax *= operand1(上位4byteはedxへ) を意味します。 すなわち、 var *= 100に対応しています。
  38. 38. メモリに代入するプログラム mov -0x4(%ebp),%ecx mov $0x66666667,%edx mov %ecx,%eax imul %edx ebp-4が指すメモリの中身をecxに代入、 0x66666667をedxに代入、 ecxの値をeaxに代入、 eax * edxの結果をedx:eaxに代入
  39. 39. メモリに代入するプログラム mov -0x4(%ebp),%ecx mov $0x66666667,%edx mov %ecx,%eax imul %edx edx = var * 0x66666667 / 0x100000000; eax = var * 0x66666667 % 0x100000000;
  40. 40. メモリに代入するプログラム mov -0x4(%ebp),%ecx mov $0x66666667,%edx mov %ecx,%eax imul %edx edx = var * 2/5; (∵ 0x66666667 ÷ 0x100000000 ≒ 0.4) eax = var * 0x66666667 % 0x100000000;
  41. 41. メモリに代入するプログラム mov -0x4(%ebp),%ecx mov $0x66666667,%edx mov %ecx,%eax imul %edx edx = var * 2/5; (∵ 0x66666667 ÷ 0x100000000 ≒ 0.4) eax = var * 3/5; (∵ A%B = A – A/B*B)
  42. 42. メモリに代入するプログラム mov -0x4(%ebp),%ecx mov $0x66666667,%edx mov %ecx,%eax imul %edx よって、これらはvarの2/5と3/5を求める命令列です。
  43. 43. メモリに代入するプログラム sar %edx sar, shrは右シフト命令。 operandが1つの場合には、 operand1 >>= 1; (⇔ operand1 /= 2; operandが2つの場合には、 operand2 >>= operand1; を表します。 sal, shlは左シフト命令。 つまり、edx = var * 2/5だから、edx /= 2すると、 edxにはvar * 1/5が代入されるのことになります。
  44. 44. メモリに代入するプログラム mov %ecx,%eax sar $0x1f,%eax sub %eax,%edx subは減算命令です。 ecxにはvarの値が入っていたから、 edx -= var >> 31をしていることになります。 varは4byte=32bitの変数ですから、31回右シフトをすると 最上位の1bitの値を求めることになります。 これはvarがsigned intであるため、varが負数の場合には edxから1を引かなくてはなりません。(cf. 2の補数表現)
  45. 45. メモリに代入するプログラム mov %edx,%eax mov %eax,-0x4(%ebp) edxの値、var * 1/5をvarに代入します。 よって、これらの命令群でvar /= 5が行われています。 今回は乗算によって除算が行われましたが、 divという除算命令が別にあります。
  46. 46. メモリに代入するプログラム ● デバッガで確認しましょう – 命令を解説するより、実際に動かした方が早い – 動かしつつレジスタやメモリの状態を見れる – Linuxにはgdbと呼ばれるGNUのデバッガがあります user@user:$ gdb ./assignment -q
  47. 47. メモリに代入するプログラム
  48. 48. メモリに代入するプログラム ● デバッガの基本 – ブレークポイントを仕掛けてプログラムを中断 – ステップ実行で逐次実行 – コマンドでレジスタやメモリの値を確認、変更
  49. 49. メモリに代入するプログラム ● break mainでmain関数の先頭にブレークポイント ● runで実行 – 当然main関数の先頭で止まる ● コマンドは省略可 – b main, rなど
  50. 50. メモリに代入するプログラム ● disasなんかも出来る
  51. 51. メモリに代入するプログラム ● imul %edxの後のレジスタを確認したいなら – b *0x08048413でアドレスをブレーク – continue(c)でブレークするまで実行 – ブレークしたらinfo registers
  52. 52. メモリに代入するプログラム ● eaxとedxだけ確認したいみたいな時 – pコマンドで値を表示 ● 本来はp 1+1とか電卓的な役割 – $regでレジスタを参照 – p $eaxで10進法表記でeaxを表示 – p/x $edxで16進法表記でedxを表示
  53. 53. メモリに代入するプログラム ● sar %edx後のedxの値を確認 – ちょうどそこでブレークしているからステップ実行 – stepi(si)で1行だけ実行できる
  54. 54. メモリに代入するプログラム ● 最終的なvarの値を確認したい – b *0x08048421で最後の代入の後でブレーク – cでブレークするまで実行 – xコマンドでメモリの中身が確認できます
  55. 55. メモリに代入するプログラム ● xコマンドのフォーマット – x/(format)で指定した書式で値を表示 – x/dwでword(4byte)サイズで10進数表記 – x/xgでgiga word(8byte)サイズで16進数表記 – サイズはb, h, w, g、表記はd, u, o, x, c, sなど
  56. 56. メモリに代入するプログラム ● まとめ – mov命令で代入できる – offset(%reg)は%reg+offsetが指すメモリの中身 – 四則演算はadd, sub, mul, divでできる ● 主にこれらにはeaxとedxが利用されます。 ● eax ・・・ extended accumulator register ● edx ・・・ extended data register
  57. 57. 関数を呼び出すプログラム ● 次にcall-funcというプログラムを読みましょう – objdump -d call-func してください – mainのサブルーチンを見てみましょう
  58. 58. 関数を呼び出すプログラム ● call <foo>がfoo関数を呼んでいそう? – 関数の呼び出しを見る時はスタックを意識します
  59. 59. 今日のテーマ(最重要) スタックと関数
  60. 60. スタック ● データ構造の一種 – Push: 新しいデータを積むこと – Pop: 一番上のデータを取り出す
  61. 61. スタック ● コンパイラはCのコードをアセンブラで表現する – コンパイラを作る人の気持ちになってください – アセンブリ命令作る人の気持ちにもなるとなお良し ● Cの関数を表現する上で必要なことはなにか? – ローカル変数用の領域は呼び出しごとに取る必要あり – 引数も与えれないと困る – 関数を呼び出した位置にreturnで戻れる必要がある
  62. 62. スタック ● それってスタックが使えるのでは? – 関数を呼び出す時に引数と呼び出した位置をpush – 関数からreturnする際にpopしてその位置に戻る – 呼び出しの入れ子や再帰にも対応できる コードの10行目から3行目の関数を呼ぶ時、 スタックには引数、11をpush、 関数内では引数のみpop、 return時に位置をpopして11行目に戻る Basicのgotoみたいな。 イメージ:
  63. 63. スタック ● でもどうやってプログラム上でスタックを表現する? – メモリならいくらでもある – 上底と下底の位置で擬似的に表現できるんじゃ?
  64. 64. スタック 11行目 11行目 15行目 3行目 20行目 10行目 上底 下底 メモリ
  65. 65. スタック ● でもどうやってプログラム上でスタックを表現する? – メモリならいくらでもある – 上底と下底の位置で擬似的に表現できるんじゃ? – それらの位置はレジスタに記憶させればいい ● → espとebp – esp ・・・ extended stack pointer(上底) – ebp ・・・ extended base pointer(下底)
  66. 66. スタック ● つまり – 関数を呼び出す時には戻る位置をpushする ● espが指すアドレスに位置を入れてespの値をdec – 関数からreturnする時はpopして位置を変える ● espが指すアドレスから値を取ってespの値をinc
  67. 67. スタック ● ついでにローカル変数用のメモリ領域を取りたい – 呼び出しごとに必要ならスタック上に取るのが自然 – 関数を呼び出した時にスタックの中に取っては? ● 少し余分にespをdecすればいいこと – これで全ての問題をクリア出来た!
  68. 68. イメージ図 関数fooへの引数 戻りアドレス fooのローカル変数 関数putsへの引数 戻りアドレス
  69. 69. 関数を呼び出すプログラム ● これを踏まえてfoo関数の呼び出し部分を見てみます movl $0x80484e0,(%esp) call 804841d <foo>
  70. 70. 関数を呼び出すプログラム ● これを踏まえてfoo関数の呼び出し部分を見てみます movl $0x80484e0,(%esp) call 804841d <foo> 引数(char*=アドレス)をスタックにpush
  71. 71. 関数を呼び出すプログラム ● これを踏まえてfoo関数の呼び出し部分を見てみます movl $0x80484e0,(%esp) call 804841d <foo> 戻るためのアドレスをスタックにpushして関数fooにjmpする
  72. 72. 関数を呼び出すプログラム 8048439: movl $0x80484e0,(%esp) 8048440: call 804841d <foo> esp
  73. 73. 関数を呼び出すプログラム 8048439: movl $0x80484e0,(%esp) 8048440: call 804841d <foo> 0x80484e0 esp
  74. 74. 関数を呼び出すプログラム 8048439: movl $0x80484e0,(%esp) 8048440: call 804841d <foo> 0x80484e0 0x8048445 esp
  75. 75. 関数を呼び出すプログラム ● movl $0x80484e0,(%esp)はpushではないのでは? – 確かにmovだけではpushにならない ● 「push A」 = 「sub $0x4, %esp; mov A, (%esp)」 – ポイントは、関数呼び出しの前のsub $0x10,%esp ● 「sub $0xC,%esp; push A」と ● 「sub $0x10,%esp; mov A,(%esp)」は同値 ● Linuxのバイナリでは関数の頭で予め引くことが多い
  76. 76. 関数を呼び出すプログラム ● fooの引数参照 – 戻りアドレスと引数をpushしてfooが呼び出された – 引数の参照を何で行う? ● イチイチpopするのは非効率 ● メモリとして参照したほうが賢い ● アドレスをregisterで記憶する必要がある ● registerは数が限られている ● ebpを上手く使えないか? ● 戻りアドレスあたりを記憶しておくと効率良さそう
  77. 77. イメージ図 関数fooへの引数 fooのローカル変数 関数barへの引数 戻りアドレス
  78. 78. イメージ図 関数fooへの引数 fooのローカル変数 関数barへの引数 戻りアドレス esp
  79. 79. イメージ図 関数fooへの引数 fooのローカル変数 関数barへの引数 戻りアドレス esp ebp
  80. 80. 関数を呼び出すプログラム ● fooの引数参照 – これでebp+offsetで引数のアドレスが求められそう – でも複数回関数が呼ばれるとマズイ ● ebpの値を呼び出すごとに変える必要あり ● return時には元の関数に合う様戻さないといけない – ebpの値もstackに記憶してはどうか? ● 呼び出し時に戻りアドレスと一緒にpush ● 新しく呼ばれた関数に値を合わせる ● return時には戻りアドレスと一緒にpop
  81. 81. イメージ図 関数fooへの引数 戻りアドレス fooのローカル変数 関数putsへの引数 戻りアドレス 元のebpの値 元のebpの値
  82. 82. 関数を呼び出すプログラム ● 実際の呼び出し過程 – 引数をpush – callにより戻りアドレスをpushし呼び出し先へjmp – 元のebpの値をpush – ebpをespの値に設定 – espから必要な分値を引く
  83. 83. 関数を呼び出すプログラム ● 実際のreturn過程 – espをebpの値に設定 – ebpへ元のebpの値をpop – 戻りアドレスへjmp(ret命令) – 必要であれば引数をpop
  84. 84. 関数を呼び出すプログラム ● デバッガで確認しましょう – gdb ./call-func -q – b fooでfoo関数を設定 – rで実行 – スタックの中身を表示してみてください ● x/xw $espでしたね ● x/8xw $espのように複数表示することも出来ます
  85. 85. 関数を呼び出すプログラム ● ひと目でローカル変数の領域がどこか分かりますか? – 冒頭のsub $0x18,%espから24byteだと分かる – つまり下絵の初め6つがローカル変数用の領域 – 残り2つはそれぞれ前のebpとreturn address – 引数はreturn addressの下だからebp+8だと分かる
  86. 86. 関数を呼び出すプログラム ● fooの引数はなんでしょう? – ソースコードから、char*であることは分かる – gdbで確認してみましょう – 引数はebp+8なのでx/xw $ebp+8 – 表示された値はchar*だからこれもアドレス – x/s 0x080484e0で文字列として表示できます ● x/s *(char**)($ebp+8)でもOK
  87. 87. メモリに代入するプログラム ● まとめ – 関数の呼び出しは一種のスタック操作になっている – ebpで引数やローカル変数を参照して効率化している – スタックのイメージがexploitationでは重要になる
  88. 88. 演習 ● problemというファイルを読んでください。 – /dev/nullに書き込んでいる内容を答えとします – 少し難しいかもしれません ● 今までの内容をよく思い出しましょう
  89. 89. 演習 ● Hint1 – main関数がない! – 難読化(?)っぽいのがかかってる – stripと言い、gccの標準機能です ● サブルーチン名は人間用の情報なので削除可能 – libc_start_mainの第1引数はmainのアドレスです
  90. 90. 演習 ● Hint2 – 呼ばれる標準関数はpltセクションにかいてあります – objdumpで「セクション .plt の逆アセンブル:」を確認 – ファイルに書き込みを行う関数はどれ? ● Hint2 – 呼ばれる標準関数はpltセクションにかいてあります – objdumpで「セクション .plt の逆アセンブル:」を確認 – ファイルに書き込みを行う関数はどれ?
  91. 91. 演習 ● Hint3 – fwriteの引数はなんでしょうか? – 第1引数がファイルへ書き込むデータです – どうやら lea 0x20(%esp),%eax mov %eax,(%esp) のeaxが第1引数らしい – lea命令とは一体?
  92. 92. 演習 ● Hint4 – lea命令はメモリのアドレスの代入です ● lea 0x20(%esp),%eaxならeax = esp+0x20 – esp+0x20とは一体... ● 実は最適化でローカル変数をespで参照しています ● なのでesp+0x20はただのローカル変数 ● この中の値は後はデバッガか何かで調べられる
  93. 93. 演習 ● 答え – “THIS_IS_FLAGGGGx00”
  94. 94. 演習 ● まとめ – objdumpによる逆アセンブルを学んだ – 簡単なデバッガの使い方を学んだ
  95. 95. 自分で勉強するには ● とにかくバイナリを読みましょう – 僕はCTFをしまくった – 自分でコンパイルしたプログラムなどがオススメ ● 分からなくなったらソースコードを見ればいい ● forやwhileはどうなるの?ifはどうなる?switchは? – 本を買うのもいいかもしれません ● 楽しいバイナリの歩き方 ● x86アセンブラ入門 – ググることも忘れないで下さい
  96. 96. 意識すると良いこと ● C言語ではどのように対応するのか – ほとんどのバイナリはC, C++からコンパイルされる – つまりバイナリをCのコードで表すことが出来るはず – 読みながらCのコードに直していくのもアリ ● スタックの状況 – これはexploit、あるいは一部の難読化に関して – Return Oriented Programmingなどではこれが不可欠
  97. 97. 御静聴ありがとうございました

×