450 likes | 652 Views
SWF Binary Hacks ~ eval のいばら道 ~. Shibuya.JS Technical Talk#3 – Shibuya.es 竹迫 良範 <takesako@shibuya.pl>. はじめに. 謝罪. 今日 Flex2 SDK を インストールしたばかりです 嘘言ってたらごめんなさい. eval の発音について. eval イーヴァル の検索結果 約 4 件 eval イヴァル の検索結果 約 11 件 eval エヴァル の検索結果 約 12 件 eval イーバル の検索結果 約 13 件
E N D
SWF Binary Hacks~ evalのいばら道 ~ Shibuya.JS Technical Talk#3 – Shibuya.es 竹迫 良範 <takesako@shibuya.pl>
謝罪 今日 Flex2 SDK を インストールしたばかりです 嘘言ってたらごめんなさい
eval の発音について • eval イーヴァル の検索結果 約 4件 • eval イヴァル の検索結果 約 11 件 • eval エヴァル の検索結果 約 12 件 • eval イーバル の検索結果 約 13 件 • eval イバル の検索結果 約 13 件 • eval エバル の検索結果 約 28件 ※某G調査機関による調べによる
JavaScriptでフォント名一覧を取得する3つの方法JavaScriptでフォント名一覧を取得する3つの方法 (1) IE限定 (2) LiveConnect (3) Flash利用 TAKESAKO @ Yet another CybozuLabs http://labs.cybozu.co.jp/blog/takesako/2007/03/javascript_getallfonts.html
(1) Dialog Helper Object でフォント名一覧取得 <OBJECT id="dlgHelper" CLASSID="clsid:3050f819-98b5-11cf-bb82-00aa00bdce0b" width="0px" height="0px"> </OBJECT> function getAllFontsByDialogHelper() { var fontslist = ''; try { for (var i = 1; i < dlgHelper.fonts.count; i++) { fontslist += dlgHelper.fonts(i) + '\n'; } } catch(e) { fontslist = 'sorry, could not get fonts list.'; } return fontslist; }
(2) LiveConnect で Javaアプレットを操作 java.awt.GraphicsEnvironment#getAllFonts() function getAllFontsByLiveConnect() { var fontslist = ''; try { var fonts = java.awt.GraphicsEnvironment. getLocalGraphicsEnvironment().getAllFonts(); for (var i = 0; i < fonts.length; i++) { fontslist += fonts[i].getFontName() + '\n'; } } catch(e) { fontslist = 'sorry, could not get fonts list.'; } return fontslist; } • LiveConnect • Netscape3以降の仕様(JavaScript1.1) • Firefox, Opera で動作 • JavaのオブジェクトをJavaScriptから操作
LiveConnectとは? • できること • JavaのオブジェクトをJavaScriptから操作できる • その逆も • 動作環境 • Netscape3以降(JavaScript1.1)の仕様 • Firefox, Opera で動作 • 使用できる条件 • Javaアプレットの実行が許可されているとき
(3) Flash の TextField.getFontList() を利用 var user_fonts = TextField.getFontList(); user_fonts.sort(); getURL('javascript:fontList("‘ + escape(user_fonts) + ‘“)’, '_self'); こんな感じで .asファイルを作って getFontList.swf を作る
でも、いちいち swfファイルを作るの面倒だよなぁ… Flash(ActionScript)で eval 使えたっけ?
SWF Binary Hacks~ evalのいばら道 ~ 斜め下から始める 初めてのFlash
FlashProxy.swf でFlash関数を動的実行 • Collection & Copy - JavaScript用Flashプロキシ、Javascript Sound Kit (id:brazilさん作) • http://d.hatena.ne.jp/brazil/20060726/1153884951 <script type="text/javascript"> Sound.methods = "loadSound start stop getId3 getPan setPan getTransform setTransform getVolume setVolume getDuration setDuration getPosition setPosition getBytesLoaded getBytesTotal".split(" "); function Sound(){ return new FlashProxy("Sound", Sound.methods); } var sound = new Sound(); : みたいな感じで JavaScript から Flash の関数を動的に呼び出すことができる
FlashProxy.as のソースコード(id:brazilさん) import flash.external.ExternalInterface; class FlashProxy{ static var proxy; var target; function FlashProxy() { this.target = new (eval(_root.className)); ExternalInterface.addCallback("dispatch", this, dispatch); ExternalInterface.addCallback("addListener", this, addListener); } function dispatch(prop, args) { var obj = this.target[prop]; if (obj instanceof Function) { return obj.apply(this.target, args); } return obj; } function addListener(event) { this.target[event] = function(){ ExternalInterface.call("FlashProxy.onTrigger", _root.id, event, arguments); } } static function main(mc) { proxy = new FlashProxy(); } }
お、Flashでも evalできる?
なんかFlashにはいろいろ制限があるみたい import flash.external.ExternalInterface; class FlashProxy{ static var proxy; var target; function FlashProxy() { this.target = new (eval(_root.className)); ExternalInterface.addCallback("dispatch", this, dispatch); ExternalInterface.addCallback("addListener", this, addListener); } function dispatch(prop, args) { var obj = this.target[prop]; if (obj instanceof Function) { return obj.apply(this.target, args); } return obj; } function addListener(event) { this.target[event] = function(){ ExternalInterface.call("FlashProxy.onTrigger", _root.id, event, arguments); } } static function main(mc) { proxy = new FlashProxy(); } } この方法だと TextField.getAllFonts() や System.setClipboard みたいな スタティック関数の呼び出しができない (インスタンスを直接生成できない abstract クラスのメソッド)
次のバージョンでは eval 自体廃止されちゃうし
JavaScript から Flash の スタティック関数を evalっぽく実行したい!
例えば Ruby の場合… • 3つのeval関数があるのに! 1. ふつうの eval 2. Object#instance_eval 3. Module#module_eval/class_eval → 空前のメタプログラミング期ブーム
それ Flashy.swf でできるよ
それFlashy.swf 使えばできるよ • JavascriptからFlashの任意の静的関数を呼び出すことができる • <object id=“flashy” data=“Flashy.swf” /> <script language="JavaScript"> var flash = document.getElementById('flashy'); flash.setStatic('flash.system.IME.enabled', true); // IME オン </script> Kazuho@Cybozu Labs: JavaScript から Flash の便利な機能を使う方法 http://labs.cybozu.co.jp/blog/kazuho/archives/2007/03/flashy.php
Flashy.as のソースコード(奥一穂さん) スタティック関数の呼び出しを動的に (インスタンスを直接生成できない abstract クラスのメソッドも呼べる) package { import flash.display.*; import flash.external.ExternalInterface; import flash.utils.getDefinitionByName; public class Flashy extends Sprite { public function Flashy() { ExternalInterface.addCallback("getClass", getClass); ExternalInterface.addCallback("getStatic", getStatic); ExternalInterface.addCallback("setStatic", setStatic); ExternalInterface.addCallback("callStatic", callStatic); } public function getClass(expr:String):Object { return getDefinitionByName(expr); } public function getStatic(expr:String):Object { var m:Object = expr.match(/^(.*)\.(.*?)$/); return this.getClass(m[1])[m[2]]; } public function setStatic(expr:String, value:Object):void { var m:Object = expr.match(/^(.*)\.(.*?)$/); this.getClass(m[1])[m[2]] = value; } public function callStatic(expr:String, args:Array):Object { var m:Object = expr.match(/^(.*)\.(.*?)$/); return this.getClass(m[1])[m[2]].apply(m[1], args); } } }
Flashの関数を呼ぶだけじゃなくASのコードを直接実行してみたいFlashの関数を呼ぶだけじゃなくASのコードを直接実行してみたい eval使えないけど、どうする???
JavaScript で SWF を動的生成すればできるよ! <body><embed width="0px" height="0px" type="application/x-shockwave-flash" flashvars="param=val" src="data:application/x-shockwave-flash;base64, Q1dTCbwDAAB42l1SQW/TMBS23a5uu5VtGqqGEFKlTaqE1CbtDmhVFzG1KxoHiuCCkCbqOm5j5iaR4y7dATEu/AROO8PP4IzEoTvwBzhx4R9wwE7G2mFF8nufv+/zy3uegexPAO58BmAbgu7mPQDA+61vEIC2dEetF91eZTYRftTS2UHVUypsWVYcx/V4rx7IsdXY39+37KbVbNY0oxad+4rMan60U3USgy6LqOSh4oFfMTkZBlN1UK1eu7r0xjScSpFYutRigk2YryKrUW9oI5e2RoGcEOWQMBScEmNnzWqRF9DTmJyx2kiQyGtbC6LRKK4Ecw7dYMgqPcFmlWblcKFP2CnFkN1Foc7SbxKjrtNgYoUycKdU1zTSVol4WWIswulQ8Mhj0pn6p34Qp1csUMOhkhEV3Gb8w8y5IP54SsbMOXqWnN3kSY1EMadp248se89q7qVFGKxt/dfra0SPzwHdjV+ZNuigj5dfXhf1YJOFwKc3KIl+X95/t6nh78Uel5HqcEkFA1/vftCYYY8kmbAG2AB1gC4u/mCgw9Ulainpfd3lUSjIee5lKLli+bEkocdpVBiyMfd7XIiiK0mcSjDzXQPliet2PC7cXH/4llG1llqxMzP79SOzdbUtUVS3r9RNb0ipm8e+YpJQxc9YipRvnXcC/RC5z+RKGZYz26i8CkoYIoyyGK5gmMMQY5jHsIBhEWfXMCphdAej9QxYXhCiQibpAkQQZiHQCcwXMnP7iYayqFBszO3KBfoxPwYn6CkCOrwaZWqwn4V6333+cLfdX8nosJ8DJ/iqj6EWIu2V35nbDAzy9qBgD4r2YNUerNkDpL9X4EGyPEPd2DKXLw/msc7/AuHTEs4="></embed></body>
URI data:スキームでGIF画像を動的に生成 • GIF画像をbase64でエンコード(RFC2397) <img id="icon_here"> <script> var data = ‘data:image/gif;base64,’+ ‘R0lGODlhAAEwAMQAAJ2M5Me98GRK1DoYyYBr3PHv・・・(中略)・・・Pe99XO81Y50auc6PBkZEgpzbmt7HJa2I57CffgnMNqmWHAWNBwwGsKpKsrmJqltOOV69nuYxSkqpoTata18rWtrr1rTIIAQA7'; var icon_elem = document.getElementById("icon_here"); icon_elem.src = data; </script> http://www.kawa.net/works/js/data-scheme/base64.html Firefox, Opera で動作 残念ながら IE では動作しませんが・・・
SWFファイルフォーマットの仕様書 • Adobe Player Licensing から入手可能 • http://www.adobe.com/licensing/developer/ • メールアドレス(Adobe ID)を登録 • ライセンスに同意する必要がある • Flash6以降の情報のみ • Alexis' SWF Reference • http://sswf.sourceforge.net/SWFalexref.html • Flash6以前の情報についても書いてある • 2001年からの蓄積
Alexis' SWF Reference http://sswf.sourceforge.net/SWFalexref.html : : : :
SWF File Header, SWF Tags… struct swf_header { unsigned char f_magic[3]; 'FWS' or 'CWS' unsigned char f_version; unsigned long f_file_length; } struct swf_header_movie { swf_rect f_frame_size; unsigned short fixed f_frame_rate; unsigned short 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; };
SWFファイルを DISアセンブル しながら勉強したい…
swfdumpコマンドで DISアセンブル • SWFTOOLS の swfdump コマンドを使うとSWFファイルの内容をダンプすることができる http://www.swftools.org/documentation.html > swfdump --full FlashProxy.swf [HEADER] File version: 8 [HEADER] File is zlib compressed. Ratio: 63% [HEADER] File size: 796 (Depacked) [HEADER] Frame rate: 20.000000 [HEADER] Frame count: 1 [HEADER] Movie width: 450.00 [HEADER] Movie height: 325.00 [009] 3 SETBACKGROUNDCOLOR (ff/ff/ff) [027] 4 DEFINESPRITE defines id 20480 [000] 0 END [038] 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" String:"ExternalInterface" String:"addCallback" String:"addListener" String:"prototype" String:"Function" String:"apply" String:"event" String:"arguments" String:"id" String:"FlashProxy.onTrigger" String:"call" String:"main" String:"proxy" String:"ASSetPropFlags" ( 2 bytes) action: Push Lookup:0 ("FlashProxy") ( 0 bytes) action: GetVariable ( 0 bytes) action: Not ( 0 bytes) action: Not ( 2 bytes) action: If 418
swfdumpはアクションレコードの抽出が苦手 : ( 8 bytes) action: unknown[8e] (remainder of 8 bytes:"\0\0\0\2)\0p\0") : アクションレコードの抽出に失敗 … orz
SWF::Parser (CPAN) なら・・・ • dumpswf.plx dumpswf.plx Flash.swf > Flash.pl Flash.swf そのものを生成する Perlスクリプト「Flash.pl」を生成 http://www.nmt.ne.jp/~ysas/butaperl/swf/Parser.sjis.pod.html http://search.cpan.org/~YSAS/SWF-File/lib/SWF/Parser.pm
Sothink SWF Decompiler (試用期間30日) http://www.sothink.com/product/flashdecompiler/
しかし、 URIデータスキームに 埋め込みのSWFは Flash Player 9 では動かない…orz Flash Player 8 では動いたのに(><)
Flash上で動く ECMAScriptの処理系があればいいじゃね? Flash Lite 職人である鴨志田さんに聞いてみると そういう処理系があるらしい!
ScriptEngine.swf の特徴 • バイトコードインタプリタ • 一旦スクリプトをバイトコード的なものに変換してから独自VM上で実行 • ECMA-262 3rd Editionにほぼ準拠 • +いくつかの拡張(コルーチンなど) • ActionScript1 的な感じで記述が可能 • 詳しくはWebで • http://www.be-interactive.org/?itemid=6 • http://www.be-interactive.org/?itemid=194
Xelf(ゼルフ)の開発者 –新藤さん(高校3年生) 名前の由来:Flexの逆でxleF http://bcnranking.jp/it_junior/21-00012742.html ゲームを製作しやすくしようプロジェクトの一環として、ECMAScript +αの処理系をFlash(AS)上に実装 期待age
Flashでevalっぽいことをするには? • JavaScript でできないことをプラグインで • Javaアプレット + LiveConnect(IEでは使えない) • Flash 使えばいろいろできる(クロスブラウザ) • JavaScriptからFlashのコードを実行したい • ActionScriptで任意の関数を呼ぶ方法 • FlashProxy.swf (id:brazilさん) • Flashy.swf (奥一穂さん) • SWFファイルの動的生成(URIデータスキーム) • Flash Player 9 以降ではもう使えない技…orz • Flash上で動く ECMAScript+αの処理系あるよ • これ最強! 新藤さんGJ
ご清聴ありがとうございました Special Thanks to: CybozuLabs 奥さん、鴨志田さん