本帖最后由 ss22219 于 2018-3-5 16:48 编辑
上一篇说到成功解析了服务器请求的加密和校验
这一篇简单分析下战斗数据吧
ac.php post:
请求参数这里就不多讲诉了,想要了解这些如何填入这些参数,可以从游戏源码,以及FGO管理系统中查获
base64解码并UTF8编码转换成字符串后
[JavaScript] 纯文本查看 复制代码 {
"response": [
{
.....
"isEncrypt": 1,
.....
}
],
"cache": "xxx"
}
战斗请求返回信息里面看到有一个cache是base64编码的
直接base64解码,发现是一堆乱码
在源代码里查找FromBase64String的引用,发现ResponseCacheDecrypt方法
查看ResponseCacheDecrypt方法引用
[C#] 纯文本查看 复制代码 if (serverMark)
{
string cryptString = (string)wwwparam["cache"];
string cacheString = string.Empty;
try
{
cacheString = CryptData.ResponseCacheDecrypt(cryptString, false);
}
这里发现,如果返回的信息包含isEncrypt=1,那么就执行ResponseCacheDecrypt
[JavaScript] 纯文本查看 复制代码 serverMark = (responseData.isEncrypt != 0);
对cache使用ResponseCacheDecrypt,然后得出战斗返回数据
这个数据包含了玩家svt信息,也包含了怪物的信息
我们写一个Fiddler插件,解析内容
判断url,base64解码返回值
[C#] 纯文本查看 复制代码 public void AutoTamperResponseBefore(Session oSession)
{
if (oSession.url.IndexOf("/ac.php?_userId=") != -1)
{
解码cache,改写isEncrypt=0
[C#] 纯文本查看 复制代码
var root = JsonConvert.DeserializeObject<JObject>(content);
var response = (JObject)root.SelectToken("response[0]");
var isEncrypt = response.Property("isEncrypt");
isEncrypt.Value = 0;
File.WriteAllText(@"C:\Users\gool\Desktop\project\fgo\cache.json", ResponseCacheDecrypt(root.SelectToken("cache").ToString()));
我们将cache保存到cache.json文件分析
可以看到其中有很多数据,进过反复对比确认
replaced.battle[0].battleInfo.userSvt包含了本次战斗的从者数据
updated.userSvtCollection包含了助战的一些信息
对于脱机战斗来说我们没必要解析这些信息
不过可以编写一个脚本,让Fiddler帮助我们来修改这些数据
获取助战svtId:
[C#] 纯文本查看 复制代码 List<int> GetFollowerSvtIds(JObject cacheObj)
{
var list = new List<int>();
var array = (JArray)cacheObj.SelectToken("updated.userSvtCollection");
if (array == null)
return list;
for (int i = 0; i < array.Count; i++)
{
var svt = (JObject)array[i];
list.Add(svt.Property("svtId").Value.Value<int>());
}
return list;
}
判定是否是怪物,修改基础数据
[Asm] 纯文本查看 复制代码 void ReplaceSvtInfo(JArray svts, List<int> followers)
{
FiddlerApplication.Log.LogString("ReplaceSvtInfo");
for (var i = 0; i < svts.Count; i++)
{
var svtObj = (JObject)svts[i];
if (svtObj.Property("userId").Value.ToString() == "0" && !followers.Contains(svtObj.Property("svtId").Value.Value<int>()))
{
if (svtObj.Property("atk") != null)
{
svtObj.Property("atk").Value = 10;
svtObj.Property("hp").Value = 40000;
}
}
else
{
if (svtObj.Property("atk") != null)
{
svtObj.Property("atk").Value = 80000;
svtObj.Property("hp").Value = 80000;
}
else if (svtObj.Property("maxAtk") != null)
{
svtObj.Property("maxAtk").Value = 80000;
svtObj.Property("maxHp").Value = 80000;
}
}
svts[i] = svtObj;
}
}
===========================================
FGO系列到此一共6章,也该结束了
1-3章记录了Native层的一些逆向技巧
4章简单说明了下Android Java层的调试方法
5-6章是游戏源代码的分析
虽然有很多遗憾,也有不少迷惑,但是也有不少收获
有朋友说想让我总结一下,但是我发现我实在总结不出什么东西来。。。
作为一名小白,一步步走到这里,发现很多都是以前积累的知识的运用
逆向的关键就是找到关键代码,比如在mono函数查找中,利用开源代码,一步步找到image_open函数
在java和c#代码分析中,利用login md5 base64这些关键词,往往能找到不少关键函数
实在想不出其他要说的,这个系列说了这么多东西,就放下脚本代码给大家用下吧
最后,祝大家新年快乐!
|