猿人学APP逆向对抗第四题

第四题调用System.currentTimeMillis获取毫秒时间戳,然后调用com.yuanrenxue.match2022.fragment.challenge.ChallengeFourFragment.signnative函数生成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

posted @ 2023-03-15 02:45  怎么可以吃突突  阅读(281)  评论(0编辑  收藏  举报