文章目录[隐藏]
转载 26 / 27
- 【转载】unidbg hook 使用大全
- 【转载】ida 基本使用 常用快捷键
- 【转载】Frida和调试器共存的问题
- 【转载】Charles抓包Android最佳流量转发APP
- 【转载】安卓自定义代码调用系统函数并编译so记录
- 【转载】jnitrace 手机卡死黑屏问题解决
- 【转载】Unidbg SO 逆向入门实战教程一 OASIS
- 【转载】Unidbg SO 逆向入门实战教程二 calculateS
- 【转载】Unidbg SO 逆向入门实战教程三 V2-Sign
- 【转载】Unidbg SO 逆向入门实战教程四 mfw
- 【转载】Unidbg SO 逆向入门实战教程五 qxs
- 【转载】Unidbg SO 逆向入门实战教程六 s
- 【转载】Unidbg SO 逆向入门实战教程七 main
- 【转载】Unidbg SO 逆向入门实战教程八 文件读写
- 【转载】Unidbg SO 逆向入门实战教程九 blackbox
- 【转载】Unidbg SO 逆向入门实战教程十 simpleSign
- 【转载】android app 加密参数分析研究 hash aes
- 【转载】第一讲——从黑盒攻击模型到白盒攻击模型
- 【转载】第二讲——白盒加密攻击方法的选择
- 【转载】第三讲——差分故障攻击的原理
- 【转载】第四讲——差分故障攻击的工具链
- 【转载】第五讲——使用源码进行DFA攻击
- 【转载】第六讲——使用Frida进行DFA攻击
- 【转载】第七讲——使用Unidbg进行DFA攻击
- 【转载】第八讲——案例
- 【转载】猿人学 - app 逆向比赛第四题 grpc 题解
- 【转载】猿人学 - app 逆向比赛第五题双向认证题解
本文转载至大佬的公众号,名称 = 二进制科学,有兴趣的可以关注下
原文链接: https://mp.weixin.qq.com/s/TaLeKFc6tjd6_eaG2VONlA
周五晚 8 点参加了猿人学的 app 逆向比赛, 和我的队友 "duoduo" 兄一起把这道题做出来了, 于是简单分享一下思路和过程。
目录
⊙一 . 什么是 grpc
⊙二. 什么是 protobuf
⊙三. 数据包协议分析
⊙四. sign 加密与 python 代码实现
⊙五. 总结
一 . 什么是 grpc
gRPC 是一个现代开源的高性能远程过程调用 (RPC) 框架,可以在任何环境中运行。它可以通过对负载平衡、跟踪、健康检查和身份验证的可插拔支持有效地连接数据中心内和跨数据中心的服务。它也适用于分布式计算的最后一英里,将设备、移动应用程序和浏览器连接到后端服务。
gRPC
基于 HTTP/2
协议传输。
客户端传递个函数进去, 然后服务端执行成功后给客户端结果。
二. 什么是 protobuf
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
可以简单理解为,是一种跨语言、跨平台的数据传输格式。与 json 的功能类似,但是无论是性能,还是数据大小都比 json 要好很多。
protobuf 之所以可以跨语言,就是因为数据定义的格式为.proto
格式,需要基于 protoc 编译为对应的语言。
三. 数据包协议分析
初看 java 层
主要的逻辑是: 把时间戳和每次下拉之后页数自动加 1 后的数据放入到函数中去执行, java 层被混淆的面目全非, 中间掉用了一个 sign 为 native 的方法, 于是换种思路从数据包上面开始分析。
3.1 抓包
拿到这道题的时候受前面几道题目的影响以为直接可以抓到包, 使用 Drony 转发到 charle 上后发现没有这道题的数据包, 初步怀疑使用了其他的协议, 然后在 pc 打开 wireshark 进行数据包的拦截, 同时开启 frida hook 第四题中的 sign。
发现 frida hook 的值和 wireshark 抓到的数据包相同, 这也就坐实了这个数据包为第四题的发包函数。
然后我就想着能不能再找到收到的响应呢?
在 wireshark 输入过滤条件
然后一个一个包来看
确实找到了返回数据。
3.2 数据包分析
于是找来两个不同时间发送的数据包来对比下差异
也就是说结尾位置的为一些重要的参数, 我们能够伪造到然后加上前面的数据段不久可以请求服务器产生数据了?
那么如何伪造这些参数呢?
在数据的 hexdump 中只能看到 sign 的身影, 那么 page 和时间戳的身影跑哪去了, 经过了查阅资料后发现 grpc 数据的传送经过了 protobuf 的编码, 字符串在这里可以显现, 但是时间戳在 hexdump 里面并没有被显现出来。
那么开始编写 protobuf 文件吧
syntax = "proto3";//指定版本为proto3,默认为proto2
message SearchRequest {
uint32 page =1;
uint64 time = 2;
string sign =3;
}
然后执行: protoc --proto_path=./ --python_out=./ test.proto
def bytes2hex(byte_arr: bytes) -> str:
return byte_arr.hex()
import test_pb2
# 实例化协议对象
ser = test_pb2.SearchRequest()
ser.page = 1
ser.time = 1652580021332
ser.sign ="b94a543f66e23656"
# 对数据进行序列化
data = ser.SerializeToString()
print(type(data))
print(bytes2hex(data))
这个时候当事人 1 和当事人 2 都非常开心, 是不是就可以解决了?解决了就可以睡大觉了
然后十分钟: 连接服务器 把 tcp 头部和数据拼接起来发给服务器。。。。。经过实验 失败,服务器会莫名断开连接。
四. sign 加密与 python 代码实现
于是想了下 python 如何 grpc 的请求和服务器交互, 说干就干. 经过了一番查阅资:需要以下条件
服务器的地址和端口 (废话), 前文中我们提到 grpc 那么就有要被执行的函数, 有被执行的函数就得有接受函数执行完的结构。
于是乎 下面的代码就出来了
syntax = "proto3";
package challenge;
message app4 {
uint32 page =1;
uint64 time = 2;
string sign =3;
}
message HelloReply {
repeated string message = 1;
}
service Challenge{
rpc SayHello (app4) returns (HelloReply) {}
}
# -*- coding: utf-8 -*-
import grpc
import data_pb2,data_pb2_grpc
_HOST = '180.76.60.***'
_PORT = '9901'
def run():
conn = grpc.insecure_channel(_HOST + ':' + _PORT)
client = data_pb2_grpc.ChallengeStub(channel=conn)
page_time = "1:1652586112285"
sign = "92979f42250a942b"
page_time = "4:1652593296974"
sign = "f9f5c6fe5b3da911"
page = page_time.split(":")[0]
time = page_time.split(":")[1]
response = client.SayHello(data_pb2.app4(page = int(page),sign = sign,time =int(time)))
print( str(response))
if __name__ == '__main__':
run()
在终端下执行:
# python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. data.proto
即可生成 grpc 和 probuf 协议的文件。
run 一下
发现返回的数据结构怎么这么多位, 服务器抽风了还是我的程序抽风了, 后来 "duoduo" 兄说前面的 004 说明后面有四个值是对的。
于是协议模拟的问题告一段落。
要让整个算法跑出来算 100 页的数据, 还需要 sign 参数
frida 代码如下
var signclass1 = Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment");
signclass1.sign.implementation = function (arg1,arg2) {
console.log("");
console.log("page_time= \""+arg1+"\"");
console.log("sign= \""+this.sign(arg1,arg2)+"\"");
return this.sign(arg1,arg2);
}
发现 sign :
第一个参数为 page: 时间戳。第二个参数就是时间就是时间戳
由于比赛原因 谁先搞完就能排名高, 掏出 unidbg(也想还原来着, 那么短时间不太现实)
写 unidbg 调用
主要代码如下
public String callsign(String input,long j){
List<Object> list=new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(0);
list.add(vm.addLocalObject(new StringObject(vm,input)));
list.add(j);
//Number number=module.callFunction(emulator,0xdf0,list.toArray())[0];
Number number = module.callFunction(emulator, "Java_com_yuanrenxue_match2022_fragment_challenge_ChallengeFourFragment_sign", list.toArray());
return vm.getObject(number.intValue()).getValue().toString();
}
然后排名上升两名 end。
五. 总结
要去看更多的东西才能扩宽自己的眼界, 有些技术不是难, 而是没接触过 (hhh 接触过也不一定会), 还有 "duoduo" 兄 yyds。
我是 BestToYou, 分享工作或日常学习中关于二进制逆向和分析的一些思路和一些自己闲暇时刻调试的一些程序, 文中若有错误的地方, 恳请大家联系我批评指正。