アセンブラ短歌やってみた。
「アセンブラ短歌」は五・七・五・七・七の三十一バイト(みそひとバイト)から成る機械語コードでプログラムを書いてみるという近未来の文化的趣味であり,近年,国内のハッカー間で密かなブームが起きています.http://kozos.jp/asm-tanka/
はっかーもすなるあせんぶら短歌といふものを、ぼくもしてみんとて、するなり。
大昔に学校でならった古文的な何か*1をインスパイアしつつ、今日はアセンブラ短歌について書いてみました。国内のハッカー間で密かなブームが起きているアセンブラ短歌、ぼくもエンジニアのはしくれとしてやってみたい! と思ったのですが、ぼくのマシン、Windows7なのでちょっとアセンブラ短歌には向いてなさそう…。というわけでAssembler Tanka on Javascriptでやってみました。
ba f8 03 00 00 68 61 6e 6b 61 90 90 68 41 53 4d 54 8b dc b9 08 00 00 00 8a 03 43 ee e2 fa 90
これがデフォルトのアセンブラ短歌です。逆アセンブルしたコードがこちらです。
baf8030000: mov edx, 0x3f8 #5 68616e6b61: push 0x616b6e61 #7 90: nop 90: nop 6841534d54: push 0x544d5341 #5 8bdc: mov ebx, esp #7 b908000000: mov ecx, 0x8 8a03: mov al, [ebx] #7 43: inc ebx ee: out dx, al e2fa: loop 0x18 90: nop
これで8文字出力できています。
しかし無駄が多いですね。まずb908000000: mov ecx, 0x8ってやつをなんとかしましょう。xor ecx, ecxで2バイト、mov cl, 0x08で2バイトの計4バイトに短縮できます。さっそく1バイト確保です。
NG) b908000000: mov ecx, 0x8 OK) 33c9: xor ecx, ecx b10c: mov cl, 0xc
2バイトずつになったので短歌にも組み込みやすくなりました。
あとは先頭のbaf8030000: mov edx, 0x3f8もなんとかしたいですね。できればここに684c6f7665: push 0x65766f4cをいれたいです。これができれば12文字出力できます。ここにpushをいれるとして、movはどこに移動しましょうか…。
さっき2バイトずつに分けた片方、33c9: xor ecx, ecxを連続しているnopにいれれば3バイトは空けられそうです。
684c6f7665: push 0x65766f4c 68616e6b61: push 0x616b6e61 33c9: xor ecx, ecx ■ココにxor ecx, ecxをいれた 6841534d54: push 0x544d5341 8bdc: mov ebx, esp b10c: mov cl, 0xc 90: nop ■この辺りにmov edx, 0x3f8をいれたい 90: nop 90: nop 8a03: mov al, [ebx] 43: inc ebx ee: out dx, al e2fa: loop 0x18 90: nop
あと2バイト、どうしましょうか。
よくみると一番最後にも1バイト余っています。8a03: mov al, [ebx]を8a0424: mov al, [esp]にすれば、8bdc: mov ebx, espの2バイトがなくなり、3+2=5バイトが確保できます。
というわけで、こんな感じになりました。
684c6f7665: push 0x65766f4c #5 68616e6b61: push 0x616b6e61 #7 33c9: xor ecx, ecx 6841534d54: push 0x544d5341 #5 baf8030000: mov edx, 0x3f8 #7 b10c: mov cl, 0xc 8a0424: mov al, [esp] #7 44: inc esp ee: out dx, al e2f9: loop 0x18
マシン語にするとこうですね。
68 4c 6f 76 65 68 61 6e 6b 61 33 c9 68 41 53 4d 54 ba f8 03 00 00 b1 0c 8a 04 24 44 ee e2 f9
というわけでAssembler Tanka on Javascriptでは、12文字出力までやれることが分かりました。頑張ればもっといけるかもしれませんが、今日はこのへんで。ではでは。
出現頻度の高いアセンブラ命令を調べてみる。
x86-64のアセンブラ命令数はすでに1000前後あるみたいです。ただそんな数の命令をいちいち覚えてられないだろうという話で、実際よくみるのはほんの20命令くらい、特別なことをしないならばだいたい100命令くらい覚えていれば問題ないんじゃないの? という感じがします。
「たのしいバイナリの歩き方」の1章でもそんな話題に少し触れています。
まぁそもそも使用しているプログラミング言語の予約語だって、全部覚えてから使い始めるわけじゃないですし。でも、じゃあどの命令を覚えておけばいいんだろう、という疑問が。
そこで、適当なプログラムを集めて逆アセンブルし、出現するアセンブラ命令をカウントしていけばいいんじゃないかと。たくさん出現するアセンブラ命令ほど覚えておいた方がよい、ほとんど出てこないものはとりあえずスルーしておこう、みたいな。
ではさっそく。まずC:\Program Files以下にあるEXEファイルを集めて、テキストセクション(.text)を逆アセンブル。その結果から命令(opecode)だけをカウントしていく。C:\Program Files以下にあるEXEファイルはひとそれぞれだと思いますが、ぼくの環境の結果はこんな感じでした。
01. mov 382077 11. ret 17117 21. popa 3850 02. push 294472 12. or 15490 22. shl 3826 03. call 141420 13. dec 12280 23. outsb 3801 04. add 113244 14. movzx 11270 24. ja 3599 05. int3 84545 15. jc 10458 25. insb 3138 06. cmp 83456 16. retn 10403 26. sbb 3059 07. lea 82858 17. imul 7870 27. jnl 2916 08. pop 72727 18. jnc 7311 28. arpl 2796 09. jz 62306 19. adc 6151 29. sar 2762 0a. test 45390 1a. shr 5231 2a. jg 2354 0b. jmp 44788 1b. jl 4841 2b. jo 2345 0c. jnz 44400 1c. outsv 4832 2c. js 2164 0d. xor 36666 1d. leave 4772 2d. mul 2040 0e. and 28319 1e. jna 4497 2e. neg 2003 0f. sub 24726 1f. nop 4252 2f. jns 1580 10. inc 21494 20. jng 4146 30. cwd 1489
わりと見慣れた命令が並んでるかなーと思います。とくに左側、トップ0x10はとても身近な感じです。
出現した各命令(上位100位まで)のカウント数をグラフにもしてみました。
ごく一部の命令はすごく出現するのに対し、まったく出現しない命令も多いですね。これは100位までを載せているので、だいたい25位以降はあまり出現しない感じです。となると、実際よくみるのは20命令くらいだなーという感覚はなんとなく当たってたのかも。
個人的な印象としてはadd命令が少し多い気がしました。これは0x00スタートの命令なので、ゼロクリアされた領域を逆アセンブルしてしまい増えているのかなーと。int3も似た印象ですね。nopはもっと多いと思ってましたが、意外と少なかったです。
こんな感じでアセンブラを眺めてみるのも面白いかもしれません。ちなみに5年前にも同じようなことやってますw
「たのしいバイナリの歩き方」という技術書を書かせていただきました。
このたび「たのしいバイナリの歩き方」という技術書を書かせていただきました。
- 作者: 愛甲健二
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
バイナリ系の技術の解説書です、というと少し分野が広すぎるのですが(汗)、自分がセキュリティ技術を中心としたエンジニアなのでソフトウェア解析や脆弱性調査といった方面からバイナリについて触れた本になっています。入門書なので、バイナリに興味がある方、またはバイナリ系の技術は知ってるけどセキュリティについてはよく知らないという方だと楽しんで読んでもらえると思います。
またこれを機にブログをはじめます。
本書では説明しきれなかったものや、より詳しい内容みたいなところをブログにて触れられればと思っています。ぜひよろしくお願いします!