Edited at

リバースエンジニアリングは精神と時の部屋で修行するようなものだ

More than 1 year has passed since last update.


まえがき

かれこれ結構昔の話ですが

カクカクしかじかでGoogleの作成したjavascriptファイルを解析した事がありました。

当時のWEBはまだインタラクティブなコンテンツなど皆無だったのですが

先進的なGoogle様は、なんかすごい感じのを作っていて

どこでそれを見たのか、同じことやりたい!と言い出す依頼主

当時プログラム歴半年ほどの自分には実装方法もさっぱり

ようやっとプログラムのイロハが分かってきたかなー程度でした。

わい「いやーさすがに無理でしょう、やりかたも検討つかないし」

依頼主「でもWEBならソースコード見れるし解析すればできるでしょ?」

わい「ほぁ!?」


リバースエンジニアリングとの出会い

まじかよ。。。マジキチやん。。。

と思いつつ、これがリバースエンジニアリングとの出会いでした。

今思えばやる前から無理と決めつけて諦めるプログラマーもやばいと思いますが

当時はそんな感じでした。

ここにはリバースエンジニアリングではどんな事をして何を得たのかなど

半分思い出日記のようなものですが書いていきたいと思います。


第一章 解析環境を作る


まず何からはじめたものか...

わい「とりあえず解析するjavascriptを手に入れるか。。。」

ソースコードがなければ始まらぬ!

該当サイトのHTMLを覗いて、javascriptを読み込んでいる箇所から目的のソースコードを探す。


いきなり嵌る

javascriptが沢山ある。

わい「わいが欲しいのはどれですか?」


  • 自分が欲しいものがわかりません

  • javascriptだけあっても関連するHTMLがなければ処理見てもわからない

実際に動かしながら試せる環境が欲しい事に気づく。

(そもそもどうやって解析するつもりだったんだろう自分。)


とりあえず全部持ってくる

HTMLとその中で読み込まれているCSS,javascript,画像など全て

全て持ってきたらそれがローカルで動作するか確認。

特にWEBサーバーもなく手に入れたHTMLをブラウザにぽいっと

クララが立ったわぁ!!

やや見た目が変なところはあるけど

今回やりたいって部分に関しては動いた!

オフラインでも動くか試す。(パソコンからLANケーブル抜く)

ねぇお爺さん!クララが歩いたの!!

オフライン環境でも動く、よかったー

裏でAjaxなどで通信する事前提となると解析の難易度が変わってくる

とりあえず


  • やりたい事はこのローカル環境に全て詰まっている

  • 動作確認もできる

解析環境の土台はできた


第二章 解析準備

解析する環境はできた、さて次は

解析する範囲を絞りたい。


HTMLの無駄な部分を消し去る

まずはHTMLからヘッダとかフッターとか明らかにここは無関係だろ

っていうところを当てずっぽうに消し去る。

(当時はSVNとかのバージョン管理も使ってなかったのでミスると地獄だった)


CSSの無駄な部分を消し去る

CSSはまぁいいか、見た目だけだし。

スルーすることにする。


いらないJSを消し去る

<script src="~~"></script>で読み込まれているjsをまた当てずっぽうに消す。

そして動くか確認する。

これも単純作業で嵌る事無くすんなり終わった。

結果的に1つのjavascriptだけ残り、こいつだけ解析すればいいと目星がついた。


第三章 解析開始

さて、本格的な解析に入るとする。

ここまで順当だったのもあり意気揚々とjavascriptファイルをエディタで開く。


そこには予想しないコードが

コードが一行しかない。

な、なんだってぇー!!

しかもめちゃくちゃなげぇ。。。

エディターの横スクロールバーがこんなに小さくなったのは生まれた初めてだ。

そう、難読化である

当時は難読化なんてものは知らず

まじかよ、天下のGoogle様は1行で書くのかよ。。。

Googleのスーパープログラマーまじやべぇと驚愕した。

よく見ると変数とかオブジェクトがaとかbとかしかないのね。

普通に考えれば難読化で解析しにくくしているだけなのだが

天下のGoogle、底辺のわいという意識が根付いており

変数は短くすっきり、アルファベット1文字で書くのが正義!!

という誤った認識をし、その1行で書かれたjavascriptを

聖書として崇めた時期もある。


改行、インデント、ブロック!!

さて、俺にはその1行のコードを読むことができない。

なんといっても読みにくすぎるのだ。

よし改行しよう

...

これが非常に難しい。

難読化は可能な限り{}もなければ永遠と処理の終わりが見えてこない謎コード

if (条件) if (条件) 処理1 else (function(){ return a })().method~~~~だったり

funcA() && funcB()のショートサーキットだったり

当時、onclickで「本当に削除しますか?」YES/NO

くらいしかjavascript書いたことのない俺には

このわけのわからないSyntaxのオンパレードに涙が出た。


気が遠くなるようなトライ&エラー

改行するだけなら簡単だと思ったけど、迂闊に改行すると動かなくなる。


  • 見やすくするために改行しては実行確認

  • 見やすくするためにインデントしては実行確認

  • 見やすくするために{}を書いては動作確認

遅々として進まぬ!

蛇の道を歩くような感覚

この作業に終わりなんてあるのか?

そう思いながら作業を続けていくとだんだん構文が分かってくる。

難読化されていてもjavascriptが理解できている以上、理屈で紐解ける。

その日、俺はコンパイラになった。(構文解析しかできないけど)


蛇の道の終着点

改行、インデント、ブロックの日々を続けること約一か月

終わりが見えてきた。

ホップ!ステップ!ジャーンプッ!!

見え始めた終わりに勢いが増す。

ついに終わった(改行しただけだけど)

そして実行確認。

動かない

終わりを感じて急ぎすぎたのかどこかでミスってしまったようだ

ホップ!ステップ!骨折である

この時ほどバージョン管理の重要性を感じた経験を俺は未だにしたことがない。

直近でコピーしておいたファイルからまたやり直す。

この不毛とも思えた作業だが、この作業はjavascriptの構文について

べらぼうに詳しくなった。

もう読めないjavascriptはないと自負できるほど、詳しくなれたと思っている。

(でももう読みたくない)


javascriptの無駄な部分を消す

改行が終わり、1行だったソースが2万行くらいになった。

次は不要と思われる処理をまた当てずっぽうに消していく。

消しては動作確認のトライアンドエラー

こうして本当に知りたいところだけというミニマムな状況を作り出す。


やっと本来の解析を開始

不要な部分を消しても1万行近くのコードが残った。

後はこれを地道に解析していく。

その方法はprintデバッグ

上から順番に逐次変数の中身を確認し

そこからこれは何をやっている処理なのかというのを

1つ1つ調べ、コメントを付けていく。

最初は断片的な理解でこれが何に使われるのかなど見当もつかず

この方法で本当にゴールにたどり着けるのだろうか?

という不安は常にあったものの、最終的には解析でき

もはや忘れかけていた当初の目的である

その当時では珍しいインタラクティブなコンテンツの開発をする事ができた。

この時の達成感はなかなか味わえないのではなかろうかと思う。


おわり

今回はリバースエンジニアリング(今時はコードリーディングかな?)について

思い出にそって具体的に何をして、何がよかったかを語ってみました。

(ただの思い出日記になってしまった感もある)

この地道な作業

正直、1ヵ月かけて改行するなら構文理解してパースする処理を作ったほうがいい。

難読化されたコードを見やすくする便利なツールもあるだろう。

ただこの地道な作業なおかげでプログラムの実力が

短期間で飛躍的に向上したのは間違いない。

Ajaxやクロージャー、プロトタイプ継承などもこの作業から学んだ。

似たようなものを長年開発し続けるような普通の仕事のやり方では

一生得る事ができなかったであろう知識を得る事ができた。

また自分の作ったものではなく、誰かの作ったものを解析する事は

今まで知らなかった技術、テクニック、発想が溢れるほど手に入る

(何を解析するかにもよるが)

世の中にある人気のあるオープンソースなどは一度解析してみたい。

おそらく1ヵ月解析すれば、普通に1年仕事をする以上の知識と実力が身につくだろう。

というか似たような仕事を続けていても知識はだいたいすぐに青天井につき成長が止まる。

この記事のやり方はガチンコで効率も悪く、決して参考にするものではないと思うが

誰かの書いたコードを解析するというのは非常に有益な情報が得られるはずだ。

・・・

ただ1つ難点があるとしたら、えらくしんどいという事。

(なので自分もそんなにやってない)