周五最后一天上班了,明后休假,写个简单的游戏分析吧!
问我为啥不先分析内存?
答:游戏框架很简单就是一个未加密未混淆的libil2cpp游戏,dump下来自己找函数就行,没啥难度也没啥意思。毕竟分析游戏只是为了好玩,并没有其他的原因,所以就直接分析协议了。1. 模拟器运行游戏
2. 直接上frIDA抓包,看看包的情况,游戏里跑跑
开心啊,这不明文跑的游戏吗,这年头很难遇到明文直接跑的游戏了,都不需要解密,不需要反编译了。拿个包给大家分析下包的结构:
[send -> 139.9.39.108:9023]: 0x53f5dd8 length: 0x25
00000000 23 00 1b 00 53 79 6e 63 50 61 72 74 5f 4f 6e 49 #...SyncPart_OnI
00000010 73 49 6e 53 63 65 6e 65 52 65 71 75 65 73 74 04 sInSceneRequest.
00000020 00 08 00 10 00 .....
23 00 是整个封包去除23 00 这两个字节的长度。
1b 00 是后面协议字符串的长度,这个协议字符串就相当于MessageID,封包的唯一识别。
53 79 6e 63 50 61 72 74 5f 4f 6e 49 73 49 6e 53 63 65 6e 65 52 65 71 75 65 73 74 是协议字符串。
04 00 是后面字节的长度,其实后面字节才是真正的协议内容。
08 00 10 00 是协议内容
3. 识别协议内容:
如果你有足够经验的话,看到08 00 10 00基本上百分之99%断定是经过protobuf序列化后的协议序列。
08(key) 00(value) 10(key) 00(value)
key = field_numer << 3 | wire_type <==> 08 = 01 << 3 | 0,可知wire_type=0属于varint,所以08 00的意思就是第一个字段的值为00,值得类型为varint
同理,10 = 02 << 3 | 0,可知wire_type=0属于varint,所以10 00的意思就是第而个字段的值为00,值得类型为varint
所以08 00 10 00反序列化之后的结果为:
4. 自己写protobuf的反序列化脚本,然后游戏的整个协议就破解完了,脚本的效果如下:
5. 贴上我字节写的脚本:
[Asm] 纯文本查看 复制代码 function hook_sendMessage(addr){
console.green_log('[+] hook_sendMessage [url=home.php?mod=space&uid=402414]@[/url] '+addr.toString());
Interceptor.attach(addr, {
onEnter: function (args) {
if (Socket.type(args[0].toInt32()) == null) return //tcp
var address = Socket.peerAddress(args[0].toInt32())
if (address === null) return
var package_size = args[1].readU16() //获取包长
var package_name_size = args[1].add(0x2).readU16() //获取Message str 大小
var package_name = args[1].add(0x4).readUtf8String(package_name_size) //获取Message str
var send_buff = args[1].add(0x4).add(package_name_size) //定位包体位置
var proto_buff = send_buff.add(0x2) //定位protobuf序列的位置
var proto_buff_size = send_buff.readU16() //获取protobuf序列长度
if(package_name == 'OnHeartPkgRequest') //过滤心跳包
return
var messages = {}
var protobuff_list = byteArray2list(proto_buff.readByteArray(proto_buff_size))
decode_protobuf(protobuff_list, 0, protobuff_list.length, messages) //反序列化包字节
print_dump(args[1], args[2].toInt32())
console.yellow_log('Message_name: ' + package_name)
console.green_log(JSON.stringify(messages, null, 4))
switch(package_name) //修改封包
{
case 'Backpack_OnUseDaoJu':
var write_messages =
{
"1:0:Varint": 0,
"2:1:Varint": 0
}
break
case 'Duplicate_OnSaoDangGuanQia':
var write_messages =
{
"1:0:embedded message": {
"1:0:Varint": 0,
"2:1:Varint": 5,
"3:2:Varint": 15
}
}
break
case 'ChatPart_Speak':
var write_messages =
{
"1:0:Varint": 0,
"2:1:string": "",
"3:2:string": "22222",
"4:3:Varint": 1
}
break
}
if(typeof(write_messages) != "undefined")
{
var data = []
encode_protobuf(write_messages, data) //序列化包字节
Memory.writeByteArray(proto_buff, data)
//写入长度
send_buff.writeU16(data.length) //写入protobuf包长
args[1].writeU16(package_size - proto_buff_size + data.length) //写入package长度
args[2] = ptr(package_size - proto_buff_size + data.length + 2) //改写发包长度
print_dump(args[1], args[2].toInt32())
}
},
onLeave: function (retval) {
}
});
}
6. 通过测试该款游戏的协议,还算是比较安全的,没有什么大的刷道具,刷钱bug,但有些小bug,这里我也不公布,希望大家公平玩游戏,不要去搞破坏。 |