swfからabcの切り出し
swfからabcを切り出してディスアセンブルする方法は、OSS で SWF をデコンパイルする(2) - swfassist と abcdump で亜流デコンパイラ - てっく煮ブログ 跡地あたりに書いてある。ただ、AIRが必要だったり、入力ファイル名が固定だったするあたりが嫌だったので、他の方法を試してみた。
サンプルとして使ったのは、以下のようなアクションスクリプト。
package{ import flash.display.*; import flash.text.*; public class Hello extends Sprite { public function Hello(){ trace('Hello'); var text:TextField = new TextField(); text.text = 'Hello world!!'; text.autoSize = TextFieldAutoSize.LEFT; this.addChild(text); } } }
SWFTOOLSによるダンプ
まずは、swftoolsに含まれるswfdumpによるダンプ。
$ swfdump Hello.swf [HEADER] File version: 9 [HEADER] File is zlib compressed. Ratio: 68% [HEADER] File size: 971 (Depacked) [HEADER] Frame rate: 24.000000 [HEADER] Frame count: 1 [HEADER] Movie width: 500.00 [HEADER] Movie height: 375.00 [045] 4 FILEATTRIBUTES [04d] 457 METADATA [041] 4 SCRIPTLIMITS [009] 3 SETBACKGROUNDCOLOR (86/9c/a7) [029] 26 SERIALNUMBER [02b] 6 FRAMELABEL "Hello" ==== Error: Unknown tag:0x052 ==== [052] 412 (null) ==== Error: Unknown tag:0x04c ==== [04c] 10 (null) [001] 0 SHOWFRAME 1 (00:00:00,000) (label "Hello") [000] 0 END
全体の構造が分かるのは便利なんだけれども、一部のタグだけを取り出すのは難しい。--hex
をつければ、中身をダンプできるけど、それでもやっぱり難しい。
$ swfdump --hex Hello.swf [HEADER] File version: 9 [HEADER] File is zlib compressed. Ratio: 68% [HEADER] File size: 971 (Depacked) [HEADER] Frame rate: 24.000000 [HEADER] Frame count: 1 [HEADER] Movie width: 500.00 [HEADER] Movie height: 375.00 ... [02b] 6 FRAMELABEL "Hello" -=> 48 65 6c 6c 6f 00 Hello. ==== Error: Unknown tag:0x052 ==== [052] 412 (null) -=> 01 00 00 00 66 72 61 6d 65 31 00 10 00 2e 00 00 ....frame1...... -=> 00 00 14 00 05 48 65 6c 6c 6f 0d 66 6c 61 73 68 .....Hello.flash -=> 2e 64 69 73 70 6c 61 79 06 53 70 72 69 74 65 05 .display.Sprite. -=> 74 72 61 63 65 0a 66 6c 61 73 68 2e 74 65 78 74 trace.flash.text ....
swfmillで切り出す
$ swfmill swf2xml Hello.swf <?xml version="1.0"?> <swf version="9" compressed="1"> <Header framerate="24" frames="1"> <size> <Rectangle left="0" right="10000" top="0" bottom="7500"/> </size> <tags> ... <UnknownTag id="0x52"> <data>AQAAAGZyYW1lMQAQA...</data> </UnknownTag> ... </tags> </Header> </swf>
なので、swfmillでXMLにしたあと、目的のタグを抜くスクリプトをRubyで書いた。(XPathはすばらしい)
require 'rexml/document' require 'base64' doc = REXML::Document.new ARGF puts Base64.decode64(doc.elements['//UnknownTag[@id="0x52"]/data'].text)
$ swfmill swf2xml Hello.swf | ruby ~/c/code/croquis/extract_abc.rb > a.abc
ただ、このABCにはSWFとしてのヘッダが付加されている。なので、abcdumpに渡す前に、ファイルの先頭から10 00 2E 00
よりも前にあるデータを削除しないといけない。