安卓逆向 | Protobuf协议逆向和仿真&举个栗子

Posted 燕幕自安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓逆向 | Protobuf协议逆向和仿真&举个栗子相关的知识,希望对你有一定的参考价值。

一、前言
产品有需求要全力满足,产品没有需求创造需求也要满足。
本次的主角是ctrip.com携程。以它为例子介绍一下非HTTP的通信协议逆向分析及协议仿真。
本文你将了解到Google Protobuf的逆向分析及协议还原等知识,没关注的盆友关注一下,我们开冲。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
二、目标
机票价格接口

三、逆向过程
按照正常的过程,我们逆向第一步应该是抓包。下面是我抓到的。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
看到这里不要怀疑,我们抓包没有问题,那为什么会这样呢。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
正常情况下,抓到的包应该是标准的HTTP协议格式,我们实现完成整个报文的仿真模拟,然后发包即可。但是现在,我们什么都看不到。
抓包我使用的工具是Packet Capture,它是基于本地VPN实现的抓包,可以支持TCP及以上层的消息捕获。
那么,我们现在就有理由怀疑,携程的网络通信,没有使用HTTP协议,而是自建协议完成的。分析完毕,那么下一步我们怎么来找到收发包位置呢。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
(此处省略几万字的定位过程)
经过长时间的寻找,后来灵机一动,如果是我来写接收数据的代码,很可能我要写个while True的循环,然后用已经建立连接的socket进行循环接收数据。以此为标识,我们找找看。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
紧接着,我们在最后一个结果中找到了想要的接收数据的标识。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
当我们跟着这个invokeResponse一直下去,就能找到一个神奇的地方“ctrip.business.comm.ProcoltolHandle”,(在这里你能找到所有的序列化和反序列化过程)到这里,具体的逆向就不表了。相信看到这的同学继续找下去不是问题。
从这里我们可以知道,每一个包前面有14个字节的协议头,之后是gzip压缩的结果。再后面是4字节的包体的长度,然后是消息内容。
这样我们就可以写出来解码的代码。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
需要说明一下的是,data的来源即是我们抓包抓到的十六进制,copy出来就可以。
接下来着重说一下这个proto_decode。
  
    
    
  
def proto_decode(data): process = subprocess.Popen([r'D:\tools\protoc.exe', '--decode_raw'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = error = None try: output, error = process.communicate(data) except OSError: pass finally: if process.poll() != 0: process.wait() return output
我们反序列化protobuf是利用google提供的工具protoc.exe,带参数执行可以解码成可读的形式。(感谢YungGong协助)
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
这个其实就是相当于HTTP协议里的header了,可是我们现在还不知道字段名,记住这些数字。我们在代码里找找看。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
通过这个文件我们就知道了文件名和数字序号的关系,然后我们自己写代码,组建一样的message,就可以序列化成他一样的结构了。
  
    
    
  
message RequestHead { enum SerialozeCode { Normal = 0; UTF8 = 1; PB = 2; Json = 3; SotpPB = 4; SotpJson = 5; PBSotp = 6; PBJson = 7; JsonSotp = 8; JsonPB = 9; GraphQL = 10; } optional SerialozeCode serializeCode = 1; optional string systemCode = 2; optional string language = 3; optional string userId = 4; optional string clientId = 5; optional string clientToken = 6; optional string clientVersion = 7; optional string sourceId = 8; optional string exSourceId = 9; optional string serviceCode = 10; optional string messageNumber = 11; optional string authToken = 12; message Extention{ optional string Key = 1; optional string value = 2; } repeated Extention extentionList = 13; optional string appId = 14; }
这个就是proto文件了,我们再通过命令行,让工具帮我们把这个结构生成为序列化反序列化的类。
  
    
    
  
protoc.exe --proto_path=D:\code\ctrip\src\main\proto --java_out=D:\code\ctrip\src\main\java D:\code\ctrip\src\main\proto\ResponseHead.proto

然后我们直接调用生成类的接口即可实现参数设置及序列化成byte[]。接下来就要展现出我们正向编码的能力了。完成Header的生成和整个body的组装,
通过socket发出即可。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
这里还涉及到发送的代码和接收的代码编写,如果不会的话抄一抄android里的代码。
对了,需要注意的是,这里有一些参数是防爬虫的参数,计算写在so里面,如果不会逆的话,可以参考之前的文章。

这样我们就能嘿嘿嘿。

安卓逆向 | Protobuf协议逆向和仿真&举个栗子


安卓逆向 | Protobuf协议逆向和仿真&举个栗子
返回中,除了header就是json格式的body了。下面就是收到的航班信息和价格了。
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
安卓逆向 | Protobuf协议逆向和仿真&举个栗子
到这里,整个任务就完成了。

四、总结
这个任务,我们需要学习和具备的知识有:
  1. Proto数据反序列化和Proto文件生成
  2. 收发包socket网络编程
  3. 加密参数逆向和调用
  4. 一大罐耐心
以上。欢迎阅读转发~

想要转载的朋友请告知我之后转载,并注明原帖来源。
如有问题,请关注公众号回复【作者】获取我的联系方式。
想了解更多技术分享,请长按识别下方二维码关注我吧。



以上是关于安卓逆向 | Protobuf协议逆向和仿真&举个栗子的主要内容,如果未能解决你的问题,请参考以下文章

Android逆向学习路线

某直播APP逆向TCP协议分析

关于安卓逆向你需要知道的工具及网站

PBTK:一款针对Protobuf App的逆向工程与模糊测试套件

什么是Android逆向?如何学习安卓逆向?Android逆向自学笔记入门到实战

《APP逆向学习》课程介绍和什么是安卓app逆向?