記号だけのJavaScriptプログラミングの原理 その2

tag

こんにちは。13日から韓国に来ています。はせがわです。

前回、記号だけのJavaScriptの動作原理を紹介したときは、alert を表示する簡単なコードについて解説しました。
今日は、任意のコードを記号だけで記述する方法について説明します。

前回の方法では、"false","true","[object Object]" という文字列から文字を切り出し、文字列 "alert(1)" を Function コンストラクタに渡して無名関数として実行する、という方法を採りました。
ですので、"alert" 以外の文字を自由に作ることができれば、記号だけで任意のコードを書ける、ということになります。
任意の文字を作り出すということで、最初に思いつくのは String.fromCharCode ですが、記号だけで大文字 C を生成するのはなかなか難しいため、もう少し簡単な方法を考えます。
JavaScriptでは、"\101" のような表記で8進数を使って文字列定数を表現することができますので、これを利用して記号と数値だけで任意の文字を作り出します。

functoin (){
    return "\101"; // 文字 'A' を返す関数 
}

関数は、前回同様 Number.constructor.constructor すなわち Function コンストラクタを利用し、また "return" という文字は "true" と "undefined" から生成します。これらを組み合わせることで、任意の文字を生成する関数を記号だけで作ることができました。

(0)[ "constructor" ][ "constructor" ] (
	(!!{}+"")[ 1 ]   + // 'r' : "true"[ 1 ]
	(!!{}+"")[ 3 ]   + // 'e' : "true"[ 3 ]
	(!!{}+"")[ 0 ]   + // 't' : "true"[ 0 ]
	(!!{}+"")[ 2 ]   + // 'u' : "true"[ 0 ]
	(!!{}+"")[ 1 ]   + // 'r' : "true"[ 1 ]
	({}.$+"")[ 1 ]   + // 'n' : "undefined"[ 1 ]
	"\"" +             // '"'
	"\\" +             // '\'
	-~[] +             //  1
	-[] +              //  0
	-~[] +             //  1
	"\""               // '"'
);

8進数で表現できない文字は、\uXXXX という形式で表現します。

$ = +[];          // $ = 0
$ = {
     ___ : $++,  // 0
     __$ : $++,  // 1
     _$_ : $++,  // 2
     _$$ : $++,  // 3
     $__ : $++,  // 4
     $_$ : $++,  // 5
     $$_ : $++,  // 6
     $$$ : $++   // 7
};

(0)[ "constructor" ][ "constructor" ] (
	(!!{}+"")[ 1 ]   + // 'r' : "true"[ 1 ]
	(!!{}+"")[ 3 ]   + // 'e' : "true"[ 3 ]
	(!!{}+"")[ 0 ]   + // 't' : "true"[ 0 ]
	(!!{}+"")[ 2 ]   + // 'u' : "true"[ 0 ]
	(!!{}+"")[ 1 ]   + // 'r' : "true"[ 1 ]
	({}.$+"")[ 1 ]   + // 'n' : "undefined"[ 1 ]
	"\"" +             // '"'
	"\\" +             // '\'
	(!!{}+"")[ 2 ]   + // 'u' : "true"[ 0 ]
	$._$$ +            //  3
	$.___ +            //  0
	$.$__ +            //  4
	$._$_ +            //  2
	"\""			   // '"'
);

このような方法を利用することで、あらゆる任意の JavaScript を記号だけにすることができました。
実際に、jjencode が生成するJavaScriptを読み解くとより理解が深まると思います。