好友
阅读权限10
听众
最后登录1970-1-1
|
远方呢
发表于 2018-9-13 11:38
本帖最后由 远方呢 于 2018-9-27 13:24 编辑
《AMF模块使用教程1―― 完整AMF封包通信的游戏辅助编写》
内容简介:
本教程针对 AMF客户端通信模块.ec 做基础及进阶性的介绍,以及对几个游戏进行破解分析过程,并使用这个模块在易语言环境下编写辅助程序作出详细说明。
第一章 破解一个Flash网页游戏
1.1找个练练手的游戏
《教程1》对于新手,简单一点的,使用完整AMF封包通信的游戏,其他使用ByteArray写对象后再通过TCPIP连接进行AMF编码字节集通信的,或FLEX外部化类编码的游戏将在《教程2》,《教程3》写。
1.2 破解人人网FLASH网页游戏《泡泡海洋》
网址:http://apps.renren.com/paopaohaiyang?origin=3871
介绍:史上鱼种最多最炫的养鱼游戏!捉鱼、养鱼、卖鱼、钓鱼…
即新版的《泡泡鱼》
FLASH网页游戏主程序一般是后缀为:.SWF的文件,我们想破解它就要先找到它。
工具准备:charles3.7_WIN32版本_带破解补丁.rar 破解DoSWF(E源码).zipASV2010 或 硕思闪客精灵(不建议这个,反编译AS3不太好,分解动画除外)UltraEditIPTOOL (层底网截)AMF完整通信字节集解释器 (自己使用AMF模块对应游戏编写)Firefox 火狐浏览器
我的运行环境windows 7sp1 IE9. Firefox v19
1.登录人人网,开启Charles,点进入应用:泡泡海洋
2.进行一两个游戏操作,网截获一些AMF请求信息,点Charles网截程序按钮[Start/Stop Recording] 停止记录。
AMF请求指令 amfService.getUserInfoAMF amfService.getRaytoonVIPAMFamfService.getAlmanacNumDataAMF等等这些是游戏主程序向服务器发出的操作请求指令,这些字符串一般在FLASH游戏主程序.SWF内,我们找到这个.SWF文件,分析这些指令及其参数,编写程序进行一系列指令自动请求发送操作,这样就达到游戏辅助目的,俗称外挂。
3.Charles内,有两个分页:structure和sequence ,玩VC的就知道这是 结构和 列序 的意思。
4.点 sequence列序,查看有没有 .swf 后缀的文件,
找不到!!!!不用心急,Charles也不是万能的,有些在网页JS脚本下的文件请求不一定能截取到。
5.查看返回网页内有没有 .swf 后缀的文件信息, 按 <Ctrl> + F,输入.swf ,注意是: (小写句号swf)
点:Find
出现搜索结果框,并把这个Search Results搜索结果框移开一点不挡着Charles为好各个双击查看这些结果
因为是Request (请求),不是我们想要的 Response(响应返回)网页,所以一样的1~4也不用看了。双击第5个
是我们想要的 Response(响应返回)网页了,看看定位在哪,如果不是可疑的.swf 请求文件,可双击多次这个Search Results搜索结果框的项目,因为网页内可能不只一个.swf字串,双击时可定位到该请求返回的下一个搜索到的字串上。 找到了
复制出来
看看<embed name="forIE" src="http://official.ppyimg.cn/media/swf/v30/gameMain3.swf" width="756" height="640" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" flashVars="skey=2.0f66314f891ff9ac41116b58805453e5.3600.1362121200-451237832&sns=renren&feed_fun=sendFeed&snsid=451237832" allowScriptAccess="always" ></embed> 一个长度宽度width="756" height="640"的FLASH程序,文件名gameMain3.swf够可疑吧。
6.如何把这个FLASH程序保存到电脑上分析把 http://official.ppyimg.cn/media/swf/v30/gameMain3.swf 复制,打开Firefox火狐浏览器(因为火狐浏览器打开纯.swf的链接后可以另存为保存到电脑上,IE就不行了),粘贴到火狐浏览器的地址栏,回车。加载完成后 点菜单栏 [文件] ->[页面另存为]…,
就D:\泡泡海洋 目录吧
7.反编译分析 gameMain3.swf文件:
打开 ASV2010 把 到目录D:\泡泡海洋 把gameMain3.swf 文件拖进去分析,
ASV2010分析方法:
A.修正混淆非字符变量名:转换 非ANSI字符为ANS字符
转换后。
哼哼!!DoSWF加密,难不到我们的,我们继续。
8. 反DoSWF加密:(内存破解方式)
需要工具:SWF to EXE Converter (注意 不支持中文目录路径)破解DoSWF加密工具.exe (破解DoSWF加密工具.e,我编写已经放到群共享里了)因 SWF to EXE Converter,不支持中文目录路径我们就放到目录D:\SWF to EXE Converter上吧,
开始了:A.复制 gameMain3.swf 到目录D:\SWF to EXE ConverteB.运行 sWf2eXe.exeC.Clear InputD.Add a File 选择 gameMain3.swfE.ConvertF.到D:\SWF to EXE Converter\Output 找到 gameMain3.exe 运行G.运行:破解DoSWF加密工具.exeH.点选进程:gameMain3.exe 点按钮:分析保存,保存后可关闭这些程序了I.破解的SWF保存在 破解DoSWF加密工具.exe运行目录下的SWF目录里,这个示例我放到了D:\SWF to EXE Converter\SWF 下,按大小排列这个目录的SWF文件,大的在前。
J.运行 ASV2010 从大到小逐个拖这些SWF到ASV2010分析,忽略错误!点选 Actionscripts 页项查看
就是这个,破解DoSWF成功, 当然不忘了 修正混淆非字符变量名:转换 非ANSI字符为ANS字符
转换后
还记得这里的amfService, this.+.getUserInfoAMF 吗,是上述的请求指令请求服务名啊!! K.保存SWF成果:菜单栏 Files -> Save as… 另存为,gameMain3_V30_CR.swf,因为它的网址及版本路径是http://official.ppyimg.cn/media/swf/v30/gameMain3.swf ,V30版,修定是3,CR代表破解,命名随便吧自己看懂就行了。L.保存TEXT文本成果(用于分析):菜单栏 Files -> Save SWF DATA as Text… 另存为,gameMain3_V30_CR_swfdata.txt,M.破解SWF完成。
1.3 分析人人网FLASH网页游戏《泡泡海洋》,同时使用AMF模块设计辅助程序 1.创建一个分析文件(泡泡海洋分析.txt),分析指令的记录都写在里面.2.如何过滤: 打开charles ,重新进入游戏网页 泡泡海洋 ,找到AMF指令请求的项的网址 双击右边那个网址就可复制的
复制 http://ocean.paopaoyu.cn ,点Charles右边的齿轮按钮
点选:Recording Setings,在弹出 的Recording Setings框里选择第二项:Include, 按 Add ,增加过滤,Protocol:选择HttpHost:粘贴刚才复制的网址 http://ocean.paopaoyu.cn其他不用填写,按OK
打勾是使能过滤,不打勾为不过滤。清空后,刷新一下游戏网页,看看是不是清淅很多了。
设置过滤只显示与服务器AMF通信完成。想全部分析时记得取消打勾哦。
3.分析第一个指令:amfService.getUserInfoAMF A.在Charles里分析AMF参数有点吃力,不能全部复制,我们先弄个带拖放的 AMF完整通信字节集解释器 (自己使用AMF模块对应游戏编写) 代码如下: .版本 2.支持库 edroptarget .程序集 窗口程序集1 .子程序 __启动窗口_创建完毕 拖放对象1.注册拖放控件 (编辑框1.取窗口句柄 ())拖放对象1.接收文件 = 真 .子程序 _拖放对象1_得到文件.参数 接收到的文件路径, 文本型.局部变量 找到位置, 整数型.局部变量 取出长度, 整数型.局部变量 AMF字节集, 字节集.局部变量 完整AMF信息, AMF封装信息.局部变量 信息, 变体型 找到位置 = 寻找文本 (接收到的文件路径, #换行符, , 假).如果 (找到位置 = -1) 取出长度 = 取文本长度 (接收到的文件路径).否则 取出长度 = 找到位置 - 1.如果结束AMF字节集 = 读入文件 (取文本左边 (接收到的文件路径, 取出长度))AMF解码 (AMF字节集, 信息, 完整AMF信息, )编辑框1.内容 = AMF封装信息到文本格式 (完整AMF信息)
B .选择第一个指令,在右边右击,选择Save Request (保存请求)
保存到目录D:\泡泡海洋 里,文件名req,到这个目录,把 req 文件拖到 运行着的AMF完整通信字节集解释器.exe 程序中
解释后是: ---------- AMF封装信息 ----------AMF版本号: 3 信息头 [ ] 信息体 [1].targetURI: "amfService.getUserInfoAMF"信息体 [1].responseURI: "/1"信息体 [1].信息: ["e31a541370ef20317f0a2e13e70bc85e","2.d7d06579f17947eb1136fe50e910472d.3600.1362128400-451237832"]---------- AMF封装信息 结束 ---------- amfService.getUserInfoAMF 指令带有两个参数:参数1:文本型:"e31a541370ef20317f0a2e13e70bc85e"参数2:文本型:"2.d7d06579f17947eb1136fe50e910472d.3600.1362128400-451237832" 这些参数的怎样来的呢,我们去找答案。。。。 C .打开 UltraEdit,把刚才破解的AS3文本文件:gameMain3_V30_CR_swfdata.txt拖到里面,视图着色文件类型选择JAVA 方案,按JAVA指令格式分色显示较为清淅。按 <Ctrl> + F 查找 getUserInfoAMF 在高级里勾选 加亮所有找到的项、勾选 列出包含字串的行,
找到一条代码 public function _P47_():void{ this.hideMouse(); this._P30_(null); var _local1:PendingCall = this.+.getUserInfoAMF(this._P29_{(this._bubbleFish.skey), this._bubbleFish.skey); _local1.responder = new Responder(this._P48_, this.errorBack); } 注:这个ASV2010的修正混淆有点问题了,this.后面的变量字串给修正为+了,Responder给包进去PendingCall了,一个函数里有这样的大括号 { { } 所以可以确定 是 反混淆不太完美造成this._P29_后面多了个左大括号{ , 自己修理一下后 public function _P47_():void{ this.hideMouse(); this._P30_(null); var _local1:PendingCall = this.amfSVR.getUserInfoAMF(this._P29_(this._bubbleFish.skey), this._bubbleFish.skey); _local1.responder = new Responder(this._P48_, this.errorBack); } 即参数1=this._P29_(this._bubbleFish.skey)参数2=this._bubbleFish.skey 全都与这个 this._bubbleFish.skey 相关,那我们先看看这个this._bubbleFish.skey 是什么神物, 慢慢向上找到 变量 _bubbleFish找到 private var _bubbleFish:_P2_;_P2_是什么类呢,得再找这个类 按 <Ctrl> + F 查找 class _P2_找到两个,但我想要的是有类成员 skey 的类,就只有 public class _P2_ extends EventDispatcher { 成员赋值 (有替换过程 全部“ ”换成 “+”) public function set skey(_arg1:String):void{ var _local2:*; var _local3:*; if (_arg1.length != 0){ _local2 = (_arg1.length - 1); this._P239_ = _arg1; _local3 = 0; while (_local3 < _local2) { this._P239_ = this._P239_.replace(" ", "+"); _local3++; }; }; } 取成员值 public function get skey():String{ return (this._P239_); 是在什么地方被赋值呢,我们找 .skey = , 按 <Ctrl> + F 查找 .skey = 找到if (!this._bubbleFish.skey){ if (loaderInfo["@doswf__p"]["bd_sig_session_key"] != null){ this._bubbleFish.skey = ((((loaderInfo["@doswf__p"]["bd_sig_session_key"] + ",") + loaderInfo["@doswf__p"]["bd_sig_user"]) + ",") + loaderInfo["@doswf__p"]["bd_sig_portrait"]); } else { if (loaderInfo["@doswf__p"]["xn_sig_session_key"] != null){ this._bubbleFish.skey = loaderInfo["@doswf__p"]["xn_sig_session_key"]; Profile.text_font = "MS PGothic"; } else {this._bubbleFish.skey = ((loaderInfo["@doswf__p"]["skey"]) || ("skey")); if (!ApplicationDomain.currentDomain.hasDefinition("_P1_")){ return; }; }; }; }; loaderInfo :载入FLASH运行时的参数信息["@doswf__p"] :是DoSWF加壳后的变换 loaderInfo["@doswf__p"]["bd_sig_session_key"]loaderInfo["@doswf__p"]["xn_sig_session_key"]loaderInfo["@doswf__p"]["skey"] 还记得在 第一章 1.2.5 分析网页里的FLASH运行参数吗?就是紫色部分:<embed name="forIE" src="http://official.ppyimg.cn/media/swf/v30/gameMain3.swf" width="756" height="640" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" flashVars="skey=2.0f66314f891ff9ac41116b58805453e5.3600.1362121200-451237832&sns=renren&feed_fun=sendFeed&snsid=451237832" allowScriptAccess="always" ></embed> 所以没有 loaderInfo["@doswf__p"]["bd_sig_session_key"]所以没有 loaderInfo["@doswf__p"]["xn_sig_session_key"]有参数:loaderInfo["@doswf__p"]["skey"] 这个重要参数this._bubbleFish.skey = 2.0f66314f891ff9ac41116b58805453e5.3600.1362121200-451237832没有空格不用替换我们编写挂时可以提取网页中这个参数用作运行 amfService.getUserInfoAMF 指令带有两个参数:参数1:文本型:"e31a541370ef20317f0a2e13e70bc85e"参数2:文本型:"2.d7d06579f17947eb1136fe50e910472d.3600.1362128400-451237832" 参数2找到了还差参数1参数1=this._P29_(this._bubbleFish.skey) 因为:函数是返回文本的 this._P29_, this this 所以在这个找到 getUserInfoAMF 的包内(//& (raytoon.bubblefish.&)) 慢慢向下或向上找 function _P29_ (或鼠标滚动找)
第一个没有参数的,没有返回的,不是第二个参数是整数而不是文本的,没有返回的,不是第三个参数对象而不是文本的,没有返回的,不是第四个参数是可多个变量的数组的,返回字串的,应该是,看看 private function _P29_{(... _args):String{ var _local3:Object; var _local4:Number; var _local5:String; var _local6:String; var _local7:String; var _local8:String; var _local9:String; var _local10:String; var _local2 = ""; for each (_local3 in _args) { if (_local3 != null){ //非空 _local2 = (_local2 + _local3.toString()); //易语言可先转换参数为字串再调用这个函数 } else { _local2 = (_local2 + "null");//空参数用字串null代替 }; };//分拆多个参数,易语言可用多个可空参数代替 _local4 = Math.random(); // 取随机小数 _local5 = _P154_._P236_(_local4.toString()); //MD5函数,结合上面就是随机MD5 _local6 = _local5.substr(0, 8);//取文本中间 _local2 = (_local2 + _local6); _local7 = _P154_._P236_((_local2 + this._bubbleFish._P117_)[0])); // MD5函数 _local8 = _local7.substr(0, 10); _local9 = _local7.substr(10); _local9 = _local9.substr(0, (_local9.length - 8)); _local10 = ((_local8 + _local6) + _local9); return (_local10); } 这是一段加密通信用的掩码生成过程, //注:MD5函数 易语言中称作 取数据摘要//_P154_ ((._P154_)package ( { import flash.utils.*; // flash.utils.* 内部类 import _P61_.*; public class _P154_ { public static var _P24_*:ByteArray; public static function _P236_(_arg1:String):String{ var _local2:ByteArray = new ByteArray(); _local2.writeUTFBytes(_arg1); return (_P164_^(_local2)); }从 function _P164_ 看出是一个FLASH设计系统的MD5生成函数//注:MD5函数 完//从 参数1:文本型:"e31a541370ef20317f0a2e13e70bc85e" 也猜到不少吧 // this._bubbleFish._P117_)[0] 是什么呢因为private var _bubbleFish:_P2_;到_P2_这个类找,按 <Ctrl> + F 查找class _P2_ public class _P2_ extends EventDispatcher {。。。略。。。 public function _P2_(_arg1:SingletonEnforcer){ this._P237_ = new Object(); this._P166_# = new Array(5); this._P238_ = new Object(); this._P117_) = ["happy$newyear", "happy.newyear"]; //密匙1、密匙2 this._P88_& = [0, 0, 0, 0, 0]; super(); } 就是这个值呢!!!!! 我暂时把它称作生成掩码1的: 通信密匙1this._bubbleFish._P117_)[0] = "happy$newyear" 我们编写挂时 这个通信掩码程序改编为易语言程序不难吧!private function _P29_{(... _args):String{ ///加密复杂度低,普通请求加密用private function _P103_(... _args):String{ ///加密复杂度高,捉鱼、收潜艇鱼请求加密用 函数 _P29_ 《掩码生成程序1》 使用 通信密匙1,普通请求加密用函数 _P103_ 《掩码生成程序2》 使用 通信密匙2,捉鱼、收鱼加密用 基本上编写好这两个掩码生成程序,这个游戏辅助就编写好80%了,余下那些只是编写操作请求指令的体力劳动了。易语言版本的 _P29_.版本 2.支持库 dp1 .子程序 getSigOf, 文本型, , 普通操作用.参数 arg1, 文本型, 可空.参数 arg2, 文本型, 可空.参数 arg3, 文本型, 可空.参数 arg4, 文本型, 可空.参数 arg5, 文本型, 可空.参数 arg6, 文本型, 可空.局部变量 arg, 文本型.局部变量 RandomMD5, 文本型.局部变量 a7, 文本型.局部变量 a6, 文本型.局部变量 a8, 文本型.局部变量 a9, 文本型.局部变量 a10, 文本型.局部变量 a5, 文本型 arg = arg1 + arg2 + arg3 + arg4 + arg5 + arg6.如果真 (arg1 = “”) arg1 = “null”.如果真结束RandomMD5 = 取数据摘要 (到字节集 (取现行时间 ()))a6 = 取文本左边 (RandomMD5, 8)a5 = arg + a6 + g_SigCodeKeyArr [1] ' //通信密匙1a7 = 取数据摘要 (到字节集 (a5))a8 = 取文本左边 (a7, 10)a9 = 取文本中间 (a7, 11, 取文本长度 (a7) - 10)a9 = 取文本左边 (a9, 取文本长度 (a9) - 8)a10 = a8 + a6 + a9' 输出调试文本 (a10) 返回 (a10)这个指令请求就分析完了,我们还要看看向服务器请求后返回什么,是玩家游戏内的等级经验ID头像昵称等信息,
把它保存为文件res 并拖到 AMF完整通信字节集解释器 看看
---------- AMF封装信息 ----------AMF版本号: 3 信息头 [ ] 信息体 [1].targetURI: "/1/onResult"信息体 [1].responseURI: "null"信息体 [1].信息: {"user_info":{"tutorial_tempo":11,"fish_food":400,"exp":627,"remain_shock_times":100,"shells":6514,"is_exchanged":false,"pearls":60,"first_login":false,"tempo":2,"max_tanks":3,"first_recharge":true,"almanac_level":2,"avatar":"http://hdn.xnimg.cn/photos/hdn121/20120401/0525/h_head_5d47_5f400003470a2f75.jpg","is_vip":"0","next_exp":750,"sns_id":"451237832","nickname":"韦春花","id":1447395,"has_level_up":false}}---------- AMF封装信息 结束 ---------- JSON的 { }代表Object 即对象数据类型,我们完全可以用模块中的 字典类 在 信息体 [1].信息 这个变体开型变量中 提取这些数据,具体看看游戏辅助的源码。注意那个id ,是玩家在游戏中的id,有部分请求指令需要用到它作参数,如取鱼缸信息,这里先注一下。Sns_id 是窝号,nickname是昵称…不详说了,看看游戏页面对照一下就知道 另:多信息体的请求,可拆分为单个请求如:
可逐个逐个拆分发送,如上述可拆分为请求1 :amfService.getRaytoonVIPAMF 发送
请求2: amfService.getAlmanacNumDataAMF 发送
请求N。。。。 发送N。。。。 作用是一样的4.分析第二个指令:amfService.getMyFishTankListAMF (操作:查询鱼缸列表信息)5.
因为其返回鱼缸ID关联到分析的第三个指令:查看鱼缸里对象信息,所以特找这个指令分析作教程
先看看Charles截取的请求参数
UltralEdit代码分析中查找 getMyFishTankListAMF
找到
public function _P79_(_arg1:uint){
this.hideMouse();
var _local2:PendingCall = this.+.getMyFishTankListAMF(this._P29_{(_arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1);
_local2.responder = new Responder(this._P80_, this.errorBack);
}
修正{后
public function _P79_(_arg1:uint){
this.hideMouse();
var _local2:PendingCall = this.+.getMyFishTankListAMF(this._P29_(_arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1);
_local2.responder = new Responder(this._P80_, this.errorBack);
}
参数1:this._P29_( _arg1, this._bubbleFish.skey) //通信掩码生成,早OK了参数2:this._bubbleFish.skey // skey,早OK了参数3:arg1 // 整数 _arg1:uint ,要去找它出处
找它出处就要看看谁调用函数 _P79_了,// _P79_(_arg1:uint)UltralEdit中按 <Ctrl> + F 查找 _P79_
1和2 一样的,任一个也行了,3是原自己这里,不用了就选择第1行 双击代码
&.getInstance()._P79_(this._hostId);
再找_hostId =
找到太多了,有点头痛是吧,不怕还有捷径,因为是 this,等于说明这个 _hostId 变量就在这个包内,鼠标慢慢向上滚动,往回看,找包的开头处
鼠标点一下开头处,我们要从这里开始向下逐个找_hostId =或按 <Ctrl> + F 输入_hostId = ,取消 列出包含字符串的行的勾。找到 public function MyHome(){ this._hostId = _P2_.getInstance()._P55_; super(); if (_P2_.getInstance()._P273_ != 0){this._hostId = _P2_.getInstance()._P273_; };_P2_是什么呢,分析第一个指令时找过了,是一个类,想再找?按 <Ctrl> + F 查找 class _P2_getInstance() 是取实例的意思,说明: _P2_ 是一个单实例类,全局只得唯一一个实例存在,我感觉它是用来保存游戏玩家主要信息的主类,一会就知道了。。到这个_P2_类的代码处: public class _P2_ extends EventDispatcher { private static var _instance:_P2_;。。。略。。。 public function _P2_(_arg1:SingletonEnforcer){ //百度一下,唯一一个实例存在类 this._P237_ = new Object(); this._P166_# = new Array(5); this._P238_ = new Object(); this._P117_) = ["happy$newyear", "happy.newyear"]; this._P88_& = [0, 0, 0, 0, 0]; super(); } public static function getInstance():_P2_{ if (_P2_._instance == null){ _P2_._instance = new _P2_(new SingletonEnforcer()); }; return (_P2_._instance); }。。。略。。。 public function set_P55_(_arg1:uint):void{ this._P240_ = _arg1; } public function get_P55_():uint{ return (this._P240_);赋值取值函数我们主要看看是谁给这个类实例的 _P55_赋值就知道什么是 _hostId了按 <Ctrl> + F 查找 ._P55_ = 找到 private function getUserInforByEvent(_arg1:BubbleFishCommunicationEvent):void{ var _local4:int; var _local5:MovieClip; var _local6:*; var _local7:HeadPanel; var _local8:BubbleFishButton; var _local9:BubbleFishButton; var _local10:FriendBt; var _local11:BubbleFishButton; var _local12:SnsIdMenu; var _local13:*; var _local14:MovieClip; var _local15:BubbleFishButton; var _local16:BubbleFishButton; var _local17:BubbleFishButton; var _local18:Timer; var _local19:Date; var _local20:AdPopWindow; var _local2:Object = _arg1.args; if (this._header == null){ this._bubbleFish.owner_level = _local2["almanac_level"]; this._bubbleFish._P266_ = _local2["nickname"]; this._bubbleFish._P141_ = _local2["sns_id"]; this._bubbleFish.owner_food = _local2["fish_food"]; this._bubbleFish.[_P110_ = _local2["tutorial_tempo"];this._bubbleFish._P55_ = _local2["id"]; //原形毕露了吧 this._bubbleFish._P271_ = _local2["max_tanks"]; this._bubbleFish.owner_shell = _local2["shells"]; this._bubbleFish.(_P77_ = _local2["remain_shock_times"]; this._bubbleFish.owner_pearl = _local2["pearls"]; this._bubbleFish._P276_ = _local2["is_vip"]; this._bubbleFish.]_P272_ = _local2["is_fan"]; this._bubbleFish.>_P131_ = _local2["power"]; this._bubbleFish._P235_ = _local2["exp"]; this._bubbleFish.&& = _local2["next_exp"]; this._bubbleFish._P242_ = _local2["is_exchanged"]; this._bubbleFish._P251_ = _local2["is_vip"]; this._bubbleFish.qqVipLevel = _local2["vip_level"]; this._bubbleFish._P252_ = _local2["is_year_vip"]; this._bubbleFish.)_P161_ = _local2["is_vip_gift"]; this._bubbleFish._P261_ = _local2["avatar"]; this._bubbleFish._P145_( = _local2["first_recharge"]; _firstLogin = _local2["first_login"]; this._bubbleFish._P81_) = _local2["first_login"]; _local4 = 9; if (_local2["tempo"] < _local4){ this._bubbleFish._P268_ = _local2["tempo"]; } else { this._bubbleFish._P268_ = _local4; }; this._bubbleFish._P276_ = _local2["is_vip"]; this._header = new Header(); _head_layer.addChild(this._header); _P195_.=_P65_ = this._header; if (Profile.version != _P6_._P8_)){ if (ExternalInterface.call("getCookie", this._bubbleFish._P141_.toString()) == "0"){ BubbleFishSound.getInstance().restoration(0); }; }; };\\\\\\\\\\\\\\\\\\\\\\\找找 这个事件响应函数 getUserInforByEvent\\\\\\\\\\\\\\\\\\\\\\\\ private function interfaceMcPutToStage(){//事件接口函数 &.getInstance().addEventListener(BubbleFishCommunicationEvent.COM_GET_USER, this.getUserInforByEvent); //加入监听事件getUserInforByEvent &.getInstance().addEventListener(BubbleFishCommunicationEvent.NEW_ALMANCE, this.newAlmanacFish);//加入监听事件newAlmanacFish &.getInstance().addEventListener(BubbleFishCommunicationEvent.COM_GET_OTHER_USER, this.getOtherInfoByEvent);//加入监听事件getOtherInfoByEvent &.getInstance()._P47_();//调用 _P47_ ,_P47_还记得吗,是我们第一个指令getUserInforAMF所在函数请求返回时产生COM_GET_USER事件,有级升时产生NEW_ALMANCE事件。。。\\\\\\\\\\\ 第一个指令啊 public function _P47_():void{ this.hideMouse(); this._P30_(null); var _local1:PendingCall = this.+.getUserInfoAMF(this._P29_(this._bubbleFish.skey), this._bubbleFish.skey); _local1.responder = new Responder(this._P48_, this.errorBack); }\\\\\\\\\\\\\\\\\\\\\\\\响应事件设置,值是_arg1["user_info"] private function _P48_(_arg1:Object):void{ MouseState.getInstance().showMouse(); this._P228_(BubbleFishCommunicationEvent.COM_GET_USER, _arg1["user_info"]);\\\\\\\\\\\\\\\创建通信事件 private function _P228_(_arg1:String, _arg2:Object):void{ var _local3:BubbleFishCommunicationEvent = new BubbleFishCommunicationEvent(_arg1);_arg1["user_info"] 意思是这个事件返回的_arg1, 只返回 _arg1["user_info"]项目 红色部分 {"user_info":{"tutorial_tempo":11,"fish_food":400,"exp":627,"remain_shock_times":100,"shells":6514,"is_exchanged":false,"pearls":60,"first_login":false,"tempo":2,"max_tanks":3,"first_recharge":true,"almanac_level":2,"avatar":"http://hdn.xnimg.cn/photos/hdn121/20120401/0525/h_head_5d47_5f400003470a2f75.jpg","is_vip":"0","next_exp":750,"sns_id":"451237832","nickname":"韦春花","id":1447395,"has_level_up":false}} 那么 this._bubbleFish._P55_ = _local2["id"]; //原形毕露了吧就等于 this._bubbleFish._P55_ = _local2["id"] = 1447395看看,对吧!!
\\\\ 我们可以在第一个指令getUserInfoAMF请求后保存这个id给需要时用了。_local3 = this.+.getMyFishTankObjectListAMF(this._P29_(_arg2, _arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1, _arg2); 全部找到了参数1:this._P29_( _arg1, this._bubbleFish.skey) //通信掩码生成,早OK了参数2:this._bubbleFish.skey // skey,早OK了参数3:arg1 // 整数 _arg1:uint ,找到了,自身ID自身ID, getUserInfoAMF请求返回的["user_info"] ["id"] = 1447395提示:可以保存getUserInfoAMF返回的一些重要信息供相关指令使用。getMyFishTankListAMF返回所有鱼缸信息(不包括缸内鱼信息)
留意一下选中的那个 ID 项目(鱼缸ID),下述getMyFishTankObjectListAMF指令需要用到getMyFishTankListAMF 分析完。
6.分析第三个指令:amfService.getMyFishTankObjectListAMF (操作:看鱼缸里鱼类等信息)先看看Charles截取的请求参数
UltralEdit代码分析中查找 getMyFishTankObjectListAMF找到AS3代码 public function *_P81_(_arg1:uint, _arg2:uint){ var _local3:PendingCall; this.hideMouse(); _local3 = this.+.getMyFishTankObjectListAMF(this._P29_{(_arg2, _arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1, _arg2); _local3.responder = new Responder(this._P82_, this.errorBack); } 修正一下_local3 = this.+.getMyFishTankObjectListAMF(this._P29_(_arg2, _arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1, _arg2); 参数1:this._P29_(_arg2, _arg1, this._bubbleFish.skey) //通信掩码生成,早OK了参数2:this._bubbleFish.skey // skey,早OK了参数3:arg1 // 整数 _arg1:uint ,自身ID参数4:arg2 // 整数 _arg2:uint ,要去找它出处 找它出处就要看看谁调用函数 *_P81_了,// *_P81_ (_arg1:uint, _arg2:uint)UltralEdit中按 <Ctrl> + F 查找 *_P81_
1和2 一样的,任一个也行了,3是原自己这里,不用了就选择第1行 双击代码&.getInstance().*_P81_(this._host_id, this._data.id);所以 arg1 = this._host_id // 原先找过了,是自身IDarg2 = this._data.id // 快了继续努力 按 <Ctrl> + F 输入this._data.id =找到 protected function changeFishTankData(_arg1:Object){ var _local2:Array; this._data.star = _arg1["star"]; this._data.isMainFishTank = _arg1["is_first"];this._data.id = _arg1["id"]; // 这里 this._data.capacity = _arg1["capacity"]; this._data.fishTank_name = _arg1["name"]; this._data.can_be_trolled = _arg1["can_be_trolled"]; this._data.troll_price = _arg1["troll_price"]; this._data.troll_times = _arg1["troll_times"]; this._data.family_code = _arg1["family"]; this._data.is_shocked = _arg1["is_shocked"]; this._data.is_pool = _arg1["is_pool"]; this._data.price = _arg1["price"]; this._data.isProtected = _arg1["is_protected"]; if (this._data.style != _arg1["style"]){ this._data.style = _arg1["style"]; _local2 = _P195_._P417_.tanks; _local2[(_P195_._P417_.currMc.index - 1)] = _P195_._P434_.data; _P195_._P417_.changeTanks(_local2); this.addStyle(); }; }看到这里,有没有感觉是一个请求的返回呢,所以经验也是很重要的,我就不倒找它来历了
看看!!是不是一样的项目,_local3 = this.+.getMyFishTankObjectListAMF(this._P29_(_arg2, _arg1, this._bubbleFish.skey), this._bubbleFish.skey, _arg1, _arg2); 参数1:this._P29_(_arg2, _arg1, this._bubbleFish.skey) //通信掩码生成,早OK了参数2:this._bubbleFish.skey // skey,早OK了参数3:arg1 // 整数 _arg1:uint ,自身ID参数4:arg2 // 整数 _arg2:uint ,getMyFishTankListAMF请求返回的各个鱼缸的ID,指令 getMyFishTankObjectListAMF 分析完成。
土豪通道
网盘地址.txt
(66 Bytes, 下载次数: 117)
|
免费评分
-
查看全部评分
本帖被以下淘专辑推荐:
- · 鱼木收集|主题: 2526, 订阅: 2706
- · 学习及教程|主题: 1126, 订阅: 1118
|