前言

在前面我们已经写好了账号的登录,现在开始正式的进入烧脑的环节。

使用工具

工具名称用途
ffdec反编译swf文件
Fiddler/F12开发者工具抓包
开发IDE(随意)存档加解密复现

分析开始

我们开始尝试抓包,抓到了获取存档列表的数据,但是发现有个 verify 参数,不过看着就是拼凑的md5。

提取SWF

因为这个游戏是swf的,所以,我们需要先提取swf,最开始的时候,我提取了游戏的swf,搜索 https://save.api.4399.com/?ac=get_list 发现,根本没有,然后分析了很久,最后发现,并不在游戏的swf里,而是在依赖包里。

这些就是游戏的依赖包,但是,我们需要的只有一个。下面我们开始分析。

分析swf

我们先把依赖包丢进 ffdec 里,直接查找 https://save.api.4399.com/?ac=get_list

最后,我们知道了 ctrl_mo_v5.swf 是我们需要的文件,接着,我们看看那里引用了 URL_SAVE_LIST 变量,我们直接跳过去。

我们直接查看,这不就是找到了吗

_loc2_ = new URLVariables();
_loc2_.gameid = mainProxy.gameID;
_loc2_.uid = mainProxy.userID;
_loc3_ = param1.target.data;
_loc2_.token = _loc3_;
_loc4_ = saveKey();
_loc2_.gamekey = _loc4_;
_loc5_ = MD5.hash(MD5.hash(MD5.hash("SDALPlsldlnSLWPElsdslSE" + _loc4_ + mainProxy.userID + mainProxy.gameID + _loc3_ + "PKslsO")));
_loc2_.verify = _loc5_;
logList = new LogData(LogData.API_SAVE,"list");
new LoaderUrl(AllConst.URL_SAVE_LIST,returnList,_loc2_);

这很明显了呀,verify 就是经过了3次 md5 计算出来的,我们接着看看它还有个 saveKey 函数

private function saveKey() : String
{
    return MD5.hash(MD5.hash(this.mainProxy.gameID + "LPislKLodlLKKOSNlSDOAADLKADJAOADALAklsd" + this.mainProxy.gameID)).substr(4,16);
}

发现也是很简单,这个 gameID 在这里是找不到的,需要在游戏的swf里找,但是,我们前面抓包里就有呀,直接拿来用就好了。然后,我们尝试把这个获取存档列表写出来

我们直接运行测试,看看能不能获取成功,下面就是成功的,所以我们的没有问题

这里,我们列表是有了,但是数据呢,我们继续抓包看看。获取是啥样的。

随便点进一个存档,我们就发现,它会提交一个 https://save.api.4399.com/?ac=get 的请求,我们在 ffdec 直接搜索,向刚刚那样定位

这里的 verify 也是一样的算法,直接用上面的即可。我们需要注意的是 returnGet 函数,我们跳过去分析

data = com.adobe.serialization.json.JSON.decode(e.target.data) as Object;
tmpObj = this.copyObj(data);
try
{
    byte = Base64.decodeToByteArray(data.data);
    byte.uncompress();
    data.data = byte.readObject() as String;
    byte = null;
}

我们最后分析看到,我们需要的只有这段代码,从中我们可以知道,它是先 Base64 解码后,再进行 zlib压缩,这里的 byteByteArray 类型,默认压缩和解压都是 zlib 的。解压之后用了 readObject ,这函数呢,是有个序列化的过程的,我们先不管,一会在研究,我们直接写代码进行测试解压后的数据。

这里我用了我封装好的 ByteArray 模块,我们直接运行看到解密是解密出来了,但是为什么前面会多几个乱码呢,别急,还记得前面我说的 readObject 函数吗,它是有自己专门的一套序列化,前面那乱码,就是它自己的解构。我们输出字节集看看。

这里,我们发现,数据长度是 12312 正确的字符长度应该是 12308 才对,这前面多了 4 字节的长度,由于我也是第一次接触到 AS 这块,后面通过网上查资料了解到了结构

请输入图片描述

最后放上解析的代码,其中借鉴了 GitHub 上的 XPilot 的 ByteArray.js ,感谢大佬们的贡献。

这里为什么我用 变体型 是因为后面我封装的时候,其他类型好读取,最后我们按照反编译出来的代码还原,运行测试。

运行成功,完美的还原出了数据,至于保存存档,也是差不多的,也就是和读取差不多的,只是提交链接不一样而已

它的存档数据,无非就是 writeObject 写入数据后,对 ByteArray 的数据进行 base64编码 即可。这里大家可以自己尝试下,我会把封装好的 ByteArray 模块放到最后,有需要的可以下载直接使用即可

最后

因为我也是第一次接触这块,如果有错误的地方,请各位告知,我也会感谢大家。

附件

ByteArry 1.1 模块.ec

最后修改:2023 年 01 月 12 日
如果觉得我的文章对你有用,请随意赞赏