弾号解析してみた
2009年4月27日 01:31最近構文解析で遊んでるからなのか反射的にお気楽ハックしちゃった。
404 Blog Not Found:news - 上に中国のソース行動強制開示あり、下に対策あり
ガクガクブルブル?
正直 Perl がなんであんなコードを実行しちゃうのか分かりません!
皮肉に皮肉を重ね合わせた皮肉
まずは話の流れから解説しとく。
中国、ITソースコード強制開示強行へ…国際問題化の懸念 : 経済ニュース : マネー・経済 : YOMIURI ONLINE(読売新聞)
制度は、中国で生産・販売する外国製の情報技術(IT)製品について、製品を制御するソフトウエアの設計図である「ソースコード」の開示をメーカーに強制するものだ。中国当局の職員が日本を訪れ製品をチェックする手続きも含まれる。拒否すれば、その製品の現地生産・販売や対中輸出ができなくなる。
チェックされるソースコードを次の三行にしたらどうなるか:
#!/usr/bin/perl
use LWP::Simple;
eval get('http://colabv6.dan.co.jp/zh-cn/nihao.pl');
コードの内容を説明します。
一行目は Perl で実行するというもの。
二行目は HTTP でインターネット上の情報を取得する為の簡略化したモジュールを使うという宣言。三行目にある get() という関数などが使えるようになる。
三行目は eval という perl の関数で get() により取得したコードを実行するというもの。
つまり、中国当局の職員によるチェックに提出するソースコードが上記の三行で、開示したくないソースコードはインターネット上の別のところから持ってくるという方法により今回の強制開示を免れようというもの。
これが、一つ目の皮肉。
しかし、この方法だとインターネット上のソースコードが誰でも見ることができてしまう。そこで、ソースコードの解読を困難にしようとした。
次のとても単純なコードを例に見てみる:
print "Hello, world!\n"
このコードは perl で Hello, world! と出力する。
404 Blog Not Found:news - 上に中国のソース行動強制開示あり、下に対策あり
カスタマイズ用のAPIも以下にご用意いたしました。どうぞご利用ください
この API を利用して先ほどのコードを変換するとこうなる:
''=~('('.'?'.'{'.('`'|'%').('['^'-').('`'|'!').('`'|',').('"').(
'['^'+').('['^')').('`'|')').('`'|'.').('['^'/').('{'^'[').'\\'.
'"'.('`'^'(').('`'|'%').('`'|',').('`'|',').('`'|'/').','.("\{"^
'[').('['^',').('`'|'/').('['^')').('`'|',').('`'|'$').'!'.'\\'.
'\\'.('`'|'.').'\\'.'"'.('!'^'+').'"'.'}'.')');$:='.'^'~';$~='@'
perl が変態言語だと言う人がいるのは知っていたけど、本当に変態だったなんて思わなかった。
このコードが実際に実行できてしまいます:
これ、Acme::EyeDrops - Perlにおけるビジュアル・プログラミング(Visual Programming)というもの。
弾さんがフローチャートがダメな3つの理由でも触れて(なぜかコメント荒れて)いたけど、簡単に説明すると、プログラムをテキストで書いていくのではなく、視覚的に図などを使って作るらしい。
Acme::EyeDrops のモジュール自体が本来のビジュアルプログラミングに対する皮肉っぽいけどね。
これが、二つ目の皮肉。
どこが皮肉かってのはビジュアルプログラミングを知らなかった人には実感がないと思う。私も今回知ったのでビジュアルプログラミングに対して思うところはないのだけれど「ビジュアル言語のすすめ」を読んでなんとなく確執みたいながあるのだなと分かった。
(PDFです!)ビジュアル言語のすすめ
おまけ: 判定! ビジュアル言語を使うべきか?
泣きながらテキスト言語を使う
404 Blog Not Found:理系バカよりなのには訳がある - 書評 - 理系バカと文系バカ
文系と理系という分け方の耐えられない軽さに関しては、本blogでもさんざん書いてきた。
実は他にもビジュアル系ってのがあるらしい。
つまり、二つ目の皮肉はインターネット上にあるソースコードを暗号化しようと考えた、けど、難読という意味では perl のビジュアルプログラミングのコードがあったので、ビジュアルプログラミングも合わせて皮肉ってるのね。
あーもう。解りにくい!
Perl のビジュアルプログラミングをお気楽ハックする
perl はあのヘンテコなコードでもちゃんと解析できてるけど、そこが不思議で仕方がなかった。
だからハックする!
次の print 関数で 1 と表示するだけのコードがある:
print 1
これを弾号化API(仮)を使って変換すると次のようになる:
''=~('('.'?'.'{'.('`'|'%').('['^'-').('`'|'!').('`'|',').('"').(
'['^'+').('['^')').('`'|')').('`'|'.').('['^'/').('{'^'[').('^'^
('`'|'/')).('!'^'+').'"'.'}'.')');$:='.'^'~';$~='@'|'(';$^="\)";
このコードを dangou.txt として保存して perl のワンライナーで -MO=Deparse を使う:
$ perl -MO=Deparse ./dangou.txt
'' =~ /(?{eval"print 1\n"})/;
$: = 'P';
$~ = 'h';
$^ = ')';
./tes.txt syntax OK
実は自力でも解析してました:
#!/usr/bin/perl
'' # '' 正規表現のマッチを試す対象です
=~ # =~ 前の対象に次の正規表現を実行します
( # / 正規表現の開始
'(' . # ( 正規表現における構文開始の意味
'?' . # ? perl 埋め込みコード構文の意味
'{' . # { perl のコード(お楽しみ)開始
( '`' | '%' ) . # e なぜ?
( '[' ^ '-' ) . # v なぜ?
( '`' | '!' ) . # a なぜ?
( '`' | ',' ) . # l なぜ?
( '"' ) . # " なぜ?
( '[' ^ '+' ) . # p なぜ?
( '[' ^ ')' ) . # r なぜ?
( '`' | ')' ) . # i なぜ?
( '`' | '.' ) . # n なぜ?
( '[' ^ '/' ) . # t なぜ?
( '{' ^ '[' ) . # なぜ?
( '^' ^ ( '`' | '/' ) ) . # 1 なぜ?
( '!' ^ '+' ) . # \n なぜ?
'"' . # " なぜ?
'}' . # } perl のコード終了
')' # ( 正規表現における構文終了の意味
) # / 正規表現の終了区切り
; # ; 一行目の式の終わり
$: = '.' ^ '~' ; # $: の変数に何入れてるの? なぜ?
$~ = '@' | '(' ; # $~ の変数に何入れてるの? なぜ?
$^ = "\)" ; # $^ の変数に何入れてるの? なぜ?
とりあえずここまでハックした。正規表現内の埋め込みコード内にある eval で実行しているってのは解ったけど、その中のコードを生成する過程が理解できない。
今まで見たことのない ^ や | といったトークンが使われている。
これなに?
$ perl -e " print '[' ^ '-' "
v
なんでこれで v が出力できるのかな。
足し算の + とか、掛け算の * のように、文字と文字を掛け合わせて別の文字にしてる?
はぁ、休日これで潰れたよ。
でも新しい発見があってすごく楽しかった!
