吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17334|回复: 33
收起左侧

[转贴] AMF封包通信的游戏辅助易语言编写(逆向分析脱机教程)

  [复制链接]
远方呢 发表于 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字符

转换后

还记得这里的amfServicethis.+.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.txtM.破解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.skey2.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, 下载次数: 109)

免费评分

参与人数 6吾爱币 +5 热心值 +6 收起 理由
♂成成の + 1 + 1 终于遇到你
coody + 1 百度地址,可以更新下吗?
huang12583 + 1 + 1 头晕
lsrteam70 + 1 + 1 不明觉厉~
wazl8890 + 1 + 1 谢谢@Thanks!
白如雪 + 1 + 1 一脸懵比,佩服

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

天使3号 发表于 2018-9-13 11:43
太乱了。。
 楼主| 远方呢 发表于 2018-9-13 12:06
ajq119 发表于 2018-9-13 12:11
吾爱打炮 发表于 2018-9-13 12:33
虽然看不懂
linclon 发表于 2018-9-13 12:44
厉害厉害感谢楼主分享
bnb 发表于 2018-9-13 13:02
这个教程好像不是你做的吧,还有重要的AMF模块都没有
张小坑 发表于 2018-9-13 13:32
群文件共享?搬了能改改么
遗忘|那段情 发表于 2018-9-13 15:59
大神啊,收下膝盖
wazl8890 发表于 2018-9-13 16:00
学习了,谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-28 21:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表