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)
csawctf 2016 writeup(forensics)
書くことがないから,最近参加したCSAWCTF 2016のWriteupをメモしておく.分野はforensics.ExploitやWebに比べると日本では人気がない印象があるのが残念.
evidence
evidence.zip
という壊れたZIPファイルが与えられる.
$ unzip -l evidence.zip Archive: evidence.zip Length Date Time Name --------- ---------- ----- ---- 1384576462406025012 1980-10-01 06:01 out/rxo802ayx4 1384576462406025012 1980-10-01 06:01 out/zhatnf5maf 1384576462406025012 1980-10-01 06:01 out/50lshu1ue6 1384576462406025012 1980-10-01 06:01 out/14o803swdq 1384576462406025012 1980-10-01 06:01 out/nppjdd2wdg 1384576462406025012 1980-10-01 06:01 out/e9ydsxwetg 1384576462406025012 1980-10-01 06:01 out/0eetjrxpdm 1384576462406025012 1980-10-01 06:01 out/otuj3jrezt 1384576462406025012 1980-10-01 06:01 out/m70ohrycax 1384576462406025012 1980-10-01 06:01 out/mpi3z4x5jt 1384576462406025012 1980-10-01 06:01 out/meoflsxv4v 1384576462406025012 1980-10-01 06:01 out/8y10tp04b2 1384576462406025012 1980-10-01 06:01 out/eui6ltoijl --------- ------- 17999494011278325156 13 files 以下,どうでも良い情報 1384576462406025012 -> 0x133700f4ee13ff34 17999494011278325156 -> 0xf9cb0c701703f5a4 全く意味のない数字のようだ.
作成日時も特に情報は見当たらない.
とりあえず
$ zip -FF evidence.zip --output fix.zip
で修復してみる.先に言っておく,これやった人はさようなら.
この後,
- unzip
- ファイル名がハッシュになっているかと検索
- base64で復号
- とりあえず,文字列を反対にしてみる
- 適当にXORしてみる
- コメントを期待して,unzip -z
- ..etc
をやってみたが,どうにも出てこない.
疲れて,基本に戻ってみようとZIP情報の詳細を見てみる.
$ unzip -vv ./evidence.zip Archive: ./evidence.zip Length Method Size Cmpr Date Time CRC-32 Name -------- ------ ------- ---- ---------- ----- -------- ---- 1384576462406025012 Unk:169 908 100% 1980-10-01 06:01 666c6167 out/rxo802ayx4 1384576462406025012 Unk:047 294 100% 1980-10-01 06:01 7b746833 out/zhatnf5maf 1384576462406025012 Unk:158 377 100% 1980-10-01 06:01 5f766931 out/50lshu1ue6 1384576462406025012 Unk:231 552 100% 1980-10-01 06:01 3169346e out/14o803swdq 1384576462406025012 Unk:223 249 100% 1980-10-01 06:01 5f77335f out/nppjdd2wdg 1384576462406025012 Unk:238 503 100% 1980-10-01 06:01 6e333364 out/e9ydsxwetg 1384576462406025012 Unk:045 150 100% 1980-10-01 06:01 5f236672 out/0eetjrxpdm 1384576462406025012 Unk:200 273 100% 1980-10-01 06:01 65656c65 out/otuj3jrezt 1384576462406025012 Unk:099 684 100% 1980-10-01 06:01 6666656e out/m70ohrycax 1384576462406025012 Unk:205 112 100% 1980-10-01 06:01 7daaaaaa out/mpi3z4x5jt 1384576462406025012 Unk:174 287 100% 1980-10-01 06:01 aaaaaaaa out/meoflsxv4v 1384576462406025012 Unk:193 172 100% 1980-10-01 06:01 aaaaaaaa out/8y10tp04b2 1384576462406025012 Unk:199 485 100% 1980-10-01 06:01 aaaaaaaa out/eui6ltoijl -------- ------- --- ------- 17999494011278325156 5046 100% 13 files
ああ,なるほどと気づいたときには笑った.こんなやり方もあるのか.CRCがASCIIだ.
666c61677b7468335f7669313169346e5f77335f6e3333645f23667265656c656666656e7d
-> flag{th3_vi11i4n_w3_n33d#freeleffen}
flag: flag{th3_vi11i4n_w3_n33d#freeleffen}
復元して頑張っても無駄だという問題.よくCRCにねじこんだな・・・.
watchword
Canned epic hidden snek flavored cookies have shy gorilla. Hint: http://domnit.org/stepic/doc/ Hint: It's not base64, but it uses the Python 3 base64 module password = password
問題文は知らない単語が多くて理解を投げた.ゴリラが何かしたらしい.
ヒントに沿って,http://domnit.org/stepic/doc/から,stepic-0.3.tar.gzをダウンロード.
$ tar xvf ./stepic-0.3.tar.gz $ cd stepic-0.3 $ sudo ./setup.py install 動作するためにImageが必要だったため, $ sudo pip install Image Image関連でエラーを吐くため, $ sudo vim /usr/bin/stepic [-] import Image [+] from PIL import Image
これで準備は完了.
動画ファイルをダンプしてみると,<data...>
というbase64があった.
"aHR0cDovL3N0ZWdoaWRlLnNvdXJjZWZvcmdlLm5ldC8="
-> http://steghide.sourceforge.net/base64
どうやら,steghide
が一枚噛んでいるようだ.
配られた動画ファイルを問答無用でforemost
.動画は結局見なかった.
$ foremost powpow.mp4
PNGファイルが出てきた.
8月にひっそりと日本での販売が終了したオレオの写真.foremost
しても何も出てこない.
また,PNGにはsteghide
が使えない.よって,stepicの出番.
$ stepic -d -i output/png/00001069.png -o out.jpg --debug
out.jpg
というJPG画像を取得する.画像は親子の微笑ましい会話.
以下,文章の訳.間違っていたら指摘してください.
> ねえ,お母さん.どうしていとこの名前はダイヤモンドなの? < おばさんが好きだからよ > 僕の名前は? < 私が好きなゴリラよ,Harambe
Harambeは先日子供を助けるために仕方なく射殺されたゴリラの名前.
Harambeはまだ良いが,おばさん,いくら好きでもダイヤモンドはキラキラしすぎじゃないかな・・・
< 閑話休題 >
JPGファイルはsteghide
でいける.パスワードが要求されるが,これは問題文で与えられたものを使う.
$ steghide extract -sf ./out.jpg Enter passphrase:password wrote extracted data to "base64.txt" $ cat ./base64.txt W^7?+dsk&3VRB_4W^-?2X=QYIEFgDfAYpQ4AZBT9VQg%9AZBu9Wh@|fWgua4Wgup0ZeeU}c_3kTVQXa}eE
base64.txt
が得られる.文字列の途中に=
が入っていたりと,問題通り普通のbase64ではないようだ.
ヒントにpython3のbase64のモジュールを使っているとあったため,
http://docs.python.jp/3/library/base64.html#module-base64
を参考に一通り試していった.結局,base85でエンコードされた文字列だった.
# decrypt.py, python3で実行推奨 # coding: utf-8 import base64 print(base64.b85decode("W^7?+dsk&3VRB_4W^-?2X=QYIEFgDfAYpQ4AZBT9VQg%9AZBu9Wh@|fWgua4Wgup0ZeeU}c_3kTVQXa}eE"))
$ python3 decrypt.py b'flag{We are fsociety, we are finally free, we are finally awake!}'
base85はASCII内でprintableな文字を全部使って限界に挑戦した符号化のようだ.データ量の膨張が6/4(1.5倍)のbase64に対し,base85は5/4(1.25倍)と,効率が良い.現在ではgitで使われているらしい.
最後に
forensicsはPwnやWebのようにきらびやかなハッカー・クラッカーっぽいものを感じにくい分野だが,解析のためにコマンドの細かいオプションを知ることができるといった面がある.
セキュリティをやっている理由が,色んなことを知りたいからという自分にとってはやってて楽しい分野.
もう少しくらいなら闇が深くても構わない.
ふと思ったが,IT業界って光という単語をあまり使わない気がする.闇の言語(C++とか)は存在するが,光の言語は聞いたことがない(Haskellとか純粋なものがある).その内出るかもしれないが,キャッチコピーが胡散臭すぎて使う気が起きなさそうだ.
そう思ってしまう辺り,IT業界に毒されているのだろう.
参考文献
Stepic - Python image steganography
19.6. base64 — Base16, Base32, Base64, Base85 データの符号化 — Python 3.5.2 ドキュメント
OSX(mac)にXmonadをインストールする方法
普段はLinuxにXmonadを入れて作業をしているが,短期間だけOSX(mac)を使うこととなった(知っている企業や大学ってやたらとLet's NoteとMacbookが好き.ThinkPadも選択肢に入れて欲しい).普段通りに作業するためにOSXにXmonadを入れる方法を模索し,動かすところまではいけた.しかしLinuxほどの快適さはないため,OSX(mac)ではXmonadを使わないほうが良い.代わりにXmonadを意識して作られたAmethystがとりあえずおすすめ.インストールの流れをメモ代わりに書き残す.
環境
$ uname -a 後で入力する(確かDarwinのx64)
OSXでXmonadを動作させる仕組み
XmonadはX11で動作するよう実装されている.どれくらい依存しているかというと,ソースコードのMain部にガッツリX11関連の関数を使っていて置き換えることが面倒くさそうな位依存している.
このためOSXで動作させるためのアプローチとしてはX11のOSX版であるXQuartzをインストールし,このX11上で動かすデスクトップマネージャ(DM)にXmonadを選択し,起動させる流れとなる.
インストール方法
brewのインストール
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
XQuartzのインストール
https://www.xquartz.orgからXQuartz-2.7.9.dmg
をダウンロード,インストール(ダブルクリックとContinueを押し続けるだけ).
インストールに成功すると,/Applications/Utilities/XQuartz.app
や/opt/X11/bin/quartz-wm
などができているはず.デスクトップの検索マークからXQuartzを探し,起動するとDock(デフォルトだと画面下にあるショートカットキーが並んでいるところ)に大文字のXが中心のマークが現れるはず.
XQuartzを選択した状態でデスクトップの左上のXQuartz -> Preferences
で各種設定を変更する.WinodowタブでFull Screen Modeを設定する以外は特にいじらなかった.
~/.xinitrc
があるとエラーが出ることもあるから,あるならrenameしておくほうが良い.
Haskellをインストールする
XmonadをインストールするためにHaskellのコンパイラなどをインストールする.She is Haskell.
って笑うやつは表に出ろ.すごいH本を朗読してやる.
https://www.haskell.org/platform/mac.htmlからHaskellのインストーラを落とす.ダブルクリックしてインストール.
インストールが終わったら,端末から
$ cabal update
でパッケージリストを最新に更新する.
xmonadのインストール
いよいよXmonadをインストールする.
$ cabal install xmonad
でできるはずだが,今回の環境ではXssライブラリがないとエラーが出た.原因は先ほどインストールしたXQuartzが持つX11のヘッダやライブラリ関係がパスに含まれていなことだった.よって今回のコマンドのときだけパスを追加してやれば良い.
$ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATH cabal install xmonad
これでXmonadがインストールできるはず.これでも駄目なら,
$ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATh cabal install X11
も試して,デバッグしていく.頑張れ.
Xmonad関連インストール
エラーが出るのを防ぐためにX11関連のヘッダを検索パスに含めておく.今回はシンボリックリンクを張る方法を選んだ.
$ ln -s /opt/X11/include/X11 /usr/local/include/X11 $ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATH cabal install xmonad-contrib xmobar
XQuarzの設定作成
X11(XQuartz)起動時に使われるWMを設定する.設定は環境変数USERWM
に使いたいWMのバイナリパスを入れてやる.
$ mkdir $HOME/.xinitrc.d/ $ vim $HOME/.xinitrc.d/90-xmonad.sh #!/bin/sh USERWM=$HOME/Library/Haskell/bin/xmonad # xmonadのバイナリが入っているところを指すようにする
xmonadのパスがわからないときは
$ find $HOME -name xmonad -type f 2>/dev/null
で検索する.
あとはX11が起動時に実行されるようにスクリプトに実行権限を付与する.
$ chmod +x ~/.xinitrc.d/90-xmonad.sh
X11で起動するWMをデフォルトのquartz-wm
に戻したければ
$ chmod -x ~/.xinitrc.d/90-xmonad.sh
で実行権限をなくせば良い.
以上で基本的な作業は終了.
後は各自xmonad.hs
や.xmobarrc
などを調整する.
起動
XQuartzが起動した状態で左上のXQuartzタブを押して,Toggle Full Screen
を押す.全画面がX11になり,Xmonadが使えるようになる(全画面にしなくても使えるが,全画面のほうがおすすめ).
戻り方
Command+Option+a
問題点
ワークスペースの切り替え,複数の端末操作は通常通り行えるが,/Applications
以下のアプリ(ブラウザやメーラ)をXmonad上で実行する方法がわからないといった致命的な問題にぶち当たり,解決策を思いつかなかった.少し使ってみての問題としては以下が挙げられる.
- OSXではXmonadの相棒
urxvt
でclear
コマンドが動かない - Chromeなどの
/Applications
以下にインストールされているアプリを起動させるとXmonadからホストのWMに戻り,そちらで起動してしまう - デフォルトで起動するxtermはマルチバイト文字読めない・入力できない
xmonad.hs
,.xmobarrc
をOSX用に調整しないといけない- デバッグしたくない
問題が山積みでここまでしてXmonadに固執する必要もない気がしてきたから,Amethyst
も試してみた.そしたら比較的快適だったから今回はこっちを使うことにした.
Amethystのインストール
$ brew cask install amethyst
とても簡単.
Amethyst設定
System Preferences
を立ち上げ,Security & Privacy -> Accessibility
,左下のロックボタンを押してロックを解除し,'+'を押す.Applications -> Amethyst
を選択し,権限を与える.詳しくはAmethystのgithubを見るのがわかりやすい.
Amethystの起動
デスクトップの検索からAmethystを検索して起動するだけ.
提供する機能はウィンドウ同士の配置を自動でXmonad風に整形,ウィンドウの選択・入れ替えといったシンプルな部分のみ.
ワークスペースの切り替えはMission Controlによるものになるが,どうにも無駄な動作が多くて疲れる.xmobarを入れて使いたいが,それっぽいものは今の所無いようだ.OSXは余程追い詰められない限り使わないと決心した.
他にはhttps://github.com/arnihermann/osxmonadといったものもあるようだったが,ワークスペースの実装がされていないと書いてあったため使わなかった.
最後に
Linuxはさいきょう
参考サイト
Xmonad on Apple OSX: Xmonad/Using xmonad on Apple OSX - HaskellWiki
xmonad Q&A: Can't build X11 due to ld linking error on OSX 10.9.2 · Issue #24 · xmonad/X11 · GitHub
彼女はちょっと純情すぎるだけなんだ: She is Haskell. : プログラマーが覚えておくべき10の英語フレーズ - NAVER まとめ
Amethyst: GitHub - ianyh/Amethyst: Automatic tiling window manager for OS X à la xmonad and i3.
ELFバイナリのデバッグ時の関数名を読めなくする方法
Defconとかでは問題のELFバイナリをデバッグすると,ユーザ定義関数名だけでなく,ライブラリ関数名も読めなくなっている.どうやるとこんなバイナリを作れるのかを調べてみた.結論から言えば,静的リンクでコンパイルして,stripでデバッグシンボルを消すだけだった.
ライブラリ関数名の読めないプログラム
例えば,/bin/id
をexecve
関数で実行するだけのid.c
を考える.
/* id.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(void) { char *env[] = {NULL, NULL}; char *args[] = {"/bin/id", NULL}; execve("/bin/id", args, env); return 0; } /* E.O.F. */
ここで使われているライブラリ関数はexecve
だけ.これの関数名消去がうまく行くと,以下のようなアセンブラになる.
$ r2 -c 'aa;pdf@main' ./id [x] Analyze all flags starting with sym. and entry0 (aa) fcns: 4 xref: 54 sect: 550756 code: 1139 covr: 0 % / (fcn) main 68 | ; var int local_8h @ rbp-0x8 | ; var int local_10h @ rbp-0x10 | ; var int local_18h @ rbp-0x18 | ; var int local_20h @ rbp-0x20 | ; DATA XREF from 0x0040082d (main) | 0x0040092e 55 push rbp | 0x0040092f 4889e5 mov rbp, rsp | 0x00400932 4883ec20 sub rsp, 0x20 | 0x00400936 48c745f00000. mov qword [rbp - local_10h], 0 | 0x0040093e 48c745f80000. mov qword [rbp - local_8h], 0 | 0x00400946 48c745e04477. mov qword [rbp - local_20h], str._bin_id | 0x0040094e 48c745e80000. mov qword [rbp - local_18h], 0 | 0x00400956 488d55f0 lea rdx, [rbp - local_10h] | 0x0040095a 488d45e0 lea rax, [rbp - local_20h] | 0x0040095e 4889c6 mov rsi, rax | 0x00400961 bf44774800 mov edi, str._bin_id ; "/bin/id" @ 0x487744 | 0x00400966 e8450e0300 call fcn.004317b0 ; !!! 本来 "call sym.imp.execve"とでる !!! | 0x0040096b b800000000 mov eax, 0 | 0x00400970 c9 leave \ 0x00400971 c3 ret
0x00400966
の行を見ると,sym.imp.execve
と普通にコンパイルしたら出るはずがfcn.004317b0
になっている.
普段こんなバイナリが来ると,引数と演算結果を見てどの関数かを特定しているが(それしか知らない),ライブラリ関数を20種類以上使われていると心にヒビが入ってくる.
こいつの関数名復元方法を知るためにまずは作り方を調べた.
この方法では消えない
関数名の削除はデバッグシンボルの削除でできると考えて,まずは以下のコマンドを試してみた.
$ gcc -o id id.c $ strip --strip-all ./id # シンボル情報の全削除 $ r2 -c 'aa;pdf@main' ./id [x] Analyze all flags starting with sym. and entry0 (aa) fcns: 13 xref: 22 sect: 434 code: 470 covr: 108 % ;-- main: / (fcn) sym.main 68 | ; var int local_8h @ rbp-0x8 | ; var int local_10h @ rbp-0x10 | ; var int local_18h @ rbp-0x18 | ; var int local_20h @ rbp-0x20 | ; DATA XREF from 0x0040040d (sym.main) | 0x004004e6 55 push rbp | 0x004004e7 4889e5 mov rbp, rsp | 0x004004ea 4883ec20 sub rsp, 0x20 | 0x004004ee 48c745f00000. mov qword [rbp - local_10h], 0 | 0x004004f6 48c745f80000. mov qword [rbp - local_8h], 0 | 0x004004fe 48c745e0b405. mov qword [rbp - local_20h], str._bin_id | 0x00400506 48c745e80000. mov qword [rbp - local_18h], 0 | 0x0040050e 488d55f0 lea rdx, [rbp - local_10h] | 0x00400512 488d45e0 lea rax, [rbp - local_20h] | 0x00400516 4889c6 mov rsi, rax | 0x00400519 bfb4054000 mov edi, str._bin_id ; "/bin/id" @ 0x4005b4 | 0x0040051e e8adfeffff call sym.imp.execve ; !!! 消えてない !!! | 0x00400523 b800000000 mov eax, 0 | 0x00400528 c9 leave \ 0x00400529 c3 ret
0x0040051e
を見ると,関数名が消えてない.
そもそもstrip
で消えているものはあるかを確認すると
$ gcc -o id id.c $ file ./id id: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=55cd7bdcff079fbbad7be7450777c5645fcd4f41, not stripped # stripされてない $ readelf -a ./id > nonstrip $ strip --strip-all ./id $ file ./id ./id: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=55cd7bdcff079fbbad7be7450777c5645fcd4f41, stripped # stripされた $ readelf -a ./id > stripall $ diff nonstrip stripall 13c13 < Start of section headers: 4784 (bytes into file) --- > Start of section headers: 2592 (bytes into file) 19c19 < Number of section headers: 31 --- > Number of section headers: 29 81,86c81,82 < [28] .shstrtab STRTAB 0000000000000000 000011a4 < 000000000000010c 0000000000000000 0 0 1 < [29] .symtab SYMTAB 0000000000000000 00000928 < 0000000000000660 0000000000000018 30 48 8 < [30] .strtab STRTAB 0000000000000000 00000f88 < 000000000000021c 0000000000000000 0 0 1 --- > [28] .shstrtab STRTAB 0000000000000000 00000921 > 00000000000000fc 0000000000000000 0 0 1 170,240d165 < < Symbol table '.symtab' contains 68 entries: < Num: Value Size Type Bind Vis Ndx Name < 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND < 1: 0000000000400200 0 SECTION LOCAL DEFAULT 1 < 2: 000000000040021c 0 SECTION LOCAL DEFAULT 2 < 3: 000000000040023c 0 SECTION LOCAL DEFAULT 3 < 4: 0000000000400260 0 SECTION LOCAL DEFAULT 4 < 5: 0000000000400280 0 SECTION LOCAL DEFAULT 5 < 6: 00000000004002e0 0 SECTION LOCAL DEFAULT 6 < 7: 0000000000400320 0 SECTION LOCAL DEFAULT 7 < 8: 0000000000400328 0 SECTION LOCAL DEFAULT 8 < 9: 0000000000400348 0 SECTION LOCAL DEFAULT 9 < 10: 0000000000400360 0 SECTION LOCAL DEFAULT 10 < 11: 0000000000400390 0 SECTION LOCAL DEFAULT 11 < 12: 00000000004003b0 0 SECTION LOCAL DEFAULT 12 < 13: 00000000004003e0 0 SECTION LOCAL DEFAULT 13 < 14: 00000000004003f0 0 SECTION LOCAL DEFAULT 14 < 15: 00000000004005a4 0 SECTION LOCAL DEFAULT 15 < 16: 00000000004005b0 0 SECTION LOCAL DEFAULT 16 < 17: 00000000004005bc 0 SECTION LOCAL DEFAULT 17 < 18: 00000000004005f0 0 SECTION LOCAL DEFAULT 18 < 19: 00000000006006e8 0 SECTION LOCAL DEFAULT 19 < 20: 00000000006006f0 0 SECTION LOCAL DEFAULT 20 < 21: 00000000006006f8 0 SECTION LOCAL DEFAULT 21 < 22: 0000000000600700 0 SECTION LOCAL DEFAULT 22 < 23: 00000000006008d0 0 SECTION LOCAL DEFAULT 23 < 24: 00000000006008d8 0 SECTION LOCAL DEFAULT 24 < 25: 0000000000600900 0 SECTION LOCAL DEFAULT 25 < 26: 0000000000600910 0 SECTION LOCAL DEFAULT 26 < 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 < 28: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c < 29: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c < 30: 00000000006006f8 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__ < 31: 0000000000400420 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones < 32: 0000000000400460 0 FUNC LOCAL DEFAULT 14 register_tm_clones < 33: 00000000004004a0 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux < 34: 0000000000600910 1 OBJECT LOCAL DEFAULT 26 completed.6945 < 35: 00000000006006f0 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fin < 36: 00000000004004c0 0 FUNC LOCAL DEFAULT 14 frame_dummy < 37: 00000000006006e8 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_ < 38: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c < 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c < 40: 00000000004006e0 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__ < 41: 00000000006006f8 0 OBJECT LOCAL DEFAULT 21 __JCR_END__ < 42: 0000000000000000 0 FILE LOCAL DEFAULT ABS < 43: 00000000006006f0 0 NOTYPE LOCAL DEFAULT 19 __init_array_end < 44: 0000000000600700 0 OBJECT LOCAL DEFAULT 22 _DYNAMIC < 45: 00000000006006e8 0 NOTYPE LOCAL DEFAULT 19 __init_array_start < 46: 00000000004005bc 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR < 47: 00000000006008d8 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_ < 48: 00000000004005a0 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini < 49: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab < 50: 0000000000600900 0 NOTYPE WEAK DEFAULT 25 data_start < 51: 0000000000600910 0 NOTYPE GLOBAL DEFAULT 25 _edata < 52: 00000000004005a4 0 FUNC GLOBAL DEFAULT 15 _fini < 53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ < 54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND execve@@GLIBC_2.2.5 < 55: 0000000000600900 0 NOTYPE GLOBAL DEFAULT 25 __data_start < 56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ < 57: 0000000000600908 0 OBJECT GLOBAL HIDDEN 25 __dso_handle < 58: 00000000004005b0 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used < 59: 0000000000400530 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init < 60: 0000000000600918 0 NOTYPE GLOBAL DEFAULT 26 _end < 61: 00000000004003f0 42 FUNC GLOBAL DEFAULT 14 _start < 62: 0000000000600910 0 NOTYPE GLOBAL DEFAULT 26 __bss_start < 63: 00000000004004e6 68 FUNC GLOBAL DEFAULT 14 main < 64: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses < 65: 0000000000600910 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__ < 66: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable < 67: 0000000000400390 0 FUNC GLOBAL DEFAULT 11 _init
サイズは明らかに減っているし,.symtab
シンボル情報が消されているようだ.しかし,関数名は消えない.
なんでだろうと思って,知り合いに聞いてみたらあっさり答えが返ってきた.
それによると,execve
などのライブラリ関数は./id
外の共有ライブラリに実体がある../id
が共有ライブラリの関数を使う場合,プログラム起動時に関数名などのシンボル名を使ってアドレス解決をする.だから,共有ライブラリを使う限りシンボル名が残ってしまう.つまり,静的リンクでコンパイルすればシンボル名を消してもアドレス解決できるようになるということだった.
これがわかれば話は早い.
消し方
$ gcc -static -o id id.c $ strip -strip-all ./id $ r2 -c 'aa;pdf@main' ./id [x] Analyze all flags starting with sym. and entry0 (aa) fcns: 4 xref: 54 sect: 550756 code: 1139 covr: 0 % / (fcn) main 68 | ; var int local_8h @ rbp-0x8 | ; var int local_10h @ rbp-0x10 | ; var int local_18h @ rbp-0x18 | ; var int local_20h @ rbp-0x20 | ; DATA XREF from 0x0040082d (main) | 0x0040092e 55 push rbp | 0x0040092f 4889e5 mov rbp, rsp | 0x00400932 4883ec20 sub rsp, 0x20 | 0x00400936 48c745f00000. mov qword [rbp - local_10h], 0 | 0x0040093e 48c745f80000. mov qword [rbp - local_8h], 0 | 0x00400946 48c745e04477. mov qword [rbp - local_20h], str._bin_id | 0x0040094e 48c745e80000. mov qword [rbp - local_18h], 0 | 0x00400956 488d55f0 lea rdx, [rbp - local_10h] | 0x0040095a 488d45e0 lea rax, [rbp - local_20h] | 0x0040095e 4889c6 mov rsi, rax | 0x00400961 bf44774800 mov edi, str._bin_id ; "/bin/id" @ 0x487744 | 0x00400966 e8450e0300 call fcn.004317b0 ; !!! 消えた !!! | 0x0040096b b800000000 mov eax, 0 | 0x00400970 c9 leave \ 0x00400971 c3 ret
というわけで読めなくなった.
読めないバイナリはこうやって作られるのだろう.
最後に
作成したバイナリは静的リンク時に共有ライブラリに含まれていたのであろう文字列が色々含まれて,本来のユーザ定義文字列が探しにくくなる.これはどうにかできないのだろうか.共有ライブラリを片っ端から--strip-all
すればいいのだろうか.
次は消した情報を復元する方法を調べたい.情報提供募集中.
参考
ありがとう: 知人