以前の投稿で、window
オブジェクトと'SCgohm'
という文字列があれば
(_,)=>!-[]
などのいくつかの文字だけを使ってJavaScriptを難読化できそうみたいな話をしたんですが、
よく考えると文字列は'CogS'
だけで済みそうと気づいたので
とりあえずHelloWorldを難読化してみます。
使う文字は少し変わって(_,)=>!+[]
です。
目標は次の関数と同じ仕事をするものです。
function helloWorld(){
console.log('Hello, World!');
}
実行するとコンソールにHello, World!
と表示するプログラムですね。
1.下準備
まずはじめに、やんごとなき理由から、関数の定義を関数式に置き直します。
const helloWorld = function(){
console.log('Hello, World!');
};
続いて、この関数式を返す関数を即時実行して代入するスタイルに変更します。
const helloWorld = (function(){
return function(){
console.log('Hello, World!');
};
})();
なんでこんなことをしたかというと、
'(_,)=>!-[]'
という文字だけで記述する部分を限定するためです。
この即時間数の中だけ'(_,)=>!-[]'
という文字のみで記述するのを目的とします。
1.1. window
と'CogS'
の準備
window
と'CogS'
を使うたびにこれらの文字を記述していては意味がないので、
_
という文字だけを使ってこれらにアクセスできるように、
const helloWorld = (function(_,__){
return function(){
console.log('Hello, World!');
}
})(window,'CogS');
てな感じで即時関数の引数に入れてしまいましょう。
これで即時関数の中でwindow
と'CogS'
を自由に使えるようになりました。
ただ、このままではあまりにも分かりにくくなるので、
一旦は原型を止めた変数名に変えておきましょう。
const helloWorld = (function(w,cogs){
return function(){
console.log('Hello, World!');
}
})(window,'CogS');
1.2. 変数置き場の準備
HelloWorldくらいなら変数を置いておく場所がなくても書けるんですが、
同じ記述が何度も出てきてしまうので、
変数入れる場所として配列を用意してあげましょう。
const helloWorld = (function(w,cogs){
v = [];
return function(){
console.log('Hello, World!');
}
})(window,'CogS');
もちろんこのv
という文字は、あとで___
などに置き直します。
const
やlet
やvar
と書けないので宣言なしで書いてしまいましたが、
このままだとグローバル的な変数のv
に配列が入ってしまいます。
このスクリプトより後に読み込まれたスクリプトで、
undefined
がほしくてwindow.v
にアクセスする人がいたら困りますし、
これより前に読み込まれたスクリプトの先頭に
無情にも'use strict'
と書かれていればそもそも動かなくなります。
なのでこいつは、即時関数の引数とみなしてあげましょう。
const helloWorld = (function(w,cogs,v){
v = [];
return function(){
console.log('Hello, World!');
}
})(window,'CogS');
これで他人の心配をしなくて済むようになりました。
2. 関数名の文字列化
まずは関数名やオブジェクト名を直接書かなくていいように文字列にしましょう。
console
オブジェクトは実はwindow.console
オブジェクトで、
window
オブジェクトのプロパティとしてアクセスできます。
そして、プロパティには.
でつなげる以外にも、window['console']
という書き方があります。
console.log
についても同様にconsole['log']
として、こいつらを組み合わせると、
const helloWorld = (function(w,cogs,v){
v = [];
return function(){
w['console']['log']('Hello, World!');
}
})(window,'CogS');
という風になり、console
やlog
と直接記述せずにconsole.log
を呼べるようになりました。
あとは'console'
,'log'
,'Hello, World!'
という文字列を用意してやるだけです。
イメージとしては
const helloWorld = (function(w,cogs,v){
v = [
'console',
'log',
'Hello, World!'
];
return function(){
w[v[0]][v[1]](v[2]);
}
})(window,'CogS');
こんな感じですね。
3. 文字の準備
3.1. String.fromCharCode
がほしい
さて、文字列を使わずに文字列を定義するのはどうすればいいでしょうか。
パッと思いつきそうなのは、String.fromCharCode
です。
こいつがいれば、数字さえ用意できればJavaScriptで扱えるどんな文字でも手に入れられるはずです。
数字の入手方法はあとで考えるとして、まずはString.fromCharCode
を呼ぶ方法を考えましょう。
まずは、先程と同じように、オブジェクトや関数を文字列に置き直すと、
String.fromCharCode
と書くべきところを
w['String']['fromCharCode']
と書けば済むようになります。
ではこの文字列をどうやって用意すればいいでしょうか。
とりあえずここでcogs
に入っている'CogS'
を利用してみましょう。
w[cogs[3]+'trin'+cogs[2]]['fr'+cogs[1]+'m'+cogs[0]+'har'+cogs[0]+cogs[1]+'de']
なんのこっちゃわからないかもしれませんが、
単に'String'
,'fromCharCode'
の中にある'C'
,'o'
,'g'
,'S'
を、
それぞれcogs[0]
,cogs[1]
,cogs[2]
,cogs[3]
で置き換えただけです。
難読化としてはこのままでもそれなりな気がしますが、
目的は難読化ではないので残っている文字が問題です。
小文字の't'
,'r'
,'i'
,'n'
,'g'
,'f'
,'m'
,'h'
,'a'
,'d'
,'e'
,が足りません。
実はこれらの一部は後述する方法で手に入るのですが、
それでも'g'
,'m'
,'h'
は(僕の知る限り)手に入れられません。
別の方法を考える必要があります。
3.2. 小文字がほしい
こうなってくるとどんな小文字でも返してくれる関数がほしくなります。
そんな都合のいい関数があるでしょうか。
あります。
この事実に気づいてなかったので、以前の投稿では'SCgohm'
という文字が欲しかったのです。
例えば'console'
という文字列がほしかったら、次のように書きましょう。
27612545666..toString(36)
知ってる人でないと意味が分からないかもしれません。
亜種として、次の2文を見てください。
0xABADFACE.toString(16)
2880305870..toString(16)
これらはどちらも'abadface'
という文字列を返します。
1文目は簡単ですね。16進数でABADFACE
となる数字を16進数で書いたものです。
2文目の2880305870
という10進数の数字は、16進数でABADFACE
となるので同じ結果が帰ってくるというわけです。
こっそり悪口を仕込みたい場合に、1文目のように書くとすぐバレますが、
2文目のように書けばすぐにはバレないでしょう1。
原理はこれと同じです。
よく使われるr進数は2進数、8進数、10進数、16進数くらいのものですが、
JavaScriptでは2進数から36進数まで使えます。
アラビア数字は10個しかシンボルがないので、
残った26個のシンボルとしてアルファベットの小文字が使われます。
16進数と同じように、a
は10
を、b
は11
を、というのを、
そのまま続けてz
まで行くと、これは35
を表しています。
最初の記述に戻って、
27612545666..toString(36)
ですが、これは36進数でconsole
と表される数27612545666
を36進表記で書いたものなので、
'console'
という文字列が返ってくるのでした。
ちなみに、'console'
には28
を表現するシンボルであるs
より後の文字が含まれていないので、
7647118590..toString(29)
と書いても'console'
が返ってきます。
この辺は好みで使い分けてください。
Number.MAX_SAFE_INTEGER
を超えなければ大丈夫でしょう。
3.3. toString
がほしい
それではString.fromCharCode
を記述するために、
まずは'tring'
という文字列を用意しましょう。
次のように書けば'tring'
が返ってきます。
49992748..toString(36)
そういえば使える文字は'(_,)=>!-[]'
だけだったので、ピリオドを使わずに、
(49992748)['toString'](36)
と書き直します。
ここで使われている'toString'
という文字列を作るには、
cogs
を使っても、't'
,'r'
,'i'
,'n'
が足りません。
これを用意する方法を考えてみましょう。
3.3.1. 't'
がほしい
t
で始まる単語で、JavaScriptを使っているとたまに使うことになるかもしれないものがあります。
それはtrue
です。
true.toString()
とすれば、文字列'true'
が手に入るので、その0番目の要素を取り出せば't'
という文字が作れます。
toString
のためにtoString
を使うと堂々巡りになってしまうため、
実際には別の方法でtrue
を文字列にします。
JavaScriptには、数字でないものを足そうとすると、
文字列の結合とみなして勝手にtoString
してくれたりする機能があります。
例えば、
'' + true
とすれば、'true'
が返ってきます。
この機能は別に文字列で始める必要があるわけではないようで、
[] + true
としても、[].toString()
とtrue.toString()
を結合して'true'
を返してくれます2。
ここで、trueをどうやって用意するかですが、
みんな大好き!+[]
を使えば手に入ります。
+[]
が0
と評価され、それをブール値とみなして論理反転してtrue
が返ってくるという仕組みです。
これらをまとめると、次のようにすれば文字't'
が手に入ります。
([]+!+[])[+[]]
3.3.2. 'r'
,'i'
,'n'
がほしい
ここまでくればあとはやり方は同じです。
'r'
は'true'
に含まれているので、
([]+!+[])[+!+[]]
として1番目の要素をとってくれば済みます。
'i'
,'n'
ですが、これらはundefined
に含まれているので、
([]+[][+[]])[5]
([]+[][+[]])[+!+[]]
とすることで手に入ります。
ここで、'i'
の方には5
という少し大きな数字があります。
!+[]+!+[]+!+[]+!+[]+!+[]
としてもいいのですが、次のように書くと少しスマートです。
([![]]+[][+[]])[[+!+[]]+(+[])]
これは何をしているのかというと、
'false'
と'undefined'
を結合して'falseundefined'
という文字列を作り、
その10番目の要素である'i'
にアクセスするのに
'1'
と'0'
を結合してできた'10'
という文字列を使っています。
分解すると次のような感じです。
(
[![]] // [false]
+[][+[]] // + undefined
)[ // falseにundefinedを直接足すとNaNになるので注意
[+!+[]] // [1]
+(+[]) // + 0
] // 当たり前ですがこっちも直接足すと1になります
// 最終的に('false'+'undefined')['1'+'0'] -> 'falseundefined'['10']
3.3.3. みんなの希望toString
これでtoString
を記述するのに必要なパーツが揃いました。
早速書き下してみましょう。
([]+!+[])[+[]]+cogs[+!+[]]+cogs[!+[]+!+[]+!+[]]+([]+!+[])[+[]]+([]+!+[])[+!+[]]+([![]]+[][+[]])[[+!+[]]+(+[])]+([]+[][+[]])[+!+[]]+cogs[!+[]+!+[]]
([]+!+[])[+[]] //t
+cogs[+!+[]] //o
+cogs[!+[]+!+[]+!+[]] //S
+([]+!+[])[+[]] //t
+([]+!+[])[+!+[]] //r
+([![]]+[][+[]])[[+!+[]]+(+[])] //i
+([]+[][+[]])[+!+[]] //n
+cogs[!+[]+!+[]] //g
下のはわかりやすく改行しただけです。
さて、このtoString
ですが何度もお世話になることになるので毎回書いていられません。
変数置き場に置いておきましょう。
const helloWorld = (function(w,cogs,v){
v = [
([]+!+[])[+[]]+cogs[+!+[]]+cogs[!+[]+!+[]+!+[]]+([]+!+[])[+[]]+
([]+!+[])[+!+[]]+([![]]+[][+[]])[[+!+[]]+(+[])]+([]+[][
+[]])[+!+[]]+cogs[!+[]+!+[]]
];
return function(){
w['console']['log']('Hello, World!');
}
})(window,'CogS');
'toString'
を変数置き場の配列の0番目の要素に入れています。
あとあまりにも長いので適当に改行しています。
改行位置は意味のあるまとまり等ではありません。
これで今度から'toString'
がほしい時はv[+[]]
として
v
の0番目の要素にアクセスするだけで済みます。
3.4. 満を辞してString.fromCharCode
toString
がいれば小文字なんか怖くないので、
さっさとString.fromCharCode
も用意してしまいましょう。
cogs[3] //'S'
+(49992748)['toString'](36) //'tring'
(735718)['toString'](36) //'from'
+cogs[0] //'C'
+(22419)['toString'](36) //'har'
+cogs[0] //'C'
+(31586)['toString'](36) //'ode'
さて、ここで大きな整数がたくさん出てきています。
例えば36
は、次のようにすれば得られます。
+( //文字列'36'を数字として評価する
[!+[]+!+[]+!+[]] //'3'
+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]] //+'6'
)
これをすべての数字でいちいち手書きしてたら気が遠くなるので、
整数を(+![])
だけを使った表現に置き換える関数を用意しておきましょう。
const convertNum = n=>'+('+n.toString().replace(/\d/g,d=>{
if(d==='0'){
return "[+[]]+"
}
let str = d==='1'?'[+':'[';
str += [...Array(parseInt(d,10))].map(e=>'!+[]').reduce((a,b)=>a+'+'+b);
str += ']+';
return str;
}).replace(/\+$/,')');
この関数の解説は割愛しますが、これでいちいち手書きで整数を置き換えなくて済みます。
数字ごとに変換するなり、
ソースを読み込んで.replace(/\b\d+\b/g,convertNum)
するなりしましょう。
'String'
と'fromCharCode'
は、それぞれ次のようになります。
/* S */ cogs[!+[]+!+[]+!+[]]
/* tring */ +(+([!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))['toString'](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
/* from */ (+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))['toString'](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
/* C */ +cogs[+[]]
/* har */ +(+([!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))['toString'](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
/* C */ +cogs[+[]]
/* ode */ +(+([!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))['toString'](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
馬鹿馬鹿しいのでもう改行はしていません。
これでやっとString.fromCharCode
を次のように呼べるようになりました。
この中の'toString'
をv[+[]]
で置き換えてやると、次のように書けます。
w[/* String */
cogs[!+[]+!+[]+!+[]]+(+([!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+
!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+
[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]
]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+
[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))[v
[+[]]](([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
][/* fromCharCode */
(+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]
+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[
]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))[v[+[]]](+([!
+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))+cogs[+[]]+
(+([!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[+!+[]]+[!
+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))[v[+[]]](+([!
+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))+cogs[+[]]+
(+([!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[
]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+
!+[]+!+[]]))[v[+[]]](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[
]+!+[]+!+[]]))
]
こいつを変数置き場に突っ込んでおきましょう。
const helloWorld = (function(w,cogs,v){
v = [
([]+!+[])[+[]]+cogs[+!+[]]+cogs[!+[]+!+[]+!+[]]+([]+!+[])[+[]]+
([]+!+[])[+!+[]]+([![]]+[][+[]])[[+!+[]]+(+[])]+([]+[][
+[]])[+!+[]]+cogs[!+[]+!+[]]
];
v[+!+[]] = w[cogs[!+[]+!+[]+!+[]]+(+([!+[]+!+[]+!+[]+!+[]]+[!+[]+!+
[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]
+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!
+[]+!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!
+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!
+[]+!+[]]))[v[+[]]](([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+
!+[]+!+[]]))][(+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]
+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]
+!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[
]+!+[]]))[v[+[]]](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!
+[]+!+[]]))+cogs[+[]]+(+([!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]
+!+[]+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[
]+!+[]]))[v[+[]]](+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!
+[]+!+[]]))+cogs[+[]]+(+([!+[]+!+[]+!+[]]+[+!+[]]+[!+[]+!+[
]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]
+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))[v[+[]]](+([!+[]+!+[]+!+[
]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))];
return function(){
w['console']['log']('Hello, World!');
}
})(window,'CogS');
これで、String.fromCharCode
を呼びたくなったらv[+!+[]]
とだけ書けばよくなりました。
3.5. 禁断の秘術eval
String.fromCharCode
を手に入れたので、
どんな文字でも書けるようになりました。
どんな文字でも書けるということは、つまり
"()=>console.log('Hello, World!')"
という文字列も書けるわけです。
もちろん、
'eval'
なんて文字列はお茶の子さいさいです。
さて、ここで
w['eval']("()=>console.log('Hello, World!')")
は何が返ってくるでしょうか。
実行するとコンソールにHello, World!
と表示するプログラムですね。
目的は達成されました。
次のようにすれば"()=>console.log('Hello, World!')"
が得られます。
[+([!+[]+!+[]+!+[]+!+[]]+[+[]]),+([!+[]+!+[]+!+[]+!+[]]+[+!+[]]),+([!+[
]+!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]]),+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+
[!+[]+!+[]]),+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[
]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+!+[]]+[+!+[]]),+([+!
+[]]+[+!+[]]+[+[]]),+([+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]),+([+!
+[]]+[+!+[]]+[+!+[]]),+([+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+
[]+!+[]]),+([+!+[]]+[+[]]+[+!+[]]),+([!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!
+[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[
]+!+[]]),+([+!+[]]+[+!+[]]+[+!+[]]),+([+!+[]]+[+[]]+[!+[]+!+[]+!+[]]),+
([!+[]+!+[]+!+[]+!+[]]+[+[]]),+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!
+[]+!+[]+!+[]+!+[]+!+[]]),+([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+
!+[]]),+([+!+[]]+[+[]]+[+!+[]]),+([+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+
[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]
+!+[]]),+([+!+[]]+[+!+[]]+[+!+[]]),+([!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!
+[]+!+[]]),+([!+[]+!+[]+!+[]]+[!+[]+!+[]]),+([!+[]+!+[]+!+[]+!+[]+!+[]+
!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+!+[]]
+[+!+[]]),+([+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+[]]+[!+[
]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]),+([+!+[]]+[+[]]+[+[]]),+([!+[]+!
+[]+!+[]]+[!+[]+!+[]+!+[]]),+([!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[
]+!+[]+!+[]+!+[]+!+[]]),+([!+[]+!+[]+!+[]+!+[]]+[+!+[]])]
/* map */[+(([!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[
]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+
[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+)[v[+!+[]]]([!+[]+!+
[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+)]
(_=>v[+!+[]](_))
/* join */[+(([!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]]+[!
+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]]+[!
+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+)[v[+!+[]]]([!+[]+!+[]+!+[
]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+)]
([]+[])
何をしているかというと、
"()=>console.log('Hello, World!')"
のそれぞれの文字コードが入った配列を用意して、
それぞれString.fromCharCode
で文字に変換してjoin
でつなげているだけです。
ちなみに、'eval'
は、
([]+!+[])[!+[]+!+[]+!+[]]
+v[+!+[]](+([+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]))
+([]+![])[+!+[]]
+([]+![])[!+[]+!+[]]
です。
めでたしめでたし。
で終わってもいいんですが、
いろいろと問題があるのでそういうわけにもいきません。
が、長くなってきたせいか、変なコード書いたせいか、
プレビュー画面がおかしくなってきているので、
今日のとこはこのくらいにしておきます。
続きはそのうち書きます。
書きました(2018-10-29 追記)。