SWF Binary Code Golf on FlashLite 1.1 サイボウズ・ラボ株式会社 竹迫 良範 http://labs.cybozu.co.jp/blog/takesako/ 質問 2 Q. この意味が わかる人? ”CWS\006” 正解: “CWS\006” = 43 57 53 06 SWFファイルを16進数でダンプ 000000 000010 000020 000030 000040 000050 000060 000070 000080 000090 00009f 43 10 5c 22 49 d7 b8 95 0e da 57 85 a7 de 06 fd f9 00 4c 85 53 e1 58 4c a9 a4 44 c6 31 ff 06 3f 70 a7 a2 69 5c 30 a0 73 fa 6d 5d 29 8e 72 22 ba 1d a6 00 15 3c 85 00 b3 db 95 45 14 00 0d 41 28 1b 7e 27 6f 2e 0a 00 45 97 84 bf 46 ac 27 7d 2a 78 8b 7a b7 24 f4 b0 b3 fd 39 9c 1b 00 78 dd b8 0d ff a1 ed 5d 37 37 f3 16 14 4e 33 59 0b cf 29 3d 4d 0e ce 8f c7 2a 95 41 d8 48 60 65 8f b5 c0 5a 09 0a 0b a0 6e 09 61 47 f8 6d 2f c2 48 0b 64 97 e0 7d 56 df ff 30 45 af 15 7b d3 c4 8c f2 +00 (3byte) : File magic “FWS” or “CWS” – 圧縮 +04 (1byte) : File version 6 4 SWFファイルフォーマットの仕様書 Adobe Player Licensing から入手可能 http://www.adobe.com/licensing/developer/ メールアドレス(Adobe ID)を登録 ライセンスに同意する必要がある Flash6以降の情報のみしか記載されていない Alexis‘ SWF Reference (お勧め) http://sswf.sourceforge.net/SWFalexref.html Flash6以前の情報についても書いてある Flash 1.0 とか Flash 4.0 (FlashLite 1.1相当) 2001年からの蓄積(これはすごい) 5 Alexis' SWF Reference : : : : http://sswf.sourceforge.net/SWFalexref.html 6 SWF File Header, SWF Tags… struct swf_header { unsigned char unsigned char unsigned long } f_magic[3]; 'FWS' or 'CWS' f_version; f_file_length; struct swf_header_movie { swf_rect unsigned short fixed unsigned short }; f_frame_size; f_frame_rate; f_frame_count; struct swf_csmtextsettings { swf_tag f_tag; /* 74 */ unsigned short f_text_id_ref; unsigned f_use_flag_type : 2; unsigned f_grid_fit : 3; unsigned f_reserved : 3; long float f_thickness; long float f_sharpness; unsigned char f_reserved; }; 7 SWFファイルを DISアセンブル しながら勉強したい… 8 swfdumpコマンドで DISアセンブル SWFTOOLS の swfdump コマンドを使うと SWFファイルの内容をダンプすることができる http://www.swftools.org/documentation.html > swfdump --full FlashProxy.swf [HEADER] [HEADER] [HEADER] [HEADER] [HEADER] [HEADER] [HEADER] [009] [027] [000] [038] File version: 8 File is zlib compressed. Ratio: 63% File size: 796 (Depacked) Frame rate: 20.000000 Frame count: 1 Movie width: 450.00 Movie height: 325.00 3 SETBACKGROUNDCOLOR (ff/ff/ff) 4 DEFINESPRITE defines id 20480 0 END 21 EXPORTASSETS exports 20480 as "__Packages.MTASC" [03b] 643 DOINITACTION adds information to id 20480 ( 206 bytes) action: Constantpool(22 entries) String:"FlashProxy" String:"_global" String:"target" String:"_root" String:"className" String:"dispatch" String:"flash" String:"external" 9 swfdumpは新しいアクションレコードが苦手 ( : 8 bytes) action: unknown[8e] (remainder of 8 bytes:"\0\0\0\2)\0p\0") : アクションレコード[8e]の抽出に失敗 … orz [8e] Declare Function (Flash Version 7 で追加されたバイトコード) 10 Sothink SWF Decompiler (試用期間30日) http://www.sothink.com/product/flashdecompiler/ 11 DISアセンブル結果(Sothink SWF Decompiler) 12 あと CPAN の SWF::File もお勧め dumpswf.plx dumpswf Flash.swf Flash Flash.swf そのものを生成する Perlスクリプト「Flash.pl」を生成 Windows ActivePerl なら ppm install SWF-File ですぐに使えるよ http://www.nmt.ne.jp/~ysas/butaperl/swf/File.sjis.pod.html 13 DISアセンブルまとめ Swftools – swfdump タグやバイトコードのデータ構造を理解できる Flash V6相当のSWFファイルならそこそこいける Sothink SWF Decompiler (試用期間30日) できればフリーのがいいなぁ ぼく ActionScript わからないし(><) SWF::File – dumpswf.plx DISアセンブルした結果が「Perlスクリプト」になる さらにそれを修正してSWFを再生成できる 14 Flasm 知らなかった! (><) こんな便利なものがあったとは・・・ http://flasm.sourceforge.net/ Yossyさん情報より 15 本題 前フリ ここまで 16 世界で一番小さい SWFファイル いったい何バイトになるんだろう? (ActionScript で意味のあるコード) 最小の “Hello world!\n” プログラム Code Golf チャレンジ 57 byte 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 http://namazu.org/~takesako/swf/ c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 hello57.swf traceを使わないパターンなので、開発環境がなくても表示可能 (traceを使ってよければもっと小さくなるかも) 18 hello57.swf コード解説 SWF File magic (4byte) 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 struct swf_header { unsigned char unsigned char unsigned long } 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 f_magic[3]; 'FWS' or 'CWS' f_version; f_file_length; 19 32bit整数(リトルエンディアン) ファイルサイズ情報 (4byte) 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 struct swf_header { unsigned char unsigned char unsigned long } 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 f_magic[3]; 'FWS' or 'CWS' f_version; f_file_length; 57 = 4b 00 00 00 20 swf_header_movie Rect構造体 (可変サイズ) が入っている 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 struct swf_header_movie { swf_rect unsigned short fixed unsigned short }; 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 f_frame_size; f_frame_rate; f_frame_count; 21 これ重要、テストにでます Rect構造体 60 00 3f c0 00 3f c0 をデコード 可変 5bit 12bit 12bit 12bit 12bit Zero padding | ssss sxxx | xxxx xxxx | xXXX XXXX | XXXX Xyyy | yyyy yyyy | yYYY YYYY | YYYY Y000 | | 0110 0000 | 0000 0000 | 0011 1111 | 1100 0000 | 0000 0000 | 0011 1111 | 1100 0000 | | 6 0 | 0 0 | 3 f | c 0 | 0 0 | 3 f | c 0 | f_size = sssss(5bit) = 011000 f_x_min = xxxxxxxxxxxx(12bit) f_x_max = XXXXXXXXXXXX(12bit) f_y_min = yyyyyyyyyyyy(12bit) f_y_max = YYYYYYYYYYYY(12bit) struct swf_rect { char align; unsigned signed twips signed twips signed twips signed twips }; = 12 ※次から符号付整数が12bit(可変)×4個並ぶ = 0 twips = +2040 twips (104px) 2^12 = -2047~+2047 = 0 twips の数値範囲 = +2040 twips (104px) f_size : 5; f_x_min : f_size; f_x_max : f_size; f_y_min : f_size; f_y_max : f_size; 22 swf_header_movie フレームレート(2byte) 例:12.0 frame/秒 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 struct swf_header_movie { swf_rect unsigned short fixed unsigned short }; 8.8bit固定小数点形式 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 f_frame_size; f_frame_rate; f_frame_count; frame rate (例) 12.0 = 00 0c 23 swf_header_movie フレーム総数 (16bit整数) 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 struct swf_header_movie { swf_rect unsigned short fixed unsigned short }; 16bit整数 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 f_frame_size; f_frame_rate; f_frame_count; frame count 通常は自動計算 24 ここまで SWFヘッダ終了! 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 お疲れ様でした 25 SWFファイルの基本構造 図で表すと・・・ SWFヘッダ情報(ファイル先頭) タグ情報(TagID、size) いろいろ タグ情報(TagID、size) の繰り返し ・ ・ ・ ActionScriptのバイトコードも タグ構造体の中に入る タグ情報(TagID、size) END で終了 26 [HEADER] File version: 4 [HEADER] File size: 75 [HEADER] Frame rate: 12.000000 [HEADER] Frame count: 2 [HEADER] Movie width: 102.00 [HEADER] Movie height: 102.00 [009] 3 SETBACKGROUNDCOLOR (33/33/33) [00c] 23 DOACTION ( 18 bytes) action: Push String:"o" String:"Hello world!\n" ( 0 bytes) action: SetVariable ( 0 bytes) action: End [025] 13 DEFINEEDITTEXT defines id 0001 variable "o" [004] 5 PLACEOBJECT places id 0001 at depth 0001 [001] [000] | Matrix | CXForm r g b a | 1.000 0.000 0.00 | mul 1.0 1.0 1.0 1.0 | 0.000 1.000 0.00 | add 0 0 0 0 0 SHOWFRAME 1 (00:00:00,000) 0 END 27 (2) SWFタグ構造体(可変サイズ) 46 0c 00 00 05 57 02 48 4d 01 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 ややこしいことに bit計算しないとタグIDとサイズがわからない! struct swf_tag { unsigned short f_tag_and_size; f_tag = f_tag_and_size >> 6; f_tag_data_size = f_tag_and_size & 0x3F; if(f_tag_data_size == 63) { unsigned long f_tag_data_real_size; 43 02 } ↓ else { f_tag_data_real_size = f_tag_data_size; TagID:09 Size:3 } }; SetBackgroundColor(TagID:09) → RR GG BB (3byte) 28 タグ構造体のヘッダ(2byteの場合) 1. Sizeが62byte以下の場合 t1 t0 0 1 4 s5 s4 0 0 s3 s2 0 0 3 s1 s0 1 1 t9 t8 t7 t6 0 0 0 0 0 t5 t4 t3 t2 0 0 1 0 2 TagID = t0*2^0 + t1*2^1 + t2*2^2 + t3*2^3 + … t9*2^9 = t0*1 +t3*8 = 1 + 8 = 9 Size = s0*2^0 + s1*2^1 + s2*2^2 + s3*2^3 + … t5*2^5 = s0*1 +s1*2 = 1 + 2 = 3 29 タグ構造体のヘッダ(6byteの場合) 2. Sizeが63byte以上の場合 t1 t0 0 0 3 s5 s4 1 1 s3 s2 1 1 f s1 s0 1 1 t9 t8 t7 t6 0 0 0 0 0 t5 t4 t3 t2 0 0 1 1 3 TagID = t0*2^0 + t1*2^1 + t2*2^2 + t3*2^3 + … t9*2^9 = t2*4 +t3*8 = 4 + 8 = 12 Size = 2^0 + 2^1 + 2^2 + 2^3 + 2^4 + 2^5 = 63 (0x3f) ← magic number 本当のSize情報は次の4byte(32bit整数) で表す 422 byte a 6 0 1 0 0 0 0 30 演習問題 たとえば、タグのデータはこんな感じのバイト列 に変換されます 3byteのデータ 442byteのデータ SetBgColor (TagID= 9, Size=3) → 43 02 RR GG BB doAction (TagID=12,Size=422)→ 3f 03 a6 01 00 00 xx PlaceObject (TagID= 4, Size=7) → 07 01 xx xx xx xx xx xx xx … xx PlaceObject2 (TagID=26, Size=8) → 88 06 xx xx xx xx xx xx xx xx ShowFrame (TagID= 1, Size=0) → 40 00 End (TagID= 0, Size=0) → 00 00 ※ size の大きさは TagID の種類やデータのフラグによって異なります(可変長に対応) 31 (3) やっとここで doAction 46 0c 00 00 05 57 02 48 4d 01 TagID [00c] 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 Size 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 17 03 = TagID:12 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 Size:23byte 23 DOACTION ( ( ( 18 bytes) action: Push String:"o" String:"Hello world!\n" 0 bytes) action: SetVariable 0 bytes) action: End __bytecode__(”96120000...”) がここに出現! 32 参考 __bytecode__ について わかりやすい資料 http://www.be-interactive.org/index.php?itemid=235 Powered by yossyさん 33 (4) DefinedEditText 46 0c 00 00 05 57 02 48 4d 01 TagID [025] [004] [001] [000] 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 Size 13 DEFINEEDITTEXT defines id 0001 variable "o" 5 PLACEOBJECT places id 0001 at depth 0001 | Matrix | CXForm r g b | 1.000 0.000 0.00 | mul 1.0 1.0 1.0 | 0.000 1.000 0.00 | add 0 0 0 0 SHOWFRAME 1 (00:00:00,000) 0 END a 1.0 0 34 (5) PlaceObject 46 0c 00 00 05 57 02 48 4d 01 TagID [025] [004] [001] [000] 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 Size 13 DEFINEEDITTEXT defines id 0001 variable "o" 5 PLACEOBJECT places id 0001 at depth 0001 | Matrix | CXForm r g b | 1.000 0.000 0.00 | mul 1.0 1.0 1.0 | 0.000 1.000 0.00 | add 0 0 0 0 SHOWFRAME 1 (00:00:00,000) 0 END a 1.0 0 35 まめ知識:Matrix構造体も可変長 struct swf_matrix { char align; unsigned if(f_has_scale) { unsigned signed fixed signed fixed } unsigned if(f_has_rotate) { unsigned signed fixed signed fixed } unsigned signed signed }; f_has_scale : 1; f_scale_bits : 5; f_scale_x : f_scale_bits; f_scale_y : f_scale_bits; f_has_rotate : 1; f_rotate_bits : 5; f_rotate_skew0 : f_rotate_bits; f_rotate_skew1 : f_rotate_bits; f_translate_bits : 5; f_translate_x : f_rotate_bits; f_translate_y : f_rotate_bits; ここで、f_has_scale=0, f_has_rotate=0 とすれば2byte以上の節約、 TranslateX, TranslateY の数値範囲を小さくすればさらに節約できる 36 (6) ShowFrame 46 0c 00 00 05 57 02 48 4d 01 TagID [025] [004] [001] [000] 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 Size 13 DEFINEEDITTEXT defines id 0001 variable "o" 5 PLACEOBJECT places id 0001 at depth 0001 | Matrix | CXForm r g b | 1.000 0.000 0.00 | mul 1.0 1.0 1.0 | 0.000 1.000 0.00 | add 0 0 0 0 SHOWFRAME 1 (00:00:00,000) 0 END a 1.0 0 37 (7) End 46 0c 00 00 05 57 02 48 4d 01 TagID [025] [004] [001] [000] 53 00 65 09 01 04 43 6c 01 00 4b 02 6c 00 01 00 33 6f 60 00 00 33 20 0a 00 00 33 77 3e 40 60 17 6f 80 00 00 03 72 0a 00 3f 96 6c 3e 00 c0 12 64 80 00 00 21 60 3f 00 0a 08 c0 6f 00 6f 00 00 1d 00 Size 13 DEFINEEDITTEXT defines id 0001 variable "o" 5 PLACEOBJECT places id 0001 at depth 0001 | Matrix | CXForm r g b | 1.000 0.000 0.00 | mul 1.0 1.0 1.0 | 0.000 1.000 0.00 | add 0 0 0 0 SHOWFRAME 1 (00:00:00,000) 0 END a 1.0 0 38 おわり 40 FizzBuzzやってみました おまけ 41 FizzBuzzではじめるABC入門 FizzBuzz Binary Golf on FlashLite1.1/2.0 http://namazu.org/~takesako/swf/ trace使ってないので 携帯でも動くよ FlashLite1.1 で 251 byte まで (Flash4相当…)、 FlashLite2.0 で 159 byte まで削減できました! yossyさんのASバイトコードの話が聞けるっていうので、 予習として SWF Code Golf やってみました。 42 FizzBuzz スタート ベースのActionScriptの部分はこんな感じで。 for (i = 1; i <= 100; i++) { 変数 x に以下の文字列を順に追記する ((i%15)?((i%5)?((i%3)?i:"Fizz"):"Buzz"):"FizzBuzz"); } DefineEditText で 変数 x を関連付け 43 FlashLite について FlashLite は Flash4ベース Flash5 の一部の機能も使える http://m-school.biz/event/files/2006_0602_flash_lite/FlashLite1x20060602.pdf しかし実際どのバイトコードの機能が使えるのか Webの情報からわからない (例)Math.sin は使えるけど、それはコンパイラが四 則演算で近似値を求めるアクションのバイトコード列 に変換してくれるから → ActionScriptの文法的に使える・使えないとは違う 44 FlashLite1.1で動くFlash5のバイトコード 鴨志田さん(サイボウズ・ラボ)調べによる [4D] [4C] [50] [51] [60] [61] [62] [3F] [63] [64] [65] http://labs.cybozu.co.jp/blog/kamoshida/ Swap Duplicate Increment Decrement BitAnd BitOr BitXor Modulo ShiftLeft ShiftRight ShiftRightUnsigned FlashLite1.1 (Flash4相当)で これらのFlash5の命令が使える 残念ながら Modulo などの命令は FlashLite2.0 からサポート 45 46 ASバイトコードをさらに最適化 とりあえず (1) 正解のFizzBuzz文字列をそのまま出力 -> 478 byte (FlashLite1.1) http://namazu.org/~takesako/swf/fizz478.swf http://namazu.org/~takesako/swf/fizz478.txt (2) FizzBuzzを計算しながら出力 -> 251 byte (FlashLite1.1) http://namazu.org/~takesako/swf/fizz251.swf http://namazu.org/~takesako/swf/fizz251.txt (3) FizzBuzzを計算しながら出力 -> 159 byte (FlashLite2.0) http://namazu.org/~takesako/swf/fizz159.swf http://namazu.org/~takesako/swf/fizz159.txt ここまで圧縮できました。 47 バイトコード最適化のテクニック 鴨志田さん情報 まとめpush http://labs.cybozu.co.jp/blog/kamoshida/2007/01/flash_push.html http://labs.cybozu.co.jp/blog/kamoshida/2007/03/flashlite_2.html FlashLiteの剰余計算 http://labs.cybozu.co.jp/blog/kamoshida/2007/01/flashlite_1.html 西尾さんのアイデア 変数の初期化を省略 i=0 の場合は、変数を初期化しなくても i++ で 1 となる 圧縮率を考慮したプログラミング 圧縮率が高くなるよう変数のネーミングを変える 社内でいろいろ教えてもらいました!(><)ノ 48 (例) fizz287.swf → fizz161.swf --- fizz287.flm 287(Flash4圧縮なし) – 161(Flash6圧縮あり) +++ fizz161.flm @@ -1,71 +1,48 @@ -movie 'fizz287.swf' // flash 4, total frames: 1, frame rate: 12 fps, 104x104 px +movie 'fizz161.swf' compressed // flash 6, total frames: 1, frame rate: 12 fps, 104x104 px + - + frame 0 push 'i', '0' setVariable label1: push 'i', 'i' push '100', 'i', 'i', 'i' getVariable increment setVariable push '100', 'i' getVariable oldLessThan not not branchIfTrue label6 push 'x', 'x', 'x' getVariable push 'i' push 'x', 'x' getVariable push 'i' getVariable push + + '15' divide int push '15' multiply subtract modulo branchIfTrue label2 push 'FizzBuzz' branch label5 label2: push 'i' getVariable push 'i' getVariable push '5' divide int push '5' multiply subtract modulo branchIfTrue label3 push 'Buzz' branch label5 = 126 byte の削減 label3: push 'i' getVariable push 'i' getVariable push '3' divide int push '3' multiply subtract + modulo branchIfTrue label4 push 'Fizz' branch label5 label4: push 'i' getVariable label5: concat push ' ' concat setVariable branch label1 label6: end // of frame 0 end 49 SWF Binary Code Golf on FlashLite 1.1 以上、 ご清聴ありがとうございました
© Copyright 2024 ExpyDoc