对网页游戏《卧龙吟》的分析3-----预登陆flash的源代码分析

            获取到预登陆flash的ActionScript源代码,在flash builder4.7中调试。

            这里顺便说一下网上说的flash builder4.7破解总是出现奇怪的问题,要么是破解完了就提示许可证过期,要么就是一大堆错误。我现在是采用一个比较2的办法,把系统时间改到2008年,再按照网上的方法改Adobe文件夹里的version值。这样能使用,只是每次都会弹出试用提示。不理佢,我D继续。希望有路过的高手指点一二。

         

            因为在分析这个网页游戏之前对ActionScript一无所知,在调试的时候一边看代码一边搜as教程。所以以下内容仅仅是我个人观点,如果有错漏之处,希望不吝赐教。

 

          

      1 提示找不到ByteArrayAsset ,这个错误需要添加framework   解决办法

             工程--属性--ActionScript构建路径--库路径--添加SWC

           C:\Program Files\Adobe\Adobe Flash Builder 4.7\sdks\4.6.0\frameworks\libs\framework.swc

           


  再修改一些其他的地方,源代码中就没有错误了,可以启动调试,但是可能会提示  未安装所需版本的Adobe flash player 这里需要设置用来调试的flash版本

           2.设置flash调试版本。

           首先在Adobe网站下载flash的调试版本。 在菜单--窗口--首选项--flash builder --调试--独立flash调试版本 里面设置下载到的调试版flash路径。

           我这里是C:\Program Files\Adobe\Adobe Flash Builder 4.7\player\win\11.9\flashplayer_11_sa_debug.exe

         


          这样就可以启动调试了。  Adobe flash builder和VS的调试方式有些类似。 以下是常用的键盘快捷键

         F11启动调试 

         Ctrl+shift+B   打断点  相当于VS的 F9

          F3  找到定义  相当于VS的F12

          F5 调试单步步入  Vs的F11

          F6调试单步步过   VS的F10

          F8 运行到下一个断点  VS的 F5

 

         Preload.swf从Preloader类的构造函数开始启动。Preloader继承自MovieClip类

        设置显示对象的舞台  stage

         

if (stage) 
            {
                stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
                stage.align = flash.display.StageAlign.TOP_LEFT;
                stage.stageFocusRect = false;
            }

 以及一些其他的初始化

本地配置  全局变量里的舞台,根目录  ,资源目录,声音资源目录等。


添加事件侦听

addEventListener(flash.events.Event.ENTER_FRAME, this.Preloader_OnEnterFrame);   //进入主框架

loaderInfo.addEventListener(flash.events.ProgressEvent.PROGRESS, this.Preloader_OnProgress);//用于进度框

this._BgLoader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, this.Bg_OnComplete);//用于加载背景flash


在flash.events.Event.ENTER_FRAME 的事件侦听函数中执行了如下的操作,移除事件侦听,执行启动函数

internal function Preloader_OnEnterFrame(arg1:flash.events.Event):void
        {
            if (currentFrame == totalFrames) 
            {
                removeEventListener(flash.events.Event.ENTER_FRAME, this.Preloader_OnEnterFrame);
                this.Startup();
            }
            return;
        }

在Startup函数主要是一些全局变量的初始化

uqee.core.global.GlobalVariables.Init();

 这个函数有flash.external.ExternalInterface.call不能运行在本地,必须要在网页中运行。所以这里为了调试直接修改为函数调用得到的值。


public static function Init():void
        {
			/*获得 URL 的协议部分 
			var test = window.location.protocol;			
			alert(test); 
			程序返回 http:   */
			//Protocol = flash.external.ExternalInterface.call("function getURL(){return window.location.protocol + \'//\';}");
			Protocol = "http://";
			UrlParams = uqee.core.utils.HtmlUtils.GetParams();
			
			/*可以获得整个URL字符串(在浏览器中就是完整的地址栏)。						
			var test = window.location.href;			
			alert(test);			
			*/
			//var loc1:*=flash.external.ExternalInterface.call("function getURL(){return window.location.href;}");
			var loc1 = "http://www.lequ.com/server/wly/s/328/public/doLogin";
			loc1 = loc1.substr(0, loc1.lastIndexOf("/"));
			GameUrl = loc1;
			return;
			

        }

uqee.core.utils.HtmlUtils.GetParams() 函数

 在htmlutils.as中的GetParams函数有一行

var loc3:*=uqee.core.utils.HtmlUtils.GetCookie("wly_key");     这个函数主要就是获取cookie项目wly_key的值

wly_key这个值可以在fiddle中看到

wly_key=eJw1jEtuxCAQRG%2fTyxEGbMOCK%2bQOpN3MIA%2fY6QZLmdMHL7Ip1UevOp6RYwkgR2ekUPv7DTXj%2fhUL%0aBdhKkCqp1wceBbI8O0kL8Mn1WShvQcHJx5U34mHbKCbjnVJqcQYSljAB08%2fQiDhG7Y1aFmXvWO9%2f%0aqTkl4s%2brQ5MWy%2fnPr9qCEF%2fEAzPajW%2fcqQW9GK88Tj6ZTTvrZmvWGL%2b1t7Oa1jSD8LXT7438AcrJ%0aRmg%3d

这个cookie值是加密了的。在GetParams()函数中会进行还原解密

(loc7 = Base64Decoder.decode(loc4)).uncompress();

        

解压出来的项如下

loc1 Object (@48f0c89)
accid "29306604"
accname "用户名"
dm "snsfun.com"
fcm "1"
isguest ""
nickname ""
provider "0"
req "1"
serverid "328"
source "null"
srvkey "328"
ticket "24a22f181e76201f9bba5b2bc313ed2a"
tid "1397570047"
tstamp "1397570548"
ucparam ""
wlydm "snsfun.com"
zingmeid "0"


回到Preloader.as里面的Startup()函数

添加事件侦听函数

uqee.core.loader.StreamLoader.Instance.addEventListener(uqee.core.events.LoaderEvent.ALL_COMPLETED, this.OnServerLoaded);

再添加一个流请求

req = uqee.core.loader.StreamLoader.Instance.AddRequest(uqee.core.global.GlobalConst.CONFIG_PATH, 
uqee.core.global.GlobalConst.SERVER_CONFIG + uqee.core.global.GlobalVariables.UrlParams.srvkey, 
uqee.core.utils.XmlUtils.GetText("preload.label.srvcfg"), 
"", true, "http://wlys328.snsfun.com/");

req.IsConfusion = false;

这个 IsConfusion 是一个布尔变量,标志要请求的流文件是否加密。FALSE则是不加密。

这个请求是下载一个地址为 http://wlys328.snsfun.com/config/Servers328.dat?t=1220447443987  的文件


这个文件下载完毕会产生uqee.core.events.LoaderEvent.ALL_COMPLETED事件,这个事件关联到了OnServerLoaded()函数,在这个函数中有两个操作

1.启动背景加载

this.Bg_Load();  这个函数判断全局变量uqee.core.global.GlobalVariables.UrlParams.bgoff  是否开启背景,如果开启就加载一个背景flash,这里为了调试我写死为

http://s2.res.uqee.com/resource/Image/zh_CN/i-15.1.swf文件


2添加一个流请求

uqee.core.loader.StreamLoader.Instance.AddRequest( uqee.core.global.GlobalConst.CONFIG_PATH, 
uqee.core.global.GlobalConst.MODULE_RESOURCE_CONFIG + "_" + uqee.core.global.GlobalVariables.Lang, 
uqee.core.utils.XmlUtils.GetText("preload.label.rescfg"), "", true, "http://wlys328.snsfun.com/");

这里没有设置 IsConfusion = false;所以这个文件是加密的。

这个流请求会下载一个地址为http://wlys328.snsfun.com/config/mns_zh_CN.dat?t=1220447444752  的文件




我们可以看到下载的 Servers328.dat 文件是明文的,内容如下

<?xml version="1.0" encoding="utf-8"?>
<ServerList adsrc="1" alias="" bgm="1" buycard="" create="3" defaultServer="dx" font="" fontsize="" guideSkip="" hidePirateBtn="" hideWarBtn="" hidecf="0" hideelite="0" ident="328" lang="zh_CN" loadReport="1" logo="" maxLv="" mix="0" multiByte="1" nameLen="8" nosword="" onlyen="" pay="" rarity="" regentGate="" resetTime="" reward="" ro="" se="1" showTime="" sys="" ujjcheck="" wf="1" wk="" wtpn="">
    <Server host="wlys328.snsfun.com" log="0" name="dx" platform="lequ" port="443,9118" preask="" report="/BattleReport" resHost="s2.res.uqee.com,s1.res.uqee.com"/>
    <GameEvent url="http://wlys328.snsfun.com:9103/player/state"/>
    <Pay url="http://www.lequ.com/pay/index/game/9/s/328"/>
    <Main favname="乐趣网卧龙吟双线328区" favurl="" loginUrl="http://www.lequ.com/wly/" title="乐趣网卧龙吟双线328区" url="" welcome="欢迎来到乐趣网《卧龙吟》双线328区!"/>
    <Indulge postUrl="http://www.lequ.com/api/fcm" url="http://www.lequ.com/user/idcard"/>
    <Bug posturl="" url=""/>
    <NewbieCard url=""/>
    <BBS url=""/>
    <GuestReg url="javascript:top.showReg();"/>
    <QQ gmqq="" payqq=""/>
    <Limit activities="" buildings="" campaignId="" navyTrain="" windows=""/>
    <Bind force="" label="" url=""/>
    <BgList>
        i-15.1.swf
    </BgList>
</ServerList>

这个文件定义了服务器的IP地址和端口列表  战斗报告地址  资源地址   背景flash名称等等非机密的数据


mns_zh_CN.dat则是一个加密的文件。文件长度为5163字节,是加密了的数据文件。在下一篇中解密这个文件


这里先看数据流请求和处理过程。

StreamLoader.as的AddRequest()函数根据传入的路径,服务器配置名,服务器Key,等参数生成请求的地址Url

loc1 uqee.core.entity.StreamRequestInfo (@4b97ee1)

Custom true
FileName "Servers328"
Folder "config/"
IsConfusion true
Label "preload.label.srvcfg"
LabelVersion "preload.label.srvcfg"
NoCache true
ResHost "http://wlys328.snsfun.com/"
_ResHost "http://wlys328.snsfun.com/"
Suffix "Servers328.dat"
Type null
UID null
Url "http://wlys328.snsfun.com/config/Servers328.dat"
_Url "http://wlys328.snsfun.com/config/Servers328.dat"
Version ""


在通过AddRequest函数发送流请求之后,StreamLoader.as 中的Process()函数来加载对应地址的流

protected function LoadStream(arg1:Boolean=false):void
        {
			if (!this._pStreamRequest) 
			{
				return;
			}
			if (this._CloseFile[this._pCurrRequest.FileName]) 
			{
				arg1 = true;
				delete this._CloseFile[this._pCurrRequest.FileName];
			}
			flash.utils.clearTimeout(this._ProcessTimeoutId);
			flash.utils.clearTimeout(this._LoadTimeoutId);
			//this._pStreamRequest.url = this._pCurrRequest.Url + (arg1 ? "?t=" + new Date().getTime() : "");
			//this._pStreamRequest.url = "http://wlys328.snsfun.com/config/Servers328.dat?t=" + (arg1 ? "?t=" + new Date().getTime() : "");
			//this._pStreamRequest.url = "http://wlys328.snsfun.com/config/"+ this._pCurrRequest.FileName + ".dat" + (arg1 ? "?t=" + new Date().getTime() : "");
			this._pStreamRequest.url = this._pCurrRequest.Url + (arg1 ? "?t=" + new Date().getTime() : "");
			this._pStream.load(this._pStreamRequest);
			trace("下载:"+this._pStreamRequest.url);
			return;
        }

因为StreamLoader.as类的构造函数中有如下的代码
public function StreamLoader()
        {
            this._pStreamRequestList = [];
            this._CloseFile = new flash.utils.Dictionary();
            super();
            this._pStreamRequest = new flash.net.URLRequest();
            this._pStream = new flash.net.URLStream();
            this._pStream.addEventListener(flash.events.Event.OPEN, this.Stream_OnOpen);
            this._pStream.addEventListener(flash.events.ProgressEvent.PROGRESS, this.Stream_OnProgress);
            this._pStream.addEventListener(flash.events.Event.COMPLETE, this.Stream_OnComplete);
            this._pStream.addEventListener(flash.events.IOErrorEvent.IO_ERROR, this.Stream_OnError);
            this._pStream.addEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR, this.Stream_OnError);
            this._pStream.addEventListener(flash.events.HTTPStatusEvent.HTTP_STATUS, this.Stream_OnHttpStatus);
            return;
        }


所以在流请求开始后会进入到  Stream_OnOpen()函数中

流请求过程中会进入 Stream_OnProgress()函数

流请求完成会进入 Stream_OnComplete()函数

 protected function Stream_OnComplete(arg1:flash.events.Event):void
        {
            flash.utils.clearTimeout(this._LoadTimeoutId);
            if (this._pCurrRequest) 
            {
                Logger(this._pCurrRequest.LabelVersion + ":下载完成.平均速度:" + this.Speed, -1);
            }
            this.ProcessStreamData();
            return;
        }


这个ProcessStreamData()函数就是处理下载完毕的数据

try 
            {
                err = this.Reader.ReadStream(this._pStream, this._pCurrRequest);
            }
            catch (e:Error)
            {
                Logger("[Read Stream]" + _pCurrRequest.Url + ":" + e.message, -1);
                return;
            }


通过 AbstractXmlDataReader.as 类的ReadStreamd 的实例读入下载完毕的文件流通过判断请求的流的IsConfusion属性,确定流是否加密

if (!arg2.IsConfusion) 
			{
				loc1 = new flash.utils.ByteArray();
				stream.readBytes(loc1, 0, loc2);
				loc1.position = 0;
				this.Store(arg2.FileName, new XML(loc1));
				return null;
			}


这里如果没有加密,就直接读取内容到局部变量 loc1 中

读取完毕就通过XmlDataRead.as类的 Store函数形成一个映射关系

_pXmlMap flash.utils.Dictionary (@2462749)
servers328 XML
<ServerList adsrc="1" alias="" bgm="1" buycard="" create="3" defaultServer="dx" font="" fontsize="" guideSkip="" hidePirateBtn="" hideWarBtn="" hidecf="0" hideelite="0" ident="328" lang="zh_CN" loadReport="1" logo="" maxLv="" mix="0" multiByte="1" nameLen="8" nosword="" onlyen="" pay="" rarity="" regentGate="" resetTime="" reward="" ro="" se="1" showTime="" sys="" ujjcheck="" wf="1" wk="" wtpn=""> ......


映射项名是  server328 

键值就是下载到的流文件xml内容



在下一篇对加密过的xml文件 mns_zh_CN.dat  进行解密分析




/*******************witch_soya****************************************/

/********************2014-4-27***************************************/













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值