1. 网址:b'aHR0cHM6Ly9zdG9yZS5zdGVhbXBvd2VyZWQuY29tL3RhZ3MvemgtY24vJUU1JTg4JUI3JUU1JUFFJTlEJUU1JUIwJTg0JUU1JTg3JUJCJUU2JUI4JUI4JUU2JTg4JThGLz9vZmZzZXQ9MA=='
base64 解密即可
2. 请求参数:
找到游戏列表请求接口发现,input_protobuf_encoded 是加密参数,从字面意思看出是protobuf 序列化的数据
3. 响应数据:
响应数据看着乱码, 应该是protobuf 序列化后二进制数据
4. 分析加密参数
4.1 在send 位置打上断点,发包后可断住
上面可以看出 d.params.input_protobuf_encoded = a, a 是 r.JQ(o)加密而来, o则是Uint8Array 数组,o 其实是 n 序列化后的结果,n 的数据结构如下图:
4.2 所以我们得分析n 是如何生成的。
向上跟栈 在下图位置打上断点:
关键生成位置代码:
首先看 t 的值是 s.gA.Init(l.eK) 生成的,生成一个还没有数据的空结构,包含m_bValid,
m_body, m_header三部分数据
上面的 const i = t.splice(0, this.k_nMaxBatchSize); 这里的t 是个数组,是每一个没有数据的空结构加上game_id 组成的, this.k_nMaxBatchSize=250 是固定值,是取出数组的前250 位
4.3 分析s.gA.Init(l.eK) 中 s,l 的由来:
找到当前代码所在模块,发现代码是用webpack 打包的,s, l 分别在68333 模块和85251模块,然后可以找到 n 加载器的位置,再导出这些模块即可
4.4 在t的数据中 添加上game_id 数据
t.Body().set_ids(i) ,上面分析的 t 是空的数据结构,i 是游戏的id 结构
添加后t 的数据增加上了game_id
(0,m.pA)(t, this.m_bUsePartnerAPI) 此代码是在 t.m_body.array 增加了语言和地区信息
5. 对上面的 t 数据进行序列化操作:
这里的 o = n.SerializeBody() 的 n 就是上面的 t 数据
序列化后得到的数据再经过 r.JQ(o) 处理后得到最终加密结果
这里的 r.JQ(o) 的 r 也是webpack 的模块 r =n(5155)
以上是请求参数加密的分析过程。。。。。。。。
5. 响应数据分析:
在此位置打上断点
let l = yield this.Send(e, t, n, a); 此时l是响应返回的数据
protobuf 反序列化位置: let e = new u.At(l.data)
, t = new s.BinaryReader(e.GetPacket(),e.TellGet(),e.GetCountBytesRemaining());
r.deserializeBinaryFromReader(i.Body(), t)
此时i.Body()是经过反序列化的结构化数据了
5.1 继续单步调试后进入以下位置:
此处是对e.Body().wrappers_[1] 的数组进行遍历操作,继续进入 this.ReadItem(i, n); 方法
在此位置 r值已经是明文数据了
可以看到r 这里是出现游戏的数据信息了
6. 游戏tagNames 签名位置
7. 游戏tagNames解密位置:
标签接口返回的二进制数据经过protobuf 放序列化操作:
反序列化后得到结构化数据 i, 单步调试后进入下图位置,经过 d = l.Body().toObject()得出游戏明文标签数据。
end。。。。。。。。。。。。。。。