アセンブラ短歌やってみた。

アセンブラ短歌」は五・七・五・七・七の三十一バイト(みそひとバイト)から成る機械語コードでプログラムを書いてみるという近未来の文化的趣味であり,近年,国内のハッカー間で密かなブームが起きています.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位まで)のカウント数をグラフにもしてみました。

f:id:b07c00:20130801033953p:plain

 ごく一部の命令はすごく出現するのに対し、まったく出現しない命令も多いですね。これは100位までを載せているので、だいたい25位以降はあまり出現しない感じです。となると、実際よくみるのは20命令くらいだなーという感覚はなんとなく当たってたのかも。

 個人的な印象としてはadd命令が少し多い気がしました。これは0x00スタートの命令なので、ゼロクリアされた領域を逆アセンブルしてしまい増えているのかなーと。int3も似た印象ですね。nopはもっと多いと思ってましたが、意外と少なかったです。

 こんな感じでアセンブラを眺めてみるのも面白いかもしれません。ちなみに5年前にも同じようなことやってますw

「たのしいバイナリの歩き方」という技術書を書かせていただきました。

 このたび「たのしいバイナリの歩き方」という技術書を書かせていただきました。

たのしいバイナリの歩き方

たのしいバイナリの歩き方

 バイナリ系の技術の解説書です、というと少し分野が広すぎるのですが(汗)、自分がセキュリティ技術を中心としたエンジニアなのでソフトウェア解析や脆弱性調査といった方面からバイナリについて触れた本になっています。入門書なので、バイナリに興味がある方、またはバイナリ系の技術は知ってるけどセキュリティについてはよく知らないという方だと楽しんで読んでもらえると思います。

 またこれを機にブログをはじめます。

 本書では説明しきれなかったものや、より詳しい内容みたいなところをブログにて触れられればと思っています。ぜひよろしくお願いします!