Decompiling the XDComm.swf file: None of the open source Flash decompilers work to decompile Facebook's XDComm Receiver, since it's compiled in Adobe Flex v4 (released apparently in March 2010). You can use the Sothink SWF Decompiler tool, but without paying $70.00, the program doesn't even allow you to export the files to ActionScript. Nonetheless, the unregistered version (as of the 6.00 version) limits you from decrypting more than the first two resources, but there's enough in the tool that allows you to save parts of the code.
Here are flashutils\PostMessage.as and XdComm.as. Hopefully it gives you a better idea of how the Flash cross-domain receiver works.
The files can also be downloaded from here:
http://bit.ly/kAJ7AJ
http://bit.ly/ltGkTF
Apparently the XdComm utilizes the LocalConnection library to communicate with the HTML page. It used the send/receive functionality and the FB.XD._origin variable to determine what the connection name should be used.
In http://hustoknow.blogspot.com/2011/06/how-flash-xdcomm-works-in-facebook.html, we'll walk through in more detail how the Flash XDComm Receiver works with Facebook.
XdComm.as:
package { import flash.display.*; import flash.events.*; import flash.external.*; import flash.net.*; import flash.system.*; import flashutils.*; public class XdComm extends Sprite { private var _cache:SharedObject; private var _cacheContext:String = "unknown"; private var postMessage:PostMessage; private static var requestIdCount:int = 0; public function XdComm() { XdComm.fbTrace("XdComm Initialized", {}); Security.allowDomain("*"); Security.allowInsecureDomain("*"); this.addEventListener(Event.ENTER_FRAME, this.init); return; }// end function private function init(event:Event) : void { XdComm.fbTrace("XdComm.init", {}); this.removeEventListener(Event.ENTER_FRAME, this.init); this.postMessage = new PostMessage(); ExternalInterface.addCallback("sendXdHttpRequest", this.sendXdHttpRequest); ExternalInterface.addCallback("setCache", this.setCache); ExternalInterface.addCallback("getCache", this.getCache); ExternalInterface.addCallback("setCacheContext", this.setCacheContext); ExternalInterface.addCallback("clearAllCache", this.clearAllCache); ExternalInterface.call("FB_OnFlashXdCommReady"); return; }// end function public function sendXdHttpRequest(param1:String, param2:String, param3:String, param4) : int { var loader:URLLoader; var reqId:int; var loaded:Function; var key:String; var value:String; var method:* = param1; var url:* = param2; var requestBody:* = param3; var extraHeaders:* = param4; loaded = function (event:Event) : void { var _loc_2:* = loader.data.toString(); XdComm.fbTrace("Requested completed", {data:_loc_2}); ExternalInterface.call("FB_OnXdHttpResult", reqId, encodeURIComponent(_loc_2)); return; }// end function ; XdComm.fbTrace("SendXdHttpRequest", {method:method, url:url, requestBody:requestBody, extraHeaders:extraHeaders}); if (url.indexOf("https://") != 0 && url.indexOf("http://") != 0) { url = "http://" + url; } var host:* = PostMessage.extractDomain(url); if (host != "api.facebook.com" && host != "graph.facebook.com" && !/^(api|graph)\.[A-Za-z0-9\-\.]+\.facebook\.com$""^(api|graph)\.[A-Za-z0-9\-\.]+\.facebook\.com$/.test(host)) { return 0; } var _loc_6:* = XdComm; var _loc_7:* = XdComm.requestIdCount + 1; _loc_6.requestIdCount = _loc_7; var req:* = new URLRequest(url); loader = new URLLoader(); reqId = XdComm.requestIdCount; req.method = method; req.data = requestBody; if (extraHeaders != null) { var _loc_6:int = 0; var _loc_7:* = extraHeaders; while (_loc_7 in _loc_6) { key = _loc_7[_loc_6]; value = extraHeaders[key]; req.requestHeaders.push(new URLRequestHeader(key, value)); } } loader.addEventListener(Event.COMPLETE, loaded); loader.load(req); return reqId; }// end function private function setCacheContext(param1:String) : void { if (param1 == null) { param1 = "unknown"; } this._cacheContext = param1; return; }// end function private function clearAllCache() : void { this.cache.clear(); this.cache.flush(); return; }// end function private function getCache(param1:String) : String { return this.contextCache[param1]; }// end function private function setCache(param1:String, param2:String) : void { var _loc_3:* = this.contextCache; _loc_3[param1] = param2; this.cache.flush(); return; }// end function private function get cache() : SharedObject { if (this._cache == null) { this._cache = SharedObject.getLocal("cache"); } return this._cache; }// end function private function get contextCache() : Object { var _loc_1:* = this.cache.data[this._cacheContext]; if (_loc_1 == null) { _loc_1 = new Object(); this.cache.data[this._cacheContext] = _loc_1; } return _loc_1; }// end function public static function traceObject(param1:Object, param2:int = 0, param3:String = "") { var _loc_6:* = undefined; var _loc_7:String = null; var _loc_4:String = ""; var _loc_5:int = 0; while (_loc_5 < param2) { _loc_4 = _loc_4 + "\t"; _loc_5++; } for (_loc_6 in param1) { param3 = param3 + (_loc_4 + "[" + _loc_6 + "] => " + param1[_loc_6]); _loc_7 = traceObject(param1[_loc_6], (param2 + 1)); if (_loc_7 != "") { param3 = param3 + (" {\n" + _loc_7 + _loc_4 + "}"); } param3 = param3 + "\n"; } if (param2 == 0) { } else { return param3; } return; }// end function public static function fbTrace(param1:String, param2:Object) : void { traceObject(param2); return; }// end function } }
...and postMessage.as:
package flashutils { import flash.events.*; import flash.external.*; import flash.net.*; import flash.utils.*; public class PostMessage extends Object { private var currentDomain:String; private var callback:String; private var connection:LocalConnection; private var connectionName:String; public function PostMessage() { this.connection = new LocalConnection(); this.connection.client = this; this.connection.connect(Math.random().toString()); ExternalInterface.addCallback("postMessage_init", this.init); ExternalInterface.addCallback("postMessage_send", this.send); return; }// end function public function getCurrentDomain() : String { if (!this.currentDomain) { try { this.currentDomain = ExternalInterface.call("self.document.domain.toString"); this.fbTrace("getCurrentDomain", {currentDomain:this.currentDomain}); } catch (e) { logError("getCurrentDomain error", e); } } return this.currentDomain; }// end function public function onFacebookDomain() : Boolean { return /(^|\.)facebook\.com$""(^|\.)facebook\.com$/.test(this.getCurrentDomain()) || /(^|\.)fbcdn\.net$""(^|\.)fbcdn\.net$/.test(this.getCurrentDomain()); }// end function public function init(param1:String, param2:String) : void { var cb:* = param1; var name:* = param2; this.fbTrace("init", {cb:cb, name:name}); try { if (!this.onFacebookDomain() && PostMessage.extractDomain(name) != this.getCurrentDomain()) { this.logError("init", "name must be a URL on the current domain: " + name); } else { this.callback = cb; if (name == this.connectionName) { return; } this.connectionName = name; name = encodeURIComponent(name); this.connection = new LocalConnection(); this.connection.client = this; this.connection.connect(name); } } catch (e) { logError("init", e.toString()); } return; }// end function public function send(param1:String, param2:String) : void { var msg:* = param1; var name:* = param2; this.fbTrace("send", {name:name, msg:msg}); if (!this.connection) { this.logError("send", "connection has not been initialized."); return; } try { name = encodeURIComponent(name); this.connection.send(name, "recv", msg); } catch (e) { logError("send", e.toString() + ". name: " + name + ", msg: " + msg); } return; }// end function public function recv(param1:String) : void { var deliverMessage:Function; var msg:* = param1; deliverMessage = function (event:TimerEvent) : void { var evt:* = event; try { ExternalInterface.call(callback, encodeURIComponent(msg)); } catch (e) { logError("recv", e.toString()); } return; }// end function ; this.fbTrace("recv", {msg:msg}); var timer:* = new Timer(1, 1); timer.addEventListener(TimerEvent.TIMER, deliverMessage); timer.start(); return; }// end function private function logError(param1:String, param2:Object) : void { XdComm.fbTrace("Error: XdComm.PostMessage." + param1, param2); return; }// end function private function fbTrace(param1:String, param2:Object) : void { XdComm.fbTrace("XdComm.PostMessage." + param1, param2); return; }// end function public static function extractDomain(param1:String) : String { return /^\w+:\/\/([^\/:]*)""^\w+:\/\/([^\/:]*)/.exec(param1)[1]; }// end function } }
Did you know that you can create short links with AdFocus and receive cash from every click on your shortened urls.
ReplyDelete