环境说明:
Nexus 6P Android8.1 已root
抓包软件 Http Canary
frida=12.8.10
frida-tools=5.4.0
objection=1.8.4
猿人学APP 1.0.31
Flask=1.1.3
分析思路 先抓包看下是第一题怎么发的包
1 2 3 post 请求 dst https: 编码参数 page = 1 &sign =19f b8a2eb72e4710109759fd992852d4&t =1650780086008
打开Jadx 使用sign 作为搜索关键词
一个一个打开看 然后看到第三个的时候可以确定发包的是用的retrofit 类似的包做的请求
请求的是是会把Field
中对应的值做为键来编码
我们这里直接邮件0oo0 查找用法
定位如图的函数
最后这个函数调用了 OooO(Integer.valueOf(this.f7810OooO0o0), OooO2, Long.valueOf(currentTimeMillis)), new OooO00o(o00o0002));
来发送最终的请求
格式和API 中定义的接口请求大体相似
1 2 3 f7810OooO0o0 就是page 的变量名 第一次请求值是1 请求第二页page 值+1 t = currentTimeMillis sign = new Oooo000 ().OooO(byteArray ("page=1" + str (t )))
加密函数就是这个new Oooo000().OooO
验证 我们使用Objection 来做一个快速验证
1 2 3 object -g com.yuanrenxue.challenge explore android hooking watch class_method o00oO00o.Oooo000.OooO --dump-args --dump-backtrace --dump-return
然后在手机上点击进入第一题的页面触发Hook 函数 我们可以看到结果输入了sign 的值可以拿着这个值和抓的包对下,确定sign 值是这个 ,那也就说明我们找到了这一题的加密函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 com.yuanrenxue.challenge on (google: 8.1 .0 ) [usb] # android hooking watch class_method o00oO00o.Oooo000.OooO --dump-args --dump-backtrace --dump-return (agent) Attempting to watch class o00oO00o.Oooo000 and method OooO .(agent) Hooking o00oO00o .Oooo000 .OooO ([B) (agent) Registering job 80ugx93pznf . Type : watch-method for : o00oO00o.Oooo000.OooO com.yuanrenxue.challenge on (google: 8.1 .0 ) [usb] # (agent) [80 ugx93pznf] Called o00oO00o.Oooo000.OooO([B) (agent) [80 ugx93pznf] Backtrace: o00oO00o.Oooo000.OooO(Native Method ) com .yuanrenxue .challenge .fragment .challenge .ChallengeOneFragment .lambda $initListeners $0(proguard-dict.txt:6) com .yuanrenxue .challenge .fragment .challenge .ChallengeOneFragment .OooOOoo (Unknown Source:0) o00o0oOO .o000 .OooO0OO (Unknown Source:2) com .scwang .smartrefresh .layout .SmartRefreshLayout $OooO0o .onAnimationEnd (proguard-dict.txt:4) android .animation .Animator $AnimatorListener .onAnimationEnd (Animator.java:552) 6) (agent) [80ugx93pznf ] Arguments o00oO00o .Oooo000 .OooO ([object Object]) (agent) [80ugx93pznf ] Return Value : 8 fb74c67e2a70aa5dd7beec6cbfecad2
RPC封装 我这里尝试过把JAVA 代码放到一个项目里打成jar包来调用,但是o00o0oOO.o000.OooO0OO
这个加密函数在APP 中运行的结果和在JAVA中运行的结果不一致。猜测里面是做了环境检查的,我这里不想正面硬钢了,所以选择使用RPC远程调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function getsign (arg ) { var res; Java .perform (function ( ) { send ("start rpc" ) const myClass = Java .use ("o00oO00o.Oooo000" ); const j_string = Java .use ('java.lang.String' ); const ret = j_string.$new(arg).getBytes ('UTF-8' ); res = myClass.$new().OooO (ret); }) return res } rpc.exports = { getsign : getsign };
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 30 31 32 33 34 35 36 37 38 39 // server.pyimport jsonimport fridafrom flask import Flask, request hook = open ('rpc.js' , 'r' , encoding='utf-8' ).read()def on_message (message, data ): if message['type' ] == 'send' : print (f"send message:{message['payload' ]} " ) elif message['type' ] == 'error' : print (message['stack' ]) process = frida.get_usb_device().attach('com.yuanrenxue.challenge' ) script = process.create_script(hook) script.on('message' , on_message) script.load() app = Flask(__name__)@app.route('/getsign' , methods=['POST' ] ) def decrypt_class (): data = request.get_data() json_data = json.loads(data.decode("utf-8" )) page = json_data.get("page" ) t = json_data.get("t" ) s = "page=" +str (page) + t print (s) res = script.exports.getsign(s) return resif __name__ == '__main__' : app.run()
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 30 31 32 33 // app01 脚本import jsonimport timeimport requests as requests headers = { 'user-agent' : "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Nexus 6P Build/OPM7.181105.004) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30" , "content-type" : "application/x-www-form-urlencoded" }if __name__ == '__main__' : s = [] for i in range (1 , 101 ): currentTimeMillis = str (int (round (time.time() * 1000 ))) data = {"page" : str (i), "t" : currentTimeMillis} sign = requests.post(url='http://127.0.0.1:5000/getsign' , json=data).text data["sign" ] = sign res = requests.post(url='https://www.python-spider.com/api/app1' , data=data, headers=headers).text content = json.loads(res) s.extend([i['value' ].strip('\r' ) for i in content['data' ]]) print (s) print (sum (int (i) for i in s))