flash页游seer2折腾日记2
前言
这里主要探究一下赛2的登录通讯部分。直接从2开始写了,后面有时间了再把1补上。
flash曾有着辉煌的过去,但是随着漏洞越来越多,且无法有效的解决,正在逐步被html5替代。过去的flash游戏网站或者转型h5、手游或者逐渐没落、淘汰,但是看一看这些“过时的代码”,还是能让人学到一些有用的东西。
用反编译工具反编译下载的flash文件,发现里面有大量ActionScript(.as)文件。我没有系统的学习ActionScript,但是考虑到有学习过Java,刚好as又和Java有相似之处,干脆结合Google,用java语言分析as。
预习
工欲善其事必先利其器,as的基本数据类型还是要了解一下的
as3基元数据类型包括 Boolean、int、Null、Number、String、uint 和 void。
Boolean 数据类型包含两个值:true 和 false,默认值是 false。
int 数据类型在内部存储为 32 位有符号整数,默认值是 0。
Null 数据类型仅包含一个值:null。
Number 数据类型使用IEEE-754标准,为64 位双精度浮点数。
String 数据类型表示一个 16 位字符的序列。字符串在内部存储为 Unicode 字符,并使用 UTF-16 格式。
uint 数据类型在内部存储为 32 位无符号整数,默认值是 0。
void 数据类型仅包含一个值:undefined。无类型变量是指缺乏类型注释或者使用星号 (*) 作为类型注释的变量。您可以将 void 只用作返回类型注释。
ActionScript 核心类还定义下列复杂数据类型:Object、Array、Date、Error、Function、RegExp、XML 和 XMLList。
ActionScript 也是面向对象的语言,遵循面向对象的抽象、封装、继承、多态等特点。
准备
导出脚本资源:
分析知,Action为我们需要的as文件,选中后导出。
导出后得到as文件,为了方便查看代码,可以使用idea配合插件使用。
探秘
this._progressBar.setTitle("正在加载登陆界面");
this._progressBar.setTitle("正在进入游戏");
大致翻一翻,看到了汉字很让人舒心。这正是游戏加载时我们能够见到提示信息,说明我们的方向是正确的。
private function onConfigXMLComplete(event:XMLEvent) : void{
var _loc_2:* = event.data;
......
this._loginURL = String(_loc_2.login);//设置loginURL为dll/LoginModule.swf
......
return;
}// end function
private function loadLogin() : void{
this._progressBar.setTitle("正在加载登陆界面");
this._loginLoader = new Loader();
this._loginLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onLoginBytesComplete);//登录成功事件
this._loginLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, this.onProgress);//过程错误事件
this._loginLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.onIoError);//通信错误事件
var _loc_1:* = new URLRequest(this.ROOT_URL + TaomeeVersionManager.getInstance().getVerURLByNameSpace(this._loginURL));//下载dll/LoginModule.swf文件
this._loginLoader.load(_loc_1); //加载登录界面
return;
}// end function
<root debug="0">
......
<login>dll/LoginModule.swf</login>
......
</root>
结合seer.xml文件,发现基本页面加载完成后,有添加对dll/LoginModule.swf的监听事件。随后的程序则为登录成功、失败处理函数,所以中间经历了LoginModule模块。
核心
故导出LoginModule.swf的as文件,并对其继续分析。
private function showMainLoginView(param1:Function = null) : void{
......
this._loginPanel = new MainLoginPanel(this._loginAgent, true, param1);
......
}// end function
private function login(param1:String) : void{
var loginPanel:MainLoginPanel;
var onConfirm:Function;
var actualLogin:Function;
var net:* = param1;
var checkPassword:* = function (param1:String) : Boolean{...};
// end function 检查密码合法性,这里语法上有点类似于JavaScript而不是Java
onConfirm = function () : void{...};// end function
actualLogin = function () : void{
......
_account = StringUtil.trim(_accountInputTxt.text);//去空格
if (_savedPassword != null)
_password = _savedPassword;
else
_password = MD5.hash(MD5.hash(_passwordInputTxt.text));
//hash hash,加密传输,看来X米还是挺负责的
if (net == "Telecom")//电信登录和网通登录,二者调用不同的函数处理
_loginAgent.telLogin(_account, _password);
else
_loginAgent.cncLogin(_account, _password);
.....
};// end function
loginPanel;
if (this.verifyAccountAndPassword() == false) return;
if (this.checkPassword(this._passwordInputTxt.text) == false)
{
AlarmPwdPanel.show(this, "你的密码太简单啦!英文+数字更加安全哦!", onConfirm, actualLogin);
return;
}
this.actualLogin();
return;
}// end function
随后调用telLogin、enterTel、checkLoginMethod、digitalAccountLogin以及Connection.send()
依次检查了登录类型是电信还是网通、账号类型是邮箱还是数字,最后调用Connection.send()函数将数据打包发送。
数据处理该过程如下:
public static function send(param1:int, ... args) : void
{
args = packBody(args);
var _loc_4:* = packHead(param1, args, args.length);
var _loc_5:* = new ByteArray();
_loc_5.endian = Endian.LITTLE_ENDIAN;
_loc_5.writeBytes(_loc_4);
_loc_5.writeBytes(args);
if (_socket.connected == true)
{
_socket.writeBytes(_loc_5);
_socket.flush();
}
return;
}// end function
private static function packHead(param1:uint, param2:ByteArray, param3:int) : ByteArray{
var _loc_4:* = new ByteArray();
_loc_4.endian = Endian.LITTLE_ENDIAN;
_loc_4.writeUnsignedInt(Message.HEAD_LENGTH + param3);
_loc_4.writeShort(param1);
_loc_4.writeUnsignedInt(_uid);
_loc_4.writeInt(0);
var _loc_5:* = 0;
param2.position = 0;
var _loc_6:* = 0;
while (_loc_6 < param3){
_loc_5 = _loc_5 + param2.readUnsignedByte();
_loc_6++;
}
_loc_5 = _loc_5 % 100000;
_loc_4.writeInt(_loc_5);
return _loc_4;
}// end function
private static function packBody(param1:Array) : ByteArray {
var _loc_3:* = undefined;
var _loc_2:* = new ByteArray();
_loc_2.endian = Endian.LITTLE_ENDIAN;
for each (_loc_3 in param1)
{
if (_loc_3 is String)
{
_loc_2.writeUTFBytes(_loc_3);
continue;
}
if (_loc_3 is ByteArray)
{
_loc_2.writeBytes(_loc_3);
continue;
}
_loc_2.writeUnsignedInt(_loc_3);
}
return _loc_2;
}// end function
代码中多处用到了as中常用的数据类型ByteArray。这一数据类型可以读写单个字节、整数、UTF,还能压缩、解压缩字节数组,最麻烦的是大小端编址的问题。Java中没有直接和其对应的数据类型,而DataInputStream不支持小端编址,且为数据流,用于存放数据有太多不便。好在Sun曾对Java的IO进行过优化,编写了ByteBuffer这一数据类型,可以读写字节、整数、字节数组,支持大小端编址。可以利用ByteBuffer实现ByteArray的基本功能。
数据处理的流程图如下:
其中校验码的计算方法为:以无符号字节为单位,计算打包后的数据体之和,最后模100000。
验证
查看源码,获得发送的数据为:
Connection.send(103, password, this.getReviseTmcid(), LoginConfig.productID, 0, this.verifyCodeInfo.getVerifyImgIdData(), this.verifyCodeInfo.getVerifyCodeData(), this.getTopLeftTmcid());
//103为协议号,cid为uint = 65,productID=10,ImgIdData为16位byte0,CodeData6位byte0,TopLeftTmcid长64位,且第一位为“0”
设置代理,获得登陆时的请求数据为:
94, 0, 0, 0, 67, 0, bf, 71, bb, f, 0, 0, 0, 0, 85, 9, 0, 0, 36, 36, 66, 39, 62, 34, 64, 37, 36, 35, 65, 33, 65, 64, 37, 38, 64, 63, 63, 37, 33, 61, 37, 65, 35, 62, 37, 33, 34, 31, 58, 58, 58, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //最后三位(58,58,58)略有修改
利用编写的解码工具,得到的结果为
length:148, param_t:103, uid:2639NNNN, zero:0, check:2437
66f9b4d765e3ed78dcc73a7e5b734XXX
65
10
0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
getMd5(getMd5("****密码***"))//66f9b4d765e3ed78dcc73a7e5b734XXX
解码结果与发送结果一致,思路正确!
吐槽
as这玩意儿有点坑,markdown的代码编码都识别不出来这语言!!!
参考
https://help.adobe.com/zh_CN/as3/learn/WSf00ab63af761f1702761490412937d6fc9b-7ff5.html
本文由 ukuq 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jul 11, 2019 at 06:59 pm