Android爬蟲比賽 第一關解析
VSole2023-01-14 11:11:54

一、環境
frida 12.8.20
python 3.8.10
jadx-gui-1.2.0
fiddler
二、實戰步驟
1、安裝APP,來到第一關,翻頁時抓包。

jadx打開APP ,根據page= 查找到 com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment 類。


此處有sign函數,很大幾率為翻頁調用函數,hook當前函數查看 this.page 和 oooOO0O.OooO00o().longValue()的值:
function hook_ChallengeOneFragment(){ //訪問內部類函數 Java.perform(function(){ var InnerClasses = Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment"); // console.log(InnerClasses); InnerClasses.lambda$initListeners$2.overload('o00O000.OooOO0O').implementation = function(age){ console.log("this.page.value:",this.page.value);//查看page的值 console.log("age.OooO00o().longValue() :",age.OooO00o().longValue());//查看值 console.log("age:",age)//查看參數 var res = this.lambda$initListeners$2(age)//運行函數 console.log("res:",res,"type:",res.$className);//返回值和返回值類型 var Map = Java.use('retrofit2.adapter.rxjava2.BodyObservable');//根據返回值類型創建對象 var NewP = Java.cast(res, Map); //將返回值轉成相應類型 console.log("NewP:",NewP.toString());//輸出返回值 return res; }; });}

分析代碼:
StringBuilder 為可變字符串。
根據代碼得出 sb的值為頁碼+時間戳 "page=21652931584"。
再次hook Sign函數查看參數和返回值并與fiddler對比。
function hook_SignClass(){ //訪問內部類函數 Java.perform(function(){ // 訪問內部類時,在當前類后加$符號,后跟內部類名 var InnerClasses = Java.use("com.yuanrenxue.match2022.security.Sign"); // console.log(InnerClasses); InnerClasses.sign.overload('[B').implementation = function(arge1){ console.log("參數和參數類型:",arge1,arge1.$className);//數組類型一般會返回null console.log("數組類型轉碼:",JSON.stringify(arge1));//數組類型可嘗試使用json解析 var res = this.sign(arge1);//運行函數 // return true; console.log("res",res);//返回值 return res; }; });}


此時已經可以斷定,這個Sign就是翻頁的加密函數 。
根據jadx反匯編代碼:
new Sign().sign(sb.toString().getBytes(StandardCharsets.UTF_8))
我們用python實現一下。
time_ = '1652932157's = 'page=1' + time_print("s:",s)bArr = [x for x in bytearray(s,'utf_8')]print("bArr:",bArr) #s: page=11652932157#bArr: [112, 97, 103, 101, 61, 49, 49, 54, 53, 50, 57, 51, 50, 49, 53, 55]
此時直接調用sign生成加密參數,抓取100頁的值相加得出flag:
#!/usr/bin/env python# -*- coding: utf-8 -*- import fridaimport requestsimport time #發送接收frida_js信息def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) js = open('hook.js', 'r', encoding='utf8').read() #讀取frida腳本 session = frida.get_remote_device().attach('com.yuanrenxue.match2022')#根據包名啟動APP script = session.create_script(js)script.on('message', on_message)script.load()#加載frida腳本 if __name__ == '__main__': time_ = int(time.time())#獲取世家戳 header2 = { 'Accept-Language':'zh-CN,zh;q=0.8', 'User-Agent':'Mozilla/5.0 (Linux; U; Android 10; zh-cn; Mi9 Pro 5G Build/QKQ1.190825.002) AppleWebKit/533.1 (KHTML, like Gecko) Version/5.0 Mobile Safari/533.1', 'Content-Type':'application/x-www-form-urlencoded', 'Content-Length':'57', 'Host':'appmatch.yuanrenxue.com', 'Connection':'Keep-Alive', 'Accept-Encoding':'gzip', 'Cache-Control':'no-cache', } count = 0 #記數 for i in range(1,101): s = f'page={i}' + str(time_) bArr = [x for x in bytearray(s,'utf_8')] res = script.exports.callsecretfunctionedy(bArr) #調用frida_js函數獲取加密參數 payload = { 'page': str(i), 'sign': res, 't': time_, } r = requests.post("https://appmatch.yuanrenxue.com/app1", data=payload, headers = header2, verify = False ) data = r.json()['data'] for v in data: count += int(v['value']) print("flag count:",count)
var result;function callDYFun(bArr) { //定義導出函數 Java.perform(function () { console.log("bArr:",bArr); var ss = Java.use('com.yuanrenxue.match2022.security.Sign'); var str = Java.use("java.lang.String"); var res = str.$new(ss.$new().sign(bArr)); result = str.valueOf(res) console.log("result:",result); }); return result;//返回值給python}rpc.exports = { callsecretfunctionedy: callDYFun,};
類中有兩個函數一模一樣lambda$initListeners$2和lambda$initListeners$0 。
經測試調用的是 lambda$initListeners$2。
VSole
網絡安全專家