radare2によるバイナリ編集
radare2
はデバッガであり,バイナリエディタでもある.バイナリエディタとして使えると何かと便利だと思い,調べてみた.
基本的なことを書き残す.
環境
$ uname -a Linux poppycompass 4.11.3-1-ARCH #1 SMP PREEMPT Sun May 28 10:40:17 CEST 2017 x86_64 GNU/Linux $ r2 -v radare2 1.6.0-git 15021 @ linux-x86-64 git.1.4.0-472-g7512396ab commit: 7512396ab5ae5f7292f41a80dc0b4dca09c4d6f2 build: 2017-06-11__02:50:45
準備
radare2がインストールされていればOK.
# Ubuntu $ sudo apt install radare2 # Arch Linux $ sudo pacman -S radare2 # 最新好きの人 $ git clone https://github.com/radare/radare2 && cd radare2 && sys/install.sh
$ r2 -v
でそれっぽいのが出れば良い. 次に,適当なバイナリファイルを用意する.
$ echo -en "\xaa\xbb\xcc\xdd" > test.bin
基本
write mode
でファイルを開いて編集していく
$ r2 -w ./test.bin -- It's working! Look at the door! シェルを既に起動した場合は [0x00000000]> o+ <file> [0x00000000]> px 4 # ファイルの内容を確認 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 aabb ccdd .... [0x00000000]> w? # ヘルプ |Usage: w[x] [str] [<file] [<<EOF] [@addr] | w[1248][+-][n] increment/decrement byte,word.. | w foobar write string 'foobar' | w0 [len] write 'len' bytes with value 0x00 | w6[de] base64/hex write base64 [d]ecoded or [e]ncoded string | wa[?] push ebp write opcode, separated by ';' (use '"' around the command) | waf file assemble file and write bytes | wao[?] op modify opcode (change conditional of jump. nop, etc) | wA[?] r 0 alter/modify opcode at current seek (see wA?) | wb 010203 fill current block with cyclic hexpairs | wB[-]0xVALUE set or unset bits with given value | wc list all write changes | wc[?][ir*?] write cache undo/commit/reset/list (io.cache) | wd [off] [n] duplicate N bytes from offset at current seek (memcpy) (see y?) | we[?] [nNsxX] [arg] extend write operations (insert instead of replace) | wf -|file write contents of file at current offset | wh r2 whereis/which shell command | wm f0ff set binary mask hexpair to be used as cyclic write mask | wo[?] hex write in block with operation. 'wo?' fmi | wp[?] -|file apply radare patch file. See wp? fmi | wr 10 write 10 random bytes | ws pstring write 1 byte for length and then the string | wt[f][?] file [sz] write to file (from current seek, blocksize or sz bytes) | wts host:port [sz] send data to remote host:port via tcp:// | ww foobar write wide string 'f\x00o\x00o\x00b\x00a\x00r\x00' | wx[?][fs] 9090 write two intel nops (from wxfile or wxseek) | wv[?] eip+34 write 32-64 bit value | wz string write zero terminated string (like w + \x00)
以降,編集していく.
16進数の書き込み
[0x00000000]> wx eeff # 最初の2バイトを"eeff"に書き換え [0x00000000]> px 4 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 eeff ccdd .... [0x00000000]> wx 1122 @ 0x2 # オフセットを指定し,0x2(3バイト目)から0x1122を書き込み [0x00000000]> px 4 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 eeff 1122 ...
書き込みはオフセットを指定しない限り,現在のアドレスからの書き込みになる.
アドレスを変更したいときは> s <addr>
で移動できる.
文字列の書き込み
[0x00000000]> w poppycompass # "poppycompass"という文字列を書き込み [0x00000000]> px 20 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 706f 7070 7963 6f6d 7061 7373 ffff ffff poppycompass.... 0x00000010 ffff ffff ....
どうやら,ファイルサイズより大きく出力するとff
が入るようだ.
Visual modeで常に結果を見ながら編集する
実際に編集するときは,変更を加えてから毎回px 20
みたいなコマンドを打つのは手間だ.この問題は簡単に解決できる,そうVisual mode
ならね!
[0x00000000]> V # Visual modeに移行 [0x00000000 0% 504 ./bin]> xc - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF comment 0x00000000 aabb ccdd ffff ffff ffff ffff ffff ffff ................
この状態で:
を押して,通常通りコマンドを入力するだけ.
Press <enter> to return to Visual mode. :px 11223344<enter><enter> [0x00000000 0% 392 ./bin]> xc - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF comment 0x00000000 1122 3344 ffff ffff ffff ffff ffff ffff ."3D............
リトルエンディアンで書き込みたい!
> wv 0xaabbccdd # \xdd\xcc\xbb\xaaとして格納 > wv 0xaabbccddeeff0102 # \x02\x01\xff...として格納
1-4
bytesの数値は32ビットとして,5-8
bytesの数値は64ビットの値として取り扱われ,少ないバイトには00
が書き込まれる(0xaabb
だと\xbb\xaa\x00\x00
となる).
9
bytes以上の値を書き込もうとすると,失敗して全桁がff
になる.
アセンブルして書き込みたい
以下のファイルを用意する. $ echo "push eax\npop eax" > asm.txt $ r2 -w ./test.bin [0x00000000]> waf ./asm.txt もしくは [0x00000000]> "wa pop eax;push eax"
注意点は,> wa "pop eax;push eax"
じゃないこと.
Visualmodeで直接編集
Vimっぽく編集する方法がある.Stirling
などに慣れた人はこっちの方が親しみやすいかも.
[0x00000000]> V
c
を押すと,16進ダンプが囲まれるはず.ここからはvim.
移動はhklj
,編集場所にカーソルが来たらi
でインサートモード.
数値をいれたら上書きされる.終わったらEsc
を押す.
おまけ
Visual mode
の編集機能を使うと,通常のエディタっぽく使えなくもない.
以下はCでHello, Worldプログラムを書いた例.使いみちは無さそうだ.
$ r2 -- # ファイルを指定しないでシェルを立ち上げる > o+ hello.c # 書き込みモードで hello.c を開く > V # ヴィジュアルモードに移行して,書き込みを逐次見られるようにする
c
を押すと,16進ダンプが囲まれる.ここでタブを押すと,ASCII
の方が囲まれる.この状態でi
を押して,書くだけ.
改行(\x0a)とダブルクウォート(\x22)は16進からしか書けないのが難点.
[0x00000000 + 30> * INSERT MODE * - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F |0123456789ABCDEF| comment 0x00000000 2369 6e63 6c75 6465 203c 7374 6469 6f2e |#include <stdio.| 0x00000010 683e 0a69 6e74 206d 6169 6e28 766f 6964 |h>.int main(void| 0x00000020 2920 7b20 7072 696e 7466 2822 4865 6c6c |) { printf("Hell| 0x00000030 6f2c 2057 6f72 6c64 2122 293b 207d ffff |o, World!"); }..| $ cat hello.c #include <stdio.h> int main(void) { printf("Hello, World!"); }
volatilityにプロファイルを追加する方法
メモリダンプ解析用ツールvolatility
はデフォルトではWindows
のメモリダンプのみが解析できる.Linux
やOSX
で作成されたメモリダンプを解析するためにはプロファイルを追加してやれば良い.公式から用意されているものを使うこともできるし,自作することもできる.
概要
プロファイルの追加は定義ファイルを追加すればよい.いくつかは公式から用意されており,基本的にはGithubからcloneするだけで使える.
$ git clone https://github.com/volatilityfoundation/profiles $ cd profiles $ find -type d -maxdepth 2 ... snip ... ./Mac ./Mac/10.10 ./Mac/10.5 ./Mac/10.8 ./Mac/10.9 ./Mac/10.6 ./Mac/10.12 ./Mac/10.7 ./Mac/10.11 ./Linux ./Linux/Fedora ./Linux/Ubuntu ./Linux/Debian ./Linux/CentOS ./Linux/RedHat ./Linux/OpenSUSE ... snip ...
以上のように複数のディストリのプロファイルが用意されている.各ファイルにはx86
とx64
がある.
使い方
使い方はvol.py
またはvolatilty
が参照しているplugins
というディレクトリにZIP
のままコピーする.
以下はUbuntu14043
のx64
版のプロファイルを使えるようにする場合.
$ pwd profiles # ローカルなvolatilityを使っている場合 $ cp Linux/Ubuntu/x64/Ubuntu14043.zip volatility/plugins/Linux # apt/pacmanなどでインストールしたvolatilityを使っている場合 $ cp Linux/Ubuntu/x64/Ubuntu14043.zip /usr/lib/python2.7/site-packages/volatility/plugins/linux/
確認
以下は,/usr/lib/python2.7/site-packages/volatility/plugins/linux/
にコピーした場合のコマンド.
$ volatility --info Profiles -------- LinuxUbuntu14043x64 - A Profile for Linux Ubuntu14043 x64 VistaSP0x64 - A Profile for Windows Vista SP0 x64 VistaSP0x86 - A Profile for Windows Vista SP0 x86 VistaSP1x64 - A Profile for Windows Vista SP1 x64 VistaSP1x86 - A Profile for Windows Vista SP1 x86 ... snip ...
後は通常通り
$ volatility -f <dump_file> --profile=LinuxUbuntu14043x64 linux_lsof
といった感じで解析できる.
プロファイルを自作する
IIJがいい感じでまとめていた.自作したい人はこちらを参照.ツールがvolatility
に用意されているから,作成したいディストリ上でmake
してzip
するだけのようだ.特定のバージョンを作りたいときはカーネルをrpm
で持ってくる必要あり.
Internet Infrastructure Review(IIR)Vol.32 | IIJの技術/セキュリティレポート | IIJ
おまけ
ZIP
ファイルはplugins
以下に置けば認識してくれるから,
$ cp profile.zip /usr/lib/python2.7/site-packages/volatility/plugins/self_made
といった目的別に分けることもできる.便利.
サイボウズの開発インターンに参加してきた
サイボウズで行われている開発インターンに3週間行ってきた.何をしたのかを含めて振り返りを書き残す.
きっかけ
就職が近くなってきて,どこか行かなきゃとは思うけどどこにいったらいいのかわからない.
周りの人は有名企業のエリートコースを狙って頑張っているが,それらの職業は上流過ぎて今持っている技術力は全然活かせそうにない.(でも稼ぎたい)
技術を活かしたり,磨くのが好きだから,これができるであろうエンジニアとして働くことを考え,職業としてのエンジニアを深く見たいからちょっと長めで現場で働けるインターンを探した.
いくつか候補は見つけた中で,IPAのセキュリティイベントでよく聞く川合秀実さんのいるサイボウズに興味を持ち,行ってみた.因みに,行く前のサイボウズに対する印象は
開発インターンは通年で募集している.kintoneというWebサービスの開発チームと一緒に機能の拡張や実装を行っていくインターン.
デフォルトは10日間だが,実装に心残りが出ると思ったため,もう一週間長くやりたいと言うだけ言ってみた.向こうも考えてくれた上で受け入れてくれた.有り難い.
勤務地はサイボウズの本社支社がある,東京・大阪・松山のどれかを希望できる.比較的近い大阪支社に行かせてもらった.離れた場所に住んでいても,部屋を手配してもらうことは可能らしい.
余談だが,インターン期間中は1日1万円の報酬がついている.本職エンジニアの技や生活を学べる上にお金をもらえるなんて素晴らしい.
大阪支社の場所
阪急梅田駅から直進徒歩5分もかからない場所にある阪急梅田ビルの35階.屋上駐車場を見下ろすことができる高さで,見晴らしはムスカ大佐.雨で霧がかかっている日は街が3割増し幻想的に見えた.画像は夕方.
kintoneについて
kintoneというサービスについて軽い説明をする.(インターン前はkintoneの名前・有用性がよくわかっていなかった)
サイボウズが提供しているサービスは「Office」「Live」「Garoon」「kintone」などがある.それぞれグループを作って会話したり,予定管理をまとめることができたりする.
kintoneはSlackみたいなチャット機能に加えて,テーマなどをまとめるスレッド・スペースを管理できる.大きな特徴として,kintoneでは既存のパーツなどを使って目的に応じたアプリを作成することができる.例えば,製品開発の進捗を行単位のレコードで表すアプリを作成したいときには,任意の数の列や選択を設定することができる.
使い込む時間はなかったが,データ管理については柔軟性が非常に大きいと思う.仕事向きに作られているから,学生の間では利点が伝わりにくいのが残念.
主に使うのはチャット機能で,色んな人の投稿を眺めることができる.数時間見ないでいると50件以上溜まったりするから驚くが,一覧にすると見やすいから問題はない.
インターン中は自分のつぶやきスペースで思いついたことをつぶやいたり,わからないことを質問すると誰かが答えてくれた.
サイボウズのアメニティグッズにキリンやゴリラがプリントされることがあるから,てっきりイメージキャラクターだと思っていたが,現場のエンジニア曰く公式キャラはいないらしい.黄色いからキリンがキャラだと思っていた.
職場の雰囲気
メンター(主に教えてくれる人)は非常に丁寧に対応してくれる人で,こちらの細かな質問にも一つ一つ答えてくれた.
周りの社員の方々がそれぞれの就職に対する考え方についても教えてくれたので,非常に参考になった.
経営理念として,「チームワークあふれる社会を創る」とあり,それを実現していることを実感した.
kintoneでつぶやくと,近くの席の人が直接話しかけてくることもあって楽しかった.東京のエンジニアから返事が来ることもあり,自社製品で全社をしっかり繋いでいる印象だった.
概ねいい場所だが,難点も当然ある.それは質問する時.メンターの人が在宅勤務や出張などでいないときは,チャット機能を使って質問することになる.直接話すときと違い,タイプや考えることでレスポンスが遅くなるため,ストレスを感じることもあった.これを解決するためにテレビ電話があるが,インターン中は使い方がよくわからず放置してしまった.早めに使えばよかった・・・.
在宅勤務は仕事に集中できるのかという質問をしてみたところ,「在宅だとリミッターが外れて出社するよりも仕事が進んで止められない.そんな人間を採用しているから大丈夫」といった返答をいただいた.理由がとってもサイボウズ.
メンターはこちらの質問の本質を探して,その問題を解決するためにより効率的なアプローチを提案してくることが多かったように思う.質問した内容にそのまま答えるよりも良い返答だと感じた.本質を探す真似をしてみようと思ったが,上手く行かなかった.まだまだ未熟.
当然社員の方々はバリバリの実装マンで実力主義な雰囲気を感じた.
やったこと
これを繰り返す感じ.途中で寿司を食べながら自分の好きなことについて話すイベントもあった.スクラム開発は最近サイボウズでやり始めた,短期的に進捗を確認しながら仕様などを見直していく開発工程のこと.語源はラグビー.
一週間に一回kintone開発チーム全体に進捗を発表する時間を設けてもらって,そこで何をやっているかを発表していく.本職の人にコメントをもらえるので,非常に励みになった.
出来事
サイボウズでの日々をもう少し詳しく書いておく.
1週目
- 環境の準備
- kintoneをローカルで立ち上げる
- kintoneを触りながら,改善できそうな部分を探す
- テーマ決め
- スクラム開発の基礎を勉強
5日間のインターンだと社員さんが用意している課題を勧められることが多いらしいが,時間があるとのことでじっくり考えることができた.
スクラムでやることについては,スクラムマスターという資格を持った社員さんが自発的に教えてくれた.有り難い.
覚えることが多かったり,慣れない職場で帰るとすぐ寝ていた.
2週目
- PBL/SBLの作成
- 実装・コードレビュー・リファクタリング 社員さんに自分の書いたコードがゴリゴリ綺麗な構文になっていくのは気持ちが良かった.コードの行数が少ないって素晴らしいって改めて思う.
まだ一週間あるため,実装に集中できる一番平和な期間だった.周りを見渡す余裕が出てきて,会社の日常を味わえるようになってくる.長めのインターンの醍醐味はここだと思う.
3週目
- 実装
- ローカル環境が壊れる
- Gitをrebaseしようとして,山ほどの衝突が起きてつらい
- テスト用に作成したデータが検証の途中で初期化される
- 資料の作成が終わらない
先週のペースなら余裕と思っていたら,インターン終了前日にローカルkintoneクラッシュから始まる悪夢の行進.最終成果発表1時間前に必死に資料を作っていた.
大切な発表は,2日前までに資料を作成し,前日は発表練習に充てましょう.
最後は送別会まで開いてもらった.
小話
- インターン生はランチ代の補助が出る日がある.ランチパスポートがあると安く抑えられそう
資料作成用にMacを貸してもらっていたが,"kintone"といれると,ことえりの自動変換で"intone" or “kenton"になる
- この変換をバイパスするには"KIntone" or “kinTone"がおすすめ(そもそも変換をGoogleのやつに切り替えれば解決する)
スタンディングデスクが来た!
- 画像はインターン期間中に来たスタンディングデスク.立ったまま使うための机.椅子を持ってきて,わざわざ椅子に座ってスタンディングデスクを使う猛者もいた.スタンディングデスクで立ったままプログラムを組んでみたが,足に力を入れながらタイプする経験があまりなかったから新鮮だった.レベルの高い立ち読みという印象.マウスを落とすと高さ2倍で威力も大きいというkintoneへの投稿もあった.
- サイボウズ内では「マッスル部」という部活があるほど筋トレや運動に対して積極的だった.ずっと座っているから体の衰えが気になってくる(切実).就業中に流れてくるつぶやきもマッスル部が多かった印象がある.内容はどのプロテインが美味しかったとか,自分の筋トレメニューを解説していたりしていた.コード調査に疲れたときに元気をもらっていた.
筋トレ用具を常備している人もいる.
- カフェ部というものもあり,屋上駐車場よりも高い眺めを一望できるラウンジで弁当と一緒にコーヒーや紅茶を嗜む.
- バレンタインや最終日に開いていただいて美味しいコーヒー・紅茶を味わった
恩恵
- サイボウズでエンジニアの生活を実感できる(働きやすい!)
- 一週間以上行くことで,会社の普段の雰囲気をつかめてくる
- 大規模プログラムを触ることができる
- 報酬あり(1万/日)
興味が出た人へ
言語はJava, Javascript, CSS, HTML, SQLといったWebの基礎知識があったほうが良い.無いならないでその場で聞くなり,触って感じればいい.
インターンの面接は実力をよく見られた印象がある.今までに何を作ってきたのかを説明したり見せることができると良さそう.
でも,興味があるのなら実力がついてから応募しようなんて難しいことを考えずにとりあえず応募してみると良いと思う.その後はなるようになる.
インターンシップ | サイボウズ 採用情報(新卒・キャリア)
最後に
働くと起きている時間の殆どを仕事に使うことになる.仕事を好きになれないと辛いことになりそうだから,興味を持って働ける場所に行きたいと思う.
インターンでは,研究室にこもっているだけでは到底出会えない経験をさせてもらった.言葉では言い表せない感謝を忘れないようにしたい.
- エンジニアが過ごしやすい雰囲気
- 在宅勤務などの新しい働き方を積極的に取り入れている
- 社員さんのレベルが高くて尊敬できる!
- 筋肉に興味があるならマッスル部
な会社です.
最後にサイボウズで関わってくださった皆様,3週間ありがとうございました!
findしてlessする動作を自動化するシェル関数
基本的にfind
コマンドで探したファイルはless
などで閲覧することが多い.大きなプログラムだと,ディレクトリごとに名前が同じファイルがあったりするから,find
して目grep
してパスをコピーしてless
するって動作を繰り返しているとうんざりしてくる.そこで自動化するシェル関数を作成した..zshrc
に追記すれば使える.
やりたいことはless $(find -name "hoge")
.複数ヒットしたときもカバーしたいと思うと複雑になってくる.
code
# findで見つけたファイルを表示し,lessする function fl() { if [[ $# -gt 0 ]]; then list=`find -type f -name $1 2>/dev/null` if [[ $list = "" ]]; then line="0" else line=`echo $list | wc -l` fi case "$line" in "0") echo "No file" ;; "1") less $list ;; *) echo -en $list | nl arr=(`echo $list | tr -s '\n', ' '`) echo -en "file: " read num less $arr[$num] 2>/dev/null ;; esac else echo "fn \"<file_name>\"" fi }
使用例
$ fl "*zshrc" 1 ./git/zsh/StartupFiles/zshrc 2 ./dotfiles/.zshrc flie: 2 <Enter>
検索する対象はカレントディレクトリ以下.ダブルクウォートで囲めばワイルドカードでの検索もできる.候補が一つしか無いときはそれをless
する.
とりあえずこれを使って,不便なら繰り返し処理を加えるなりしてみようかな.
そもそもIntelIJ
みたいなIDE使えという話もあるが,手軽に探す分にはこれで十分だろう.コードが冗長な気がするから,気が向いたら書き直す.
参考
既出の値を判定するコードについて思いついたこと(ビンゴゲームをネタに考える)
重複を許さないランダムな数値を一定数生成したいという機会は割りと遭遇する.このときの既出判定についてふと思いついたことを書き残す.
「そんなの一般的に使われている」というツッコミは置いておく.実装についての答えを示すものではなく,「簡単な用途であればこんな実装のほうが綺麗だな」って話.
きっかけ
去年開催された忘年会において,ビンゴゲームが開催された.その際に「白紙を渡すから,1-16の数字の中から,9個選んで3x3に適当に書け」ということになった.
自分で選ぶのも一興だが,時間がないときにはプログラムに任せて一瞬で作成してしまいたい.乱数を生成する事自体はAPIを使えば非常に簡単に生成できる.しかし,既出判定の部分が面倒臭いから簡単にできないものかと考えた.
以降のコードの目的は,ビンゴと同じ1-16の数値を被らないように9個選ぶこととする.変数や分岐などはC言語で考えている.
最初に思いつくやつ
出てきた数字を配列に格納し,生成した数字が出ているかを確認する.実装としては以下のような感じか.
int buf[9] = {0}; int i, j, t, c=0; srand(time(NULL)); for (i=0; i<9; i++) { while (1) { // 生成 t = rand() % 16 + 1; for (j = 0; j < 9; j++) { // 既出チェック if (buf[j] == t) c = 1; } if (c == 1) { c = 0; continue; } // c=1なら,既出でもう一回 break; } c = 0; buf[i] = t; // 出力処理 }
というように,どうにも入り組んだものになりがちである.他の処理があったりすると,読みたくないコードになってくる.既出判定のオーダーは,配列長nの半分程度だから,O(n/2)
かな?
このコードだと取り扱う数字・個数が大きくなっても使えるが,毎回線形探索するのはオーバヘッドばかりかかる.かといって配列を毎回ソートし,二分探索みたいなことするのも複雑だ.ビンゴ生成にそこまでやるかという問いはさておき.
楽そうなコード(フラグ管理してみる, 配列)
フラグ管理してしまえば簡単だなと思った.乱数を添字にして,フラグ配列に1が入っていれば既出,0なら未出扱い.
int flag[16] = {0}; // フラグ管理 for (i=0; i<9; i++) { tmp = rand() % 16 + 1; // 1-16の値をランダム生成 if (flag[i-1] == 1) continue; // 既出だから,もう一回 flag[i-1] = 1; // 出力処理 }
大分スッキリした.既出判定は一回しか参照しないから,オーダーはO(1)
のはず.問題は,取り扱う数値・個数が多くなったときに使用するメモリ量が大きくなりがちなこと.
もうちょい改良してみる.
楽そうなコード(フラグ管理してみる, 省メモリ)
フラグは0/1しかないのに,何もわざわざint
の配列を確保する必要はない.変数一個だけでも行けるなと気づいた.ブール変数の配列とどっちがいいんだろうか.
unsigned int flag = 0; // 64ビットOSだと,変数の大きさは64ビット int i, t; srand(time(NULL)); for (i=0; i<9; i++) { while (1) { t = rand() % 16 + 1; if ( (flag & (1 << (t-1) )) == 0 ) break; // t-1ビット目に1が立っていれば既出扱い,0なら未出 } flag |= (1 << (t-1)); // 出力処理 }
初見だと少し読みにくい印象.
これもオーダ的にはO(1)
か.64個までしか数字を取り扱わないのなら,これでも十分にできる.しかし,64以上の整数や個数を取扱いにくいのが難点.
多倍長的なものを実装するのが良いが,これは実装コストが一気に上がる(といっても配列のどの要素を見るかの処理を加えるくらいだが).GMPを使えば楽にできそうだが,GMP使うと速度が下がりがちだから,要注意か.
完成版ビンゴジェネレータ
現実で使う機会が無さそうだから,ここでソースを挙げておく.
/* bingo.c */ #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { unsigned int flag = 0; int i, t=0; printf("=== Bingo Card Generator ===\n" "================\n|"); srand(time(NULL)); for (i=0; i<9; i++) { while (1) { t = rand() % 16 + 1; if ( (flag & (1 << (t-1) )) == 0 ) break; } flag |= (1 << (t-1)); if ( ((i % 3) == 0) && (i != 0) ) printf("\n|"); if (t >= 10) printf(" %d |", t); else printf(" %d |", t); } printf("\n================\n"); printf("Good Luck!\n"); return 0; } /* E.O.F. */
$ gcc bingo.c -o bingo $ ./bingo === Bingo Card Generator === ================ | 2 | 16 | 8 | | 1 | 15 | 14 | | 13 | 5 | 4 | ================ Good Luck!
おわり
そこまで大きな数字・個数を取り扱わないものであれば,既出判定はフラグ管理するのがスッキリしててわかりやすそう.
Linuxで突然startxが起動しなくなったときの対処
startx
が上手くいかないときの対処はググると色々出てくるが,ややこしいやつばかり出てきた.そして,それを試しても成功しなかった.最終的に上手くいったことを書き残す.
症状
それまで普通に使えたUbuntuを再起動した途端にGUIで起動しなくなった.$ startx
してみると,
waiting for X server to shut down error setting MTRR (base = 0xd0000000, size = 0x04000000, type = 1) Invalid argument(22)
とでて,終了してしまう.
$ sudo Xorg -configure
してみると,セグフォが起こっていると言われた.
対処
いくつか試してみたが,結局
$ cp /etc/X11/xinit/xinitrc ~/.xinitrc
した後に$ startx
したら動いた.
下手にビデオカードやら何やら入れていないなら,.xinitrc
はいじらないほうが良いようだ.
使えれば良いや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+d
かexit
で終了.
最後に
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)