猿人学APP逆向对抗第四题
第四题调用System.currentTimeMillis
获取毫秒时间戳,然后调用com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment.sign
native函数生成sign值,传入的参数是page+":"+时间戳。
gRPC抓包#
由于第四题使用了gRPC
进行网络请求,gRPC
基于HTTP2.0并使用protobuf序列化。charles可以抓取到HTTP2.0的数据但是好像并无法自动解析。
正好最近微软的新bing很火,问问他该如何解析gRPC
协议数据包。他给出了3种方法,但是很明显第二种方法不对,因为gRPC
协议基于HTTP2
,所以其发送的数据是以HTTP2
协议的格式,protobuf序列化的数据存放在DATA帧中,如果把所有的数据都按照protobuf协议的格式进行解析肯定不对。
继续问他,说明charles
确实并不能解析HTTP2,只能使用wireshark
去解析HTTP2从而解析gRPC。
电脑开启热点并使用手机连接,wireshark选择手机ip对应的本地连接后即可进行抓包。
查看抓包数据可以看到post信息,wireshark
默认不识别HTTP2.0
,需要右键Decode As主动设置。
设置HTTP2.0之后就可以看到post的数据,与hook sign函数打印的信息对比发现其传递了三个参数分别是page
, time
, sign
。
这里gRPC使用的是protobuf序列化传递二进制数据,可以编写proto文件让wireshark
识别protobuf中对应的字段。
syntax = "proto3";
package challenge;
message app4 {
uint32 page =1;
uint64 time = 2;
string sign =3;
}
message Data {
repeated string value = 1;
}
service Challenge{
rpc SayHello (app4) returns (Data) {}
}
点击编辑中的首选项,设置protobuf
协议的proto文件搜索路径为刚才编写的文件。
设置完成之后就可以看到wireshark
解析出来protobuf中的数据信息名称,post请求右键追随流可以查看每次post请求会返回页面所有的数据value。
所有就有两个思路解题,第一种思路就是使用python使用gRPC请求所有页面的数据,第二种思路和前三题一样主动调用app的发包函数并拦截收包函数获取返回值。
思路一#
首先利用之前编写的proto文件,运行命令python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. .\challenge.proto
生成gRPC文件。
frida 主动调用sign函数
function callsign(string1, time){
var sign_value;
Java.perform(function(){
var ChallengeFour_instance;
Java.choose("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment", {
onMatch:function(instance){
ChallengeFour_instance = instance;
},onComplete:function(){}
})
sign_value = ChallengeFour_instance.sign(string1, time);
})
return sign_value;
}
rpc.exports = {
callsign: callsign,
};
py脚本中利用rpc主动调用sign函数生成sign值,使用gRPC请求页面数据并计算和。完整脚本如下:
import grpc
import time
import frida
import challenge_pb2,challenge_pb2_grpc
#连接设备,附加进程
rdev = frida.get_usb_device()
session = rdev.attach("com.yuanrenxue.match2022")
#加载脚本
with open("challenge.js") as fp:
script = session.create_script(fp.read())
script.load()
def main():
conn = grpc.insecure_channel("180.76.60.244:9901")
client = challenge_pb2_grpc.ChallengeStub(conn)
sum = 0
page = 1
while page <= 100:
#毫秒时间戳
timestamp = int(time.time() * 1000)
arg1 = str(page) + ":" + str(timestamp)
arg2 = timestamp
#call sign
sign_value = script.exports.CallSign(arg1, arg2)
print(page)
print(sign_value)
#post request
response = client.SayHello(challenge_pb2.app4(page=page, sign=sign_value, time=timestamp ))
#get value
value_array = response.value
for value in value_array:
sum = sum + int(value[2:])
page = page + 1
print(sum)
if __name__ == '__main__':
main()
思路二#
思路二主动调用发包函数com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment.lambda$initListeners$1
请求所有页面数据,hook收包函数得到返回数据并计算和。完整脚本如下:
function main(){
Java.perform(function(){
Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment").sign.overload('java.lang.String', 'long').implementation = function(arg1, arg2){
console.log("\narg1 :", arg1);
console.log("arg2 :", arg2);
var result = this.sign(arg1, arg2);
console.log("result :", result);
return result;
}
var ChallengeFour_instance;
Java.choose("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment", {
onMatch:function(instance){
ChallengeFour_instance = instance;
console.log(ChallengeFour_instance);
},onComplete:function(){}
})
var Smart_instance;
Java.choose("com.scwang.smartrefresh.layout.SmartRefreshLayout",{
onMatch:function(instance){
Smart_instance = instance;
console.log(Smart_instance);
},onComplete:function(){}
})
var sum = 0;
Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment$OooO0O0").OooO0oO.overload('oOO00O.OooO0OO').implementation = function(arg1){
var class1 = Java.cast(arg1, Java.use("oOO00O.OooO0OO"));
var class2_array = class1.OooO0O0().toArray();
for(var i = 0; i < class2_array.length; i++){
var class2 = Java.cast(class2_array[i], Java.use("oOO00O.OooO0o"));
var value_string = class2.OooO0O0();
sum = sum + int64(value_string);
}
}
for(var i = 0; i < 100; i++){
//page.value
ChallengeFour_instance.OooO0O0.value = i;
ChallengeFour_instance.lambda$initListeners$1(Smart_instance);
Thread.sleep(1)
}
console.log("sum is ", sum);
})
}
setImmediate(main)
参考链接 :
https://jingwei.link/2018/10/02/grpc-wireshark-analysis.html
https://blog.csdn.net/luo15242208310/article/details/122911526
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】