首页
社区
课程
招聘
google protubuf 序列化分析
发表于: 2022-10-23 23:35 6246

google protubuf 序列化分析

2022-10-23 23:35
6246

# 前言

protubuf 支持多种语言跨平台的 协议序列化库

所以有很多公司用此库

发此文用于记录逆向心得,以及交流

Github:https://github.com/protocolbuffers/protobuf

docs:https://developers.google.com/protocol-buffers/docs/reference/overview


# 逆向

发包函数:

WSASend    WSARecv

Send       Recv


例子使用的是 WSASend  WSARecv


在 WSASend 下段获取原始发包内容

如下:


发包长度:0x24


$ ==>     00 00 00 20 00 06 63 68 00 0C 00 03 33 17 1B DE  ... ..ch....3..Þ  
$+10      48 BC 43 2A F1 CA 5C 91 0A A1 70 7D 34 B4 81 0F  H¼C*ñÊ\..¡p}4´..  
$+20      DE D8 23 3D 0C 01 B6 C3 DB E7 68 29 8C 27 4D 3E  ÞØ#=..¶ÃÛçh).'M>



经过对比分析发现其中

00 00 00 20        包总体长度除去自身字节,当然这个是倒叙排列

00 06              包头长度 除去自身字节以及上面的4字节

头部分析

63 68              “ch” 特征字 无用

00 0C 00 03        特征字

头总共大小 0xC

剩下的都是Message主体部分


发包前他把消息主体进行了加密,经过解密如下




$ ==>     08 09 10 02 18 0D 20 1F 2A 06 0A 00 10 7B 18 01  ...... .*....{..  
$+10      08 08 08 08 08 08 08 08 51 B8 3D 92 00 C2 00 80  ........Q¸=..Â..


Message 消息一共 0x18字节

我们使用 **protoc.exe --decode_raw < pbuf.bin**

根据解析内容编写 proto 文件

syntax = "proto2";//使用的语法
package bs.client_ms;
message GoldLockReq {
        required string fld1 = 1;
        required int64 ilock_gold = 2;
        required int64 op_type = 3;
}
message GoldLockHeadReq {
        required int64 fld1 = 1;
        required int64 fld2 = 2;
        required int64 fld3 = 3;
        required int64 res_op_type = 4;
        required GoldLockReq GoldSuccor = 5;
}

从结构对应上图,有的小盆友可能会问 8888

为什么没有成员?

因为经过分析 后面的为填充字节 (值为填充了多少字节),使用protubuf 解析将会失败,有时候会成功,有时候会失败

这个根据后面填充的字节数值是什么决定


编译"proto"文件

protoc.exe --python_out=. *.proto

得到同文件名.cpp .h 文件


复制到自己工程目录并引用他

编译 会发现一大堆报错

根源就在于 


#include <google/protobuf/port_def.inc>

#include <google/protobuf/port_undef.inc>


引入了 .inc 文件

找到这两个文件,复制一份改为.h

并在引用的地方把后缀改为.h

即可


bs::client_ms::GoldLockHeadReq pResGoldLockHead = bs::client_ms::GoldLockHeadReq();//创建GoldLockHeadReq对象
if (pResGoldLockHead.ParseFromArray(newdata, nNewAlignSize))// 反序列化数组
{
  printf("fld1:%s  lock gold:%lld op_type:%lld\n", pResGoldLockHead.goldsuccor().fld1().c_str()
, pResGoldLockHead.goldsuccor().ilock_gold(), pResGoldLockHead.goldsuccor().op_type()
);
    pResGoldLockHead.mutable_goldsuccor()->set_ilock_gold(2222);//设置子结构成员
    pResGoldLockHead.SerializeToArray(newdata, nCurrtenAlignSize);// 序列化到数组
}

以上代码编译成功,但测试无法解析,重点就在于后面填充的字节,也就是大小传入错误填充字节不属于 结构


怎么办呢?

同性交友走起 github

protodec:https://github.com/schdub/protodec

这是一个 proto 文件解析库,包含示例

我们引用重要文件 : protoraw.hpp

RawMessage msg;//创建对象
char* endbyssdd = &newdata[nCurrtenAlignSize];//结尾指针
bool Success = msg.parse((const unsigned char*)newdata, (const unsigned char*)endbyssdd);//解析

这里仍然会解析失败,但不重要,我们修改 parse 函数

添加成员:m_ErrorPos  标识错误位置

添加函数:GetErrorPos  获取错误位置

添加相同数据跳出



这样我们就知道错误位置在哪里以便于修正大小

那么又有小盆友问了

为什么不直接使用这个进行解析

关于这个问题,我的回答是他不如官方解析来的方便

当然你可以使用这个来进行解析


# 结尾

没有结尾,故事没有结束(屁来的故事啊!可恶)


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//