第一步肯定还是抓包,这里不能用fiddler,因为不是http协议,刚好试一下r0captcha,使用教程可以参考:

frida+r0capture安卓应用层抓包通杀 – N_schema

先启动firda-server,配置接口转发,然后 frida-ps -R 确认连接

没问题后,切换到r0capture目录,运行命令

1
python r0capture.py -U -f com.yuanrenxue.match2022 -v -p yuanrenxue_20230105.pcap

就会自动启动目标app了,观察日志:

  • 发送包

image.png

  • 数据包

image.png

也可以把保存的 yuanrenxue_20230105.pcap 文件拖进 wireshark 分析

  • 发送包

image.png

  • 数据包

image.png

这里可以先确认发送包的几点信息

  • host为:180.76.60.244:9901
  • 路径为:/challenge.Challenge/SayHello
  • 提交数据:a2f25d9111c3f20c

hook一下ChallengeFourFragment的sign函数,然后对比抓包结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function main(){
console.log("脚本加载成功");
Java.perform(function() {
let ChallengeFourFragment = Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment");
ChallengeFourFragment["sign"].implementation = function (str, j) {
console.log('参数str为:' + str);
console.log('参数j为:' + j);
let ret = this.sign(str, j);
console.log('结果为:' + ret);
return ret;
};
});
}
setImmediate(main)

image.png

image.png

结果一致,结合前面几道题目,表单数据应该和 page、时间戳、sign结果 有关

然后就是用python来实现grpc了,首先编写yxr_grpc.proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
syntax = "proto3";

package challenge;

service Challenge{
rpc SayHello(RequestMessage) returns(ResponseMessage){}
}

message RequestMessage{
int32 page = 1;
int64 t = 2;
string sign = 3;
}

message ResponseMessage{
repeated Item data = 1;
}

message Item{
optional string value = 1;
}

有三个地方需要对着改,其他的照抄就行了

image.png

然后运行命令

1
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. yxr_grpc.proto

本地就多生成了两个文件

image.png

然后就可以来写爬虫了,可以简单理解成平时用的requests请求替换成grpc请求

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
import yxr_grpc_pb2
import yxr_grpc_pb2_grpc
import grpc
import time
import re

from frida_rpc import script


def main():
total = 0
target = "180.76.60.244:9901"
for page in range(1, 101):
with grpc.insecure_channel(target) as channel:
client = yxr_grpc_pb2_grpc.ChallengeStub(channel=channel)
req_data = yxr_grpc_pb2.RequestMessage()
req_data.page = page
ts = int(time.time()) * 1000
req_data.t = ts
req_data.sign = script.exports.main(f"{page}:{ts}", ts)
response = client.SayHello(req_data)
data = re.findall(r'"(\d+)"', str(response))
nums = list(map(int, data))
total += sum(nums)
print(f"前{page}页总和为:", total)


if __name__ == '__main__':
main()

这里需要结合frida rpc来调用sign函数,hook代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var str
var j
var result
function main(str, j) {
console.log("Script loded successfully")
console.log(str)
Java.perform(function () {
var clazz = Java.use('com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment')
console.log("调用类成功")
var instance = clazz.$new()
console.log("创建实例成功")
result = instance.sign(str, j)
console.log(result)
})
return result
}
rpc.exports = {
main: main
}

挑战成功!🎇🎇🎇

image.png

参考资料:

猿人学2022安卓逆向对抗比赛第四题分析_贫穷斯蒂芬的博客-CSDN博客

猿人学安卓逆向对抗比赛(1-5题)_渔滒的博客-CSDN博客_猿人学11题