日本語でプログラミングしたい.

別になでしことかっていう話ではありません.

ポリモーフィックシェルコードってのがあります.それは実行時にコードを生成して,全部生成し終わったらそれに実行を移すようなコードを言います.
それで,ポリモーフィックシェルコードならば以下みたいなコードが書けます.

%8G6H%B0I%-iiii-s55s-DaacP\-AAAA-cv1%-jj0%-fyR4P-_PP%-wV%6-vF%2P-0000-3yyy-XaYYP-txxS-xyyj-zzzHP
-5ll2-%ii%-%gA%P-3333-0oRs-KnVxP-lNN6-o555-D-00P-00tt-nWnn-euEsP-Yqqq-4NZv-8443P-m%1m-w%%p-w5JR

実はこれはhello worldを出力する機械語のコードですが,ASCII文字列として読めるようになってます.
例えば,ASCII以外の入力を拒否するプログラムにexploitを仕掛けるなどの目的で使われるらしいです.

mov命令とかadd命令とかほとんどの機械語はASCIIでは表せません.でも

  1. 任意のバイト列を作り出す(上ではsubを使っている)
  2. それを任意の場所に書き込む(上ではpopとpushを使っている)

という2つの処理(+α)さえ書ければ,任意のコードを任意の場所に生成するコードが作れるわけです.

上のコードはPhiral Research Laboratoriesのdissemblerというプログラムで作りました.

日本語で挑戦

これからアイデアをもらいまして「日本語として読める機械語コード」が書けたら面白いんではないかと少し考えてます.EUCの可読文字のみを使って機械語コードが書けないなぁと.

日本語なんて沢山あるから簡単だろうと思ってたのですが結構難しくてまだ出来てません.もうちょっと挑戦しますがとりあえず調べたとこまでここに書いておきます.

Wikipedia:EUC-JPによるとEUC-JP符号は第1バイトも第2バイトもA1〜FEあたりにおさまってれば良さそうです.*1

ということでオペランドは後から考えるとして,オペコードが上の範囲に収まってるのまとめます.

  • movの一部
  • in/out
  • mul/imul/div/idiv/inc/dec/neg/not/sar/shr/sal/shl/ror/rol/rcr/rcl
  • testの一部
  • jmp/jecxz
  • loop
  • callの一部
  • ret/iret/iretd
  • int
  • enter/leave
  • movs/movsb/movsw/movsd
  • cmps/cmps/cmpsb/cmpsw/cmpsd
  • scas/scasb/scasbw/scasbd
  • lods/lodsb/lodsw/lodsd
  • stos/stosb/stosw/stosd
  • rep ins/rep movs/rep outs/rep lods/rep stos/repe cmps/repe scas/repz cmps/repz scas/repne cmps/repne scas
  • stc/clc/cmc/cld/std
  • sti/cli
  • lds/les
  • fcmove/fcmovne/fcmovb/fcmovbe/fcmovnb/fcmovnbe/fcmovu/fcmovnu
  • fld/fst/fstp/fstp/fild/fist/fistp/fbld/fbstp/fxch/
  • fadd/faddp/fiadd
  • fsub/fsubp/fisub/fsubr/fsburp/fisubr
  • fmul/fmulp/fimul
  • fdiv/fdivp/fidiv/fdivr/fidivr/fidivr
  • fprem/fabs/fchs/frndint/fscale/fsqrt/fxtract
  • fcom/fcomp/fcompp/fucom/fucomp/ficom/ficomp/fcomi/fucomi/fcomip/fucomip/ftst/fxam
  • fsin/fcos/fsincos/fptan/fpatan
  • f2xm1/fyl2x/fyl2xp
  • fld1/fldz/fldpi/fldl2e/fldln2/fldl2t/fldlg2
  • fincstp/fdecstp/ffree/fninit/fnclex/fldcw/fnstcw
  • fldnv/fnstenv/fnsave/fnstsw/fnstsw/fnop

うーん,もの凄く算術命令が充実してますね.
普通の命令はオペコードがみんな1バイトで,2バイト目にレジスタの指定などが入ります.このレジスタの指定の部分でA1〜FEを外れるものが大量にあるのではないかいう感じで,ちょっと難しそうです.

  1. 1バイト命令のcmpsbとかは1バイトコードをずらすのとかに使えそうです.
  2. jmp命令がある!当然アドレスもA1〜FEで書く.環境変数あたりに飛ばせるかも(?)
  3. intがある!と思ったら,システムコールはせいぜい1〜数百までなので2バイト目でアウト.
  4. movが使えたら嬉しいけれども...難しそう

その他

  • 他の文字コードだったらもうちょっと事情は変わってきそう.ちょっと見たところShift-JISだともっと幅が広くて可能性が高い.
  • FPU命令のほとんど全てが1バイト目も2バイト目A1〜FEに収まっているということは意外.
  • FPUってなんか面白い命令がいっぱいある.楽しそう.超越関数命令なんてのがある.

*1:最初はひらがなのみで作れないかと思ったのですが,そうすると奇数番バイトが全てA1なんていう制限がついてとてもじゃないけど無理でした