复现一下这题,因为手头有环境可以学学。强网的时候根本没看。
可以还原出apk
发现有个域名,下面还有个URL
虽然主活动是com.silence.scoreboard.SplashActivity
,但是我们先看base的东西
首先是BaseActivity,去BaseApplication注册了一个广播
然后有一个MyReceiver去接收广播消息
跟进BaseApplication
调用了一个scoreboard
的链接库
同时在onCreate
的时候,会有一个RootUtils.check()
和一个OoOO.OOOOOooo()
RootUtils一看就知道是检测root权限的,这个OoOO.OOOOOooo应该是链接库里的方法,也就不去管了
再来到主活动SplashActivity
进行分析
在onCreate
的时候进行isLogin()
的判断
如果登录了,就去执行autoLogin
自动登录,有个回调函数,搞过安卓网路开发的都知道这个是Retrofit
那么思路先去全局搜索一下http
找到RetrofitHelper
找到了服务器的基地址http://47.93.244.181/re/
返回到主活动,继续分析
登录成功就去MainActivity
,失败就去LoginActiviy
顺着HttpRequest.login,去看API接口
有个GetFlag.php
需要code、account、username
结合app下载的界面显示,超过9999分就可以获取flag
register,密码用md5加密后post
login,account被encrypt
加密了,密码还是md5的形式
autologin,多了一个code,account和username都被加密了
submit,提交分数,在贪吃蛇的界面有调用
addFriend,添加好友,需要一个code来添加
getScoreBoard,查看排行榜
getFlag,需要code,account,username
先去注册一个,获得了一个code
去scoreboard看看,有users和admins,因为是复现,所以我怀疑users都是比赛时做出来的,直接把分数改成大于9999了
admins中,只有第一个的分数是9999
因为getFlag这个api,不需要密码的,只需要account和code还有一个username
观察到registerActivity中,注册后会把注册后的json信息回调给setUserInfo方法
这里调用了decrypt,会想起在注册或者login后,会对accouont、username进行encrypt
那么,我们先去尝试加个好友,因为加好友后会显示部分信息
api测试,发现给的太多了,甚至给了account
这个account和username肯定是经过encrypt的,那么思路有了,直接hook这个OooOoo0.decrypt
,把加密后的这个admin的account和username都调用一下这个decrypt,那么可以得到admin的account然后获取flag
因为这个app检查了root权限,我手头上的机子用的Magdisk22,可以使用Magdisk Hide功能隐藏root权限,所以打开app是没问题的。
但是经过测试发现,如果先打开frida-server,再启动app,直接闪退
那么换个思路,先打开app,在开启frida-server,使用attach模式来附加到进程上面
hook调用decrypt和encrypt
的ts脚本,需要编译成js
const encrypt = (s: any) => {
let res = ''
Java.perform(() => {
res = Java.use("com.silence.utils.OooOoo0").encrypt(s)
})
return res
}
const decrypt = (s: any) => {
let res = ''
Java.perform(() => {
res = Java.use("com.silence.utils.OooOoo0").decrypt(s)
})
return res
}
rpc.exports = {
encrypt: encrypt,
decrypt: decrypt
}
python调用frida
import sys
import frida
def on_message(message, data):
if message['type'] == 'send':
print(f"[frida hook] : {str(message['payload'])}")
else:
print(f"[frida hook] : {str(message)}")
session = frida.get_usb_device().attach("ScoreBoard")
with open("./ts_script/js/test.js",encoding="utf-8") as f:
script = session.create_script(f.read())
script.on("message", on_message)
script.load() # 加载脚本
tmp = script.exports.encrypt("test114")
print(tmp)
tmpp = script.exports.decrypt(tmp)
print(tmpp)
account = script.exports.decrypt("SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll/Q4Q=")
print(account)
username = script.exports.decrypt("IbaoQT/3eTXIjHDJ2L5TQE==")
print(username)
# sys.stdin.read()
tmp
和tmpp
是用来测试加密解密是否成对
account和username两个解密的都是addFriend的API获取的,直接解密
拿到账号&Od987$2sPa?>l
把参数放到api里,直接获取