FFDec というすごいツール
JPEXS Free Flash Decompiler - Opensource SWF decompiler and editor
このソフトを使うと、swfファイルの読み込み、中身の書き換えまで全部できちゃう。それでいて完全無料(オープンソース)。良い時代になったものですね!!
たとえば以下のソースコードを swf ファイルにコンパイルする
package { import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { public function Main() { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point } } }
コンパイルしてできた swf ファイルを FFDec で開くとこのように ソースコード/中間言語を並べて見ることができる
中間言語の説明がすぐに見れてすごい
中間言語の行にカーソルを合わせると、すぐ下に命令の説明が表示されるので、元々知らなくてもある程度はすぐに理解できる。これすごい。
特に、説明文にあるスタックの状況表示が Before → After
の形式で簡潔に書かれているのが非常に良い。
対応するソースコードがすぐに見れてすごい
下の動画のように、ソースコード(or 中間言語)の行を選択すると、対応する中間言語(or ソースコード)に自動的にジャンプする。 ソースコードと中間言語の対応関係がすぐにわかって非常に良い。
その場ですぐに書き換えできてすごい
Edit P-Code ボタンを押すとその場で中間言語を書き換えできる。 Saveするとすぐに左のソースコードにも反映されるので、自分が書いた中間言語が正しいかどうか、すぐにチェックできる。
そして、FFDecのメニューにある Save ボタンで 即座に swfファイルに変更を反映できる。非常に良い
Webブラウザで見ている swf を書き換える
Webページにすでに埋め込んでいる swf ファイルの動作を変更したいこともあるかもしれない。 そういった場合は、その swf ファイルをローカルに保存して、サーバーから来る swf ファイルを置換して差し替えればよい
Windows であれば Fiddler を使うと簡単である。
次のサイトに書いてある Auto responder をつかって特定のswfファイルをローカルで変更したものに差し替えればよい。
中間言語 (P-Code) のリファレンスが見たい
Adobeが提供しているリファレンスがある。なぜPDFファイル…って思ったけど中身はまぁ見やすい。
ActionScript Virtual Machine 2 (AVM2) Overview - Adobe
特定の値をブラウザ側のFlashPlayerに表示させる方法
swfファイルを書き換えながら実行していると、処理のある時点での値を見たい、ということがよくある。 その場合は throw でエラーとして投げる のが簡単で良かった
中間言語の throw の説明は次の通り、スタックの一番上にあるものを throw するだけ、というシンプルな機能。
たとえば、レジスタ1に格納されている値を表示したい場合は、次の2行で済む。すごい楽!
getlocal_1 throw
throw はブラウザのFlashPlayerでも表示される
ブラウザ上でのFlash Playerであっても、デバッグ用のPlayerを入れることでエラーを表示させることができる。
たとえば Chrome だと次のサイトに方法がのっている。
Google Chrome での Flash Player コンテンツデバッガの有効化
throw "hello world!";
とすると、次のようにFlash Player側でエラーダイアログが出る。スタックトレースも出る。すごい!
printデバッグ的な手法として trace() 関数 というのもあるが、この関数はReleaseビルドされていると表示されなかったりするらしく、ブラウザ上で実行しているswfでは見えないこともあったため自分は採用しなかった。
ただ、throw には欠点もあって、プログラムがその時点で完全に止まってしまう ので、該当箇所のデバッグが完了したら throw はちゃんと消しておく。
まとめ
- FFDec すごい
- Fiddler すごい
- 実行中の値を見るには、
throw
を使うと楽