読者です 読者をやめる 読者になる 読者になる

日本人にしか読めない難読化ツールつくってみた

はじめに

※ この記事は Tech KAYAC Advent Calendar 2015 10日目の記事になります

初めまして。フロントエンドエンジニアの@butchi_yです。

いやー、SUSHI食べたいですよねー。

たまらなくて今日のランチはお寿司にしました。

つくったもの

のっけから成果物をどうぞ。

Sushify

オンライン寿司難読化ツールです。

(function(win) {
  var hoge = 5;
  var piyo = 3;
  var fuga = 8;
  console.log(hoge, piyo, fuga);
})(window);

こんなコードが

!function(鮨){var 鮭=5,鯛=3,鯖=8;console.log(鮭,鯛,鯖)}(window);

こんな風に変換されます。

このように、変数等の名前に漢字(しかも日本人のソウルフードである寿司ネタ)を用いる処理を行うことによって、 日本人にしか解読できないJavaScriptコードを生成できます。

(日本人でも、漢字検定上級者か寿司湯呑みをマイカップにしている寿司通じゃないと全部は読めないでしょうね。)

制作の目的

変数名に寿司ネタを使うことにピンときたのがきっかけではあるものの、 今回は楽して勉強したいという思いが強かったです。

  • 既存のオープンソースプログラムを使って、最小限のコストでネタツールを制作する
  • Nodeモジュール(npm)の仕組みや動的サイトの構造(Heroku + Node)などを「出来物から」習得する

この2点を重視しました。

当初は「フォークすれば楽してネタライブラリを作れるよ」という主旨の記事を書く想定でいましたが、 ある程度のスキルがないと挫折ポイントだらけなことと、ネタライブラリに改変するためにある程度ソースを熟読する必要があったので、難易度はやや高いです。

でも実際npm登録とHerokuでのデプロイは驚くほど簡単にできたので、 ツール制作を俯瞰するために出来物を使うのは近道となるでしょう。

知っていたこと

  • JavaScriptの基本とマニアックな仕様
  • npmの使い方
  • Gitでの開発

知らなかったこと

  • Nodeモジュールの作り方
  • GitHubリポジトリのフォーク
  • Herokuでのサイト公開

「知っていたこと」があったからこそ全体をイメージできて、 前からやってみたかった「知らなかったこと」に挑戦できました。

技術的解説

難読化とは

ソースコードを人の目で読みにくくする技術です。 Webにおいては、JavaScriptのソースは丸見えなので、 汚いソースを隠蔽するため 技術の流出リスクを減らすためにJavaScriptの動作結果を保持したまま等価な読みづらいコードに変換します。

カヤックではよく「minify」と呼ぶことが多いですが、これは「最小化」という意味でちょっと趣向が違います。 ただ、よくあるminifyツールはちゃんと名前が付いている変数等を1文字のアルファベット等に置き換えたりするため、最小化した結果難読化になっている、というだけで、大抵は難読化が主目的ではないです。

ちなみに変数に漢字を用いるということは、ASCII文字よりもバイト数の多い文字を使うということなので、 圧縮率は低くなり、minifyとしての有用性は減少します。

変数名に使える文字

変数名には実は漢字も使えます。 深追いした結果、どんなUnicode文字でも使えるわけではないということがわかりましたが、漢字ならほぼ例外なく使えるはずです。

たとえばこんなこともできてしまいます。

var π = Math.PI;
var 五 = 5;
var 吾輩は猫である;

参考: Valid JavaScript variable names in ECMAScript 5 ? Mathias Bynens (英語)

また色々調べたら、顔文字の難読化ツールもありました。

KaomojifyJSとかいうUglifyJSの亜種を試してみた - yutaponのブログ

制作過程

既存ツールの調査

まず元となる難読化ツールとして、普段業務でも使っている UglifyJS2 を採用しました。

ただ、これはコマンドラインでしか動作しないので、 オンラインで実行できる方法を探しました。

調べた結果、UglifyJS2をオンラインで実行できるJSCompressというサービスのソース一式がGitHubに公開されていたので、こちらを使わせていただきました。

フォーク

GitHub上でForkボタンを押し、名前を変更します。

fork.png

あとはそのリポジトリをクローンすれば好き勝手できます。

とりあえず動作確認

UglifyJS2

まず最初に

$ npm install

てっきりタスクランナーでソースを結合したりいろいろやってるものと思ってましたが、 コンパイル部分が全くない構成だったので、ソースをいじっても

$ ./bin/uglifyjs hoge.js -c -m

だけですぐに実行できました。 binのコンパイルすら必要ないとはNodeモジュール恐るべし…。

あと、最近社内勉強会で勉強した「テスト」についても、コマンド一発でできるようになっていました。

jscompress.com

$ npm install
$ npm run start

だけでした。

グローバルインストールしたNodeモジュールを使わせるのではなく、 package.jsonのscriptsプロパティにnpm runのコマンドを入れるのが優しいプロジェクトですね。

手を加えたところ

UglifyJS2

ret += String.fromCharCode(chars[num % base]);

でアルファベット生成しているところを寿司配列に置き換え

function is_identifier(name) {
   return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
};

で英数字かどうかチェックしている部分を除外

プログラムとしてはたった2箇所です。 あとはbinの名前をsushifyjsに変えるのとpackage.jsonの書き換え。

jscompress.com

$ npm install sushify-js --save

import UglifyJS from 'sushify-js';

で機能はあっさり差し替わりました。

あとはフロント部分をSushify仕様にして、こっちもpackage.jsonの書き換え

ネタの選定

独自に入手した魚へんの漢字から、メジャーなものを64個に厳選しました。 (元々変数に使える半角文字の総数が64なので) これらをUglifyJS2の変数に格納。

以下おまけですが、Googleヒット数の大きい魚へんの漢字のランキングです。 (一番右の数字がヒット数です。)

人気のネタ64選ベスト5

  • 1位 鮭(さけ) 22900000件
  • 2位 鯛(たい) 20900000件
  • 3位 鯖(さば) 18200000件
  • 4位 鰻(うなぎ) 12300000件
  • 5位 鯉(こい) 10300000件

人気のネタ64選ワースト5

  • 60位 鯥(むつ)76300件
  • 61位 魛(たちうお)68300件
  • 62位 魬(はまち)62800件
  • 63位 魳(かます)61800件
  • 64位 鯎(うぐい)50800件

公開

npmはこのあたり Node.js - 3分でできるnpmモジュール - Qiita

Herokuはこのあたり Heroku へのデプロイ手順 - Qiita

を参考に拍子抜けするぐらいすんなりできました。

完成

butchi/SushifyJS

butchi/sushify-online

https://serene-scrubland-2735.herokuapp.com/

できたー!!

ちなみに、最近開発したサイトをサンプルとしてSushifyしてみましたが、全く問題なく動いてます。 http://butchi.github.io/SushifyJS/sample/

jQueryなんて、こうです!

jquery_sushi.png

みんな各々のソースをSushifyしてみてください♪

※変数名・関数名・プロパティ名に漢字を使うことは問題ないはずではありますが、 開発時の文字化けの危険性等リスクはあるので、自己責任でお願いします!

PR

ネタりか」というアプリをカヤックがお手伝いしました。

こちらもいいネタが揃ってますよ!!!ぜひインストール!

ネタりかアプリ

明日はテクニカルなlaoujiさんです。