首页
论坛
课程
招聘
逆向某聊天app实现60行代码自定义发送消息图片
2020-12-7 03:29 11480

逆向某聊天app实现60行代码自定义发送消息图片

2020-12-7 03:29
11480

前段时间休假了半个月,在家无聊,也没有出去浪,像我们这种闲男,不陪lp和gf的话,肯定宅在这里。无聊,想找点事玩玩。在平时很少接触protubuf这个玩具。那天在群里闲转,就在群里问:有没有哪些app用了protobuf的,老友说QQ,微信,抖音。我这样的小白哪能去玩这么高大上的,有个群友说有个难度不太的app,然后就开始了一段梦幻的休假旅行。

 

因为涉及到有敏感信息,app名就叫马斯克吧。

抓包分析

登录抓包

登录返回界面如下:

具体抓包数据如下:

登录分析

逆向app把这个m_e和m_d搞定。思路很多种.
第一种,jadx中查看app的dex文件,搜索关键字"m_e".定位到如下内容。熟悉的aes和rsa加密。

我使用最快的frida hook它。用上库存里的frida脚本,得到如下动态信息,加密信息出来了。

 

 

一般而言,我会先进行动态分析,尤其是加密类的,一般frida脚本都能马上显示出来。如果加密关键内容比如key没有正常得出,肯定再需要进一步so层的分析,那接下来的步骤就是静态分析,静态分析的步骤是先找出关键搜索内容,定位到关键位置,进行java层的分析,后期的分析要么就进入 到so层,要么就会有其它第三方的框架,引入js或者lua。

 

这个请求提交的原始数据,我们从图中的before_doFinal可以直接看到。哪怕是加密的key和iv也出现了。

 

手机号和密码是我随便输入的,pwd字段明显就是md5,直接用了明文作了一次md5运算。

 

返回结果如下:

 

 

再用python转换一下:

 

分析后登录信息加密信息如下:

 

请求头中m_d是AES加密的,m_e是RSA加密的,服务器上有rsa的私钥,直接解密出来一个key,用这个key去参与m_d的AES解密,然后服务器就得到了m_d的原始内容了。响应中也类似一样,只是现在app做了服务器上一样的解密动作。

 

注册好了帐号正式登录,返回来了个人的用户信息,随后还会有两个一样加密算法的请求,获取群列表和好友列表。然后用bp开始抓不到包了。用charles出现connect的问题。

聊天内容抓包分析

聊天内容抓包

这个时候抓包可以用wireshark,或者tcpdump之类的工具,但这类工具抓取到的数据太杂,不利于这次的抓包分析工作,所以换另外一个自制的工具,用python写的socks5代理端,专用来抓tcp包的。

 

设置好了环境后,抓包。

 

抓到了数据。这里要说明一下。抓取到的数据输出都是byte字节的。这样做很方便转换成其它需要的数据。比如抓取到的内容如下

1
b'\x1a\x12\x0fHeartBeatAckMsg\x1a\x07\x12\x053.

用python输出这个bytes的16进制数据

 

 

16进制的数据,如果想转换成二进制数据,就很简单了。

聊天内容分析

因为protoc解析的是二进制数据。所以通过16进制转成二进制很方便。

 

打开一个hexFiend,然后把转换后的16进制数据复制到左侧栏内容:

保存。

 

用protoc来解析一下看看。操作了二个不包的数据包,解析结果如下:

 

 

有一个“好像”能解析有一个直接解析失败。什么原因呢?

 

马斯克是360加固的,脱壳app,然后把dex放jadx里倒腾倒腾。经过静态再经过用objection hook protubuf类,确定了是用了protobuf,而且通过搜索关键词"HeartBeatAckMsg"直接定位到了protobuf的关键类,proto文件要还原的话,有了这个类的信息就够了。但是为什么又解析不了呢??

 

再从jadx里面结合objection去分析,发现还用了一个框架netty,搜索了一下netty,并对它有了初步的认识,深入了解后,原来是他配合protobuf一起做到了高并发,高效率收发数据。protobuf用了netty的特点是在protobuf的数据前面多加了二个字节,表示protobuf数据的大小。

 

知道了原因,再尝试解析成功。

 

 

奇怪的是,从服务器返回来的数据在解析的时候有时需要去掉一个字节,有时2个字节。比如上面的HeartBeatAckMsg

 

数据能够通过protoc正常解析了,开始分析jadx中的proto相关类的生成。

 

 

从上面直接可以分析出来proto文件里面的格式,而且跟protoc解析出来的字段序号都是一样的。其它收发消息的proto文件按同样方式即可得到。
只例举一个书写好的proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
syntax = "proto3";
 
message HeartBeatMsg{
    string token = 1;
    string proto_class_name = 2;
    HeartBeatMsgContent body = 3;
}
 
message HeartBeatMsgContent{
    string from_id = 1;           
    int32 device_type = 2;
    int32 device_slave_type = 3;
    int64 last_msg_sequence_id = 4;
    int64 last_msg_receive_time = 5;
    string version = 6;
    int64 interface_up_time = 7;
    string apiurl = 8;
    string imurl = 9;
}

有几个地方需要注意:

 

1 proto格式文件的版本。
2 string类型的字段定义一般不需要处理,但int类型有很多种,还需要根据实际情况解析正常的数据后得到正确的结果。因为这个在jadx中分析不出来。

 

proto文件写好了,转换成python类

1
protoc --python_out=. HeartBeatMsg.proto

会在当前目录下生成一个HeartBeatMsg_pb2.py文件

 

然后在python中引入,解析数据

1
2
3
4
5
6
7
import HeartBeatMsg_pb2 #引入类
 
hbm = HeartBeatMsg_pb2.HeartBeatMsg()   #实例化
 
hbm.ParseFromString(buffer[2:])     #解析,buffer是byteArray类型,从抓到的数据中直接赋值给它,所以需要去掉2个字节
 
print(hbm)

得到如下结果

 

 

写其它proto文件和解析案例略过,有坑的地方我已经在上面说过。一个案例够其他同学研究学习了。

自定义消息内容发送

有了上面的分析和前期的工作,可以开始写发送消息的代码了。

 

首先是流程:通过http协议登录,获取群id或者好友id,然后再通过tcp协议收发消息。

 

为了省事,直接取用bp中抓到的token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import socket,uuid,time,google.protobuf
import AuthMsg_pb2,ChatMsg_pb2
 
skt = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
address = ("test.host.com",5000)
skt.connect(address)
token = {'isAuth': 1, 'nickName': '测试23242', 'headUrl': 'https://down.host.com/head/userhead.png', 'defaultId': '801adfafcc0d1afa0d', 'accessToken': 'tk:801adfafcc0d1afa0d:adfasdfaec0faf6a9', 'token': '1010e3d11973980c36ec8'}   #抓包获取到的token
 
#会话认验
def auth():
    am = AuthMsg_pb2.AuthMsg()
    am.token = token['accessToken']
    am.proto_class_name = "AuthMsg"
    am.body.from_id = token['defaultId']
    am.body.device_id = "861234123412"   #设备号
    am.body.device_type = 1;
    bnry = am.SerializeToString()   #protobuf序列化
    skt.send(addNettyHeader(bnry)); #通过skt发送内容
 
#聊天
def chat(news):
    msgstr = ChatMsg_pb2.ChatMsg()
    msgstr.token = userinfo['accessToken']
    msgstr.proto_class_name = "ChatMsg"
    msgstr.body.msg_id = "100-"+str(uuid.uuid1()).replace("-","")   #消息id号
    msgstr.body.main_type = 6           #固定
    if(news['type']==2):    #如果发送消息是图片
        msgstr.body.slave_type = 3         #1 纯文本,表情,3 图片 2 语音
        msgstr.body.content = news['txt']
    elif(news['type']==1):
        msgstr.body.slave_type = 1
        msgstr.body.content = news['txt']
    msgstr.body.from_id = userinfo['defaultId']
    msgstr.body.from_name = userinfo['nickName']
    msgstr.body.from_head_url = userinfo['headUrl']
    msgstr.body.dest_id = news['to'#接收消息的好友
    msgstr.body.send_time = int(time.time()*1000)
    msgstr.body.device_type = 1
    msgstr.body.device_slave_type = 11
    bnry = msgstr.SerializeToString()
    skt.send(addNettyHeader(bnry))
 
# 增加Netty头
def addNettyHeader(msg):
    value = len(msg)
    bits = value & 0x7f
    value >>= 7
    header_array = []
    while value:
        header_array.append(0x80 | bits)
        bits = value & 0x7f
        value >>= 7
    header_array.append(bits)
    return bytes(header_array)+msg
 
auth()
msg1 = {"type":1,"txt":"今天天气真好,有约吗?","to":123412}
msg2 = {"type":3,"txt":"https://img.host.com/test.jpg","to":123412}
chat(msg1)
chat(msg2)

发送成功了

后记总结

通过这次的学习,对protobuf有了更深入的了解,虽然最终代码量少,但是分析工作做了很多,花了很长的一段时间。有个小彩蛋是马斯克上传图片是采用阿里的oss的。获取到临时的一个凭证后,通过阿里自带的oss-brower登录后,可以查看主帐号的所有Bucket

 

进入bucket里面以后,测试了上传,复制,下载都可以。里面的聊天图片,视频,语音内容都能正常查看。

 

本次学习记录内容仅限于研究学习交流使用,有兴趣尝试玩一玩的同学,请勿做其它非法的延伸功能扩展,否则后果自负,与本文发布者、平台、参与交流同学无关。


[2022夏季班]《安卓高级研修班(网课)》月薪三万班招生中~

最后于 2020-12-7 19:03 被影…………编辑 ,原因:
收藏
点赞14
打赏
分享
最新回复 (29)
雪    币: 2016
活跃值: 活跃值 (4230)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
supperlitt 活跃值 2020-12-7 09:21
2
0
66666
雪    币: 5365
活跃值: 活跃值 (2455)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
尐进 活跃值 2020-12-7 09:30
3
0
秀儿啊
雪    币: 462
活跃值: 活跃值 (954)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2020-12-7 10:32
4
0

233

最后于 2020-12-7 10:39 被sudami编辑 ,原因:
雪    币: 3771
活跃值: 活跃值 (626)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MsScotch 活跃值 2020-12-7 10:41
5
0
期待 frida脚本。。。
雪    币: 2223
活跃值: 活跃值 (243)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
灬飘淼灬 活跃值 2020-12-7 11:07
6
0
期待目标样本
雪    币: 601
活跃值: 活跃值 (741)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Lateautumn4 活跃值 2020-12-7 11:25
7
0
雪    币: 14382
活跃值: 活跃值 (3564)
能力值: ( LV13,RANK:835 )
在线值:
发帖
回帖
粉丝
大帅锅 活跃值 4 2020-12-7 13:07
8
0
gf是什么意思
雪    币: 80
活跃值: 活跃值 (572)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
只是来打酱油 活跃值 2020-12-7 13:39
9
0
通过com.zuiai.hh我已经知道是哪个app了 确实不是微信.
雪    币: 5178
活跃值: 活跃值 (862)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xianhuimin 活跃值 2020-12-7 13:53
10
0
看样子像会合
雪    币: 1332
活跃值: 活跃值 (967)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
影………… 活跃值 1 2020-12-7 14:09
11
0
大帅锅 gf是什么意思
girl friend
雪    币: 175
活跃值: 活跃值 (3552)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
suuuuu 活跃值 2020-12-8 10:00
12
0
楼主妙笔生花,6666666
雪    币: 0
活跃值: 活跃值 (188)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
paynesb 活跃值 2020-12-8 12:56
13
1
求楼主的python写的socks5代理端
雪    币: 11081
活跃值: 活跃值 (3157)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 活跃值 4 2020-12-9 10:16
14
0
思路很好,强! 能再详细一点就好了
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
花雪 活跃值 2020-12-9 10:22
15
0
frida脚本有吗
雪    币: 1054
活跃值: 活跃值 (838)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
莫灰灰 活跃值 9 2020-12-9 10:49
16
0
牛逼
雪    币: 8911
活跃值: 活跃值 (37806)
能力值: (RANK:105 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2020-12-9 13:30
17
0
666 感谢分享
雪    币: 2436
活跃值: 活跃值 (227)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
飘云 活跃值 1 2020-12-9 16:31
18
0
优秀~~
雪    币: 295
活跃值: 活跃值 (725)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
darbra 活跃值 2020-12-9 21:59
19
0
厉害了 666
雪    币: 2
活跃值: 活跃值 (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Helang何浪 活跃值 2020-12-10 08:20
20
0
学习了
雪    币: 1226
活跃值: 活跃值 (617)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ST0n5 活跃值 2020-12-10 09:27
21
0
学习了,阿里oss 凭证是怎么获取的。 
雪    币: 1332
活跃值: 活跃值 (967)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
影………… 活跃值 1 2020-12-10 12:21
22
0
ST0n5 学习了,阿里oss 凭证是怎么获取的。
对这个感兴趣啊。不应该是学习protobuf吗?

抓这个app的包,然后需要解密响应包。这样还是需要会逆向app。把登录的算法逆向出来。你的问题就解决了。
雪    币: 1332
活跃值: 活跃值 (967)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
影………… 活跃值 1 2020-12-10 12:25
23
0
楼上有朋友说需要frida脚本,脚本更多的是自己写的。尤其针对不同的app有不同的脚本思路,也跟你对这个app的具体需求有很大的关系。所以给你也不一定适合。如果给你了,你再来问怎么使用,我会很尴尬。
最后于 2020-12-10 12:25 被影…………编辑 ,原因:
雪    币: 1
活跃值: 活跃值 (184)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bluegatar 活跃值 2020-12-13 16:23
24
0
牛逼就完事
雪    币: 1486
活跃值: 活跃值 (1162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylrocket 活跃值 2020-12-23 15:07
25
0
可以加个好友吗?可以聊聊这个,我这边也在研究这个!
游客
登录 | 注册 方可回帖
返回