JavaScriptを全角文字で記述して、究極の難読化をする方法

#JavaScriptを全角文字で書いて更に難読化させる

JavaScriptの一部の文字列、もしくは、命令全体を全角文字で書くことによって、更に難読化させることができます。
セキュリティー上、少しでも見られたくないURLや文字列、命令文を記述したりするのに有効です。

ソースコード上では、ただ全角コードで記述してあるため、可読性が良く、かつ、難読化させる時は、全角文字を強制的に \uxxxxのような文字列にするために、更に難読化させる効果があります。

>現代のブラウザは、JavaScriptはUTF-16で実行されていますが、ツールによって変換を行ないます。
>ソースはUTF-8で記述するようにしてください。


##必要なツール
- 各種packerソフト jsPacker.plがお勧め　http://dean.edwards.name/download/#packer
- yuicompressor
- 以下のソースのツール

```perl:utf16.pl
#!/usr/bin/perl
# Usage perl utf16.pl inputfile outputfile

use utf8;
use Encode;

$in=$ARGV[0];
$out=$ARGV[1];

$buf="";
open(R,"<:utf8",$in)||die "$in not found\n";
#binmode(R,":utf8");
open(W, ">$out")||die "$out can't write\n";
foreach(<R>) {
	for($i=0; $i<length($_); $i++) {
		$c=substr($_, $i, 1);
		if(utf8::is_utf8($c) && (ord($c) > 0x7f)) {
			utf8::encode($c);
			Encode::from_to($c, "utf8", "utf16");
			$c=~s/(.)/unpack('H2',$1)/eg;
			$c=~s/(feff)/\\u/g;

			$buf.=$c;

			$c=substr($_, $i+1, 1);

		} else {
			$buf.=$c;
		}
	}
#	print W "\n";
}
$buf=~s/\\u([0-9A-Fa-f][0-9A-Fa-f])(\n)/"\\u$1" . unpack("H2",$2)/ge;

print W $buf;
close(W);
close(R);
```

##難読化方法
Makefile等で

```Makefile:Makefile
perl utf16.pl script.js script.min.js.tmp1
yuicompressor --type js script.min.js.tmp1 > script.min.js.tmp2
perl jsPacker.pl -e62 -q -f -i script.min.js.tmp2 > script.min.js
rm -f script.min.js.tmp1 script.min.js.tmp2
```

##実例として、まず、行ないたいソースです。

###ソース
```JavaScript:step1_src.js
var GLOBAL = (this || 0).self || global;

(function (G, D, W){
	W.onload = function() {
		alert("test");
	}
})(GLOBAL, document, window);
```

###難読化します
```JavaScript:step1_compiled.js
eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36);};;if(!''.replace(/^/,String)){while(c--)d[c.toString(a)]=k[c]||c.toString(a);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('e 1=(d||0).9||8;(2(b,c,a){a.7=2(){6("5")}})(1,4,3);',15,15,'|GLOBAL|function|window|document|test|alert|onload|global|self||||this|var'.split('|'),0,{}))
```

alert、test共に文字列がソースに存在します。

##次に、「test」の文字だけ、更に難読化します

###ソース
```JavaScript:step2_src.js
var GLOBAL = (this || 0).self || global;

(function (G, D, W){
	W.onload = function() {
		alert(zenhan("ｔｅｓｔ"));
	};
	var zenhan=function(str) {
		var h = '';
		str.split('').forEach(function (s) {
			h += String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
		});
		return h;
	};

})(GLOBAL, document, window);
```

###難読化します
```JavaScript:step2_compiled.js
eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36);};;if(!''.replace(/^/,String)){while(c--)d[c.toString(a)]=k[c]||c.toString(a);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('2 3=(r||0).q||p;(1(b,c,a){a.o=1(){n(d("\\4\\m\\l\\4"))};2 d=1(f){2 e="";f.k("").j(1(g){e+=i.h(g.9(0)-8)});7 e}})(3,6,5);',28,28,'|function|var|GLOBAL|uff54|window|document|return|65248|charCodeAt||||||||fromCharCode|String|forEach|split|uff53|uff45|alert|onload|global|self|this'.split('|'),0,{}))
```

testの文字列がわかりづらくなりました。

##alert("test")自体をすべて難読化する
evalを使うことで、すべて全角文字でJavaScriptを書くことができます。

```JavaScript:step3_src.js
var GLOBAL = (this || 0).self || global;

(function (G, D, W){
	W.onload = function() {
		eval(zenhan("ａｌｅｒｔ（’ｔｅｓｔ’）；"));
	};
	var zenhan=function(str) {
		var h = '';
		str.split('').forEach(function (s) {
			h += String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
		});
		return h;
	};

})(GLOBAL, document, window);
```

```JavaScript:step3_compiled.js
eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36);};;if(!''.replace(/^/,String)){while(c--)d[c.toString(a)]=k[c]||c.toString(a);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('2 4=(y||0).x||w;(1(v,u,9){9.t=1(){r(6("\\q\\p\\8\\o\\3\\n\\7\\3\\8\\m\\3\\7\\l\\k"))};2 6=1(5){2 h="";5.j("").i(1(s){h+=g.f(s.e(0)-d)});c h}})(4,b,a);',35,35,'|function|var|uff54|GLOBAL|str|zenhan|u2019|uff45|W|window|document|return|65248|charCodeAt|fromCharCode|String||forEach|split|uff1b|uff09|uff53|uff08|uff52|uff4c|uff41|eval||onload|D|G|global|self|this'.split('|'),0,{}))
```
alert、testともにわかりづらくなりました。

##function zenhanの注意
- 強制的にコードを引き算するため、半角文字が含んでいるとうまく動作しません。
- 全角文字に存在して、半角文字に存在する文字列を含めることはできません。例：「あいうえお」

##最後に
- あくまで難読化であって、何らかの方法で復号することはできます。（筆者は既に確認済です）
- 難読化を行うことによって、パフォーマンスが落ちたり、動作しなくなったりする可能性があります。よくデバッグを行ないながら行いましょう。