前言:
本文章仅学习研究,如若侵权,请联系第一时间进行删除
准备:
app版本:8.1.0.33
工具:frida
一般我们都用jadx查看xml文件,得到app的包名,还可以使用adb命令,来查看包名
adb shell pm list packages -3
Frida检测:
使用frida spawn 模式启动app,app直接闪退了,猜测存在frida检测
这里有几篇大佬的过检测文章,感兴趣的可以研究一下,强烈推荐宝藏论坛 -- 看雪论坛
通过bilibili分析libmsaoaidsec.so的环境检测-Android安全-看雪-安全社区|安全招聘|kanxue.com
[原创] frida常用检测点及其原理--一把梭方案-Android安全-看雪-安全社区|安全招聘|kanxue.com
[原创]绕过爱奇艺新版libmsaoaidsec.so Frida检测-Android安全-看雪-安全社区|安全招聘|kanxue.com
不过 本次app 的frida检测并不是很变态,使用hluda就可以轻松绕过,感谢大佬的分享
Releases · hzzheyang/strongR-frida-android · GitHub
分析:
通过登录接口,发现再表单里有个sign字段,每次请求登录都不一样,这个就是校验的参数,我们来看看再哪里生成的
逆向:
因为加密在so,我们直接关注so,先试试通用脚本,能否找到这个生成位置
function hook_register(name, address) {
Interceptor.attach(address, {
onEnter: function (args) {
console.log(" vvv-------------------------------------------------vvv ")
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"))
console.log(name, ": ", args[1].readCString())
console.log(" ^^^-------------------------------------------------^^^ \n\n")
}, onLeave: function (retval) {
}
})
}
function hook_NewStringUTF() {
var hkFunc = "NewStringUTF"
var symbols = Process.getModuleByName("libart.so").enumerateSymbols(); // 枚举所有符号
for (let i = 0; i < symbols.length; i++) {
var symbol = symbols[i]
if (symbol.name.indexOf("CheckJni") == -1 && symbol.name.indexOf(hkFunc) != -1) {
console.log(symbol.name, symbol.address)
hook_register(hkFunc, symbol.address)
}
}
}
直接就可以hook到,省了不少事情,通过堆栈,可以看到他是在libNativeHelper.so中生成的,我的手机是64位的,所以将 lib/arm64-v8a 文件夹下的libNativeHelper.so 拖出来,并使用ida64打开,直接搜索位置
将a1一下数据类型,再看一下代码就清晰了
我们先简单的分析一下,v4是由s而来,s由v14和v15拼接而来,再向上,v15只能看到初始化,没有别的有用线索了,重点关注一下v14
从表面看,他好像是一个md5,是不是标准的呢,hook一下MD5Final看看,查看日志 ,注意我的这个版本还有一层,需要再进去
function print_arg(addr) {
var module = Process.findRangeByAddress(addr)
if (module != null) return hexdump(addr, {length: 32}) + "\n";
return ptr(addr) + "\n";
}
function hook_1() {
var soAddr = Module.findBaseAddress("libNativeHelper.so")
var sub_11668 = soAddr.add(0x12588)
Interceptor.attach(sub_11668, {
onEnter: function (args) {
this.arg0 = args[0]
this.arg1 = args[1]
this.arg2 = args[2]
console.log(" 进入时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}, onLeave: function (retval) {
console.log(" 离开时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}
})
}
通过日志分析,参数1,也就是buffer,将来的结果存放地,参数2,是上下文,参数3是长度
再去hook MD5Update
function print_arg(addr) {
// 这里可能有bug,如果传来的是一个jString,可能会报错
var module = Process.findRangeByAddress(addr)
if (module != null) return hexdump(addr) + "\n";
return ptr(addr) + "\n";
}
function hook_1() {
var soAddr = Module.findBaseAddress("libNativeHelper.so")
var sub_11668 = soAddr.add(0x11668)
Interceptor.attach(sub_11668, {
onEnter: function (args) {
this.arg0 = args[0]
this.arg1 = args[1]
this.arg2 = args[2]
console.log("12588 : 进入时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}, onLeave: function (retval) {
console.log("12588 : 离开时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}
})
var sub_12588 = soAddr.add(0x12588)
Interceptor.attach(sub_11668, {
onEnter: function (args) {
this.arg0 = args[0]
this.arg1 = args[1]
this.arg2 = args[2]
console.log("12588 : 进入时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}, onLeave: function (retval) {
console.log("12588 : 离开时 ---------------------------------------- ")
console.log(print_arg(this.arg0))
console.log(print_arg(this.arg1))
console.log(print_arg(this.arg2))
}
})
}
再次观察日志,参数1是上下文,参数2,看起来像明文,中间有我输入的手机号,拿到加密网站试试,看看是否是标准md5
aaghcaptchaReqbf86bb305f98419985417153313461WOOpS79PEz4=1888888ef2vx#sf*^FlklSD*9sdf(m$&qw%d7po
可以看到,加密结果与抓包的一致,那么他就是一个标准md5了
通过对明文的分割,发现与抓包的data相同,只是多了一串东西,再次请求一下看看最后是否会变
再次hook的结果
最后一串是固定的,那么参数的来源我们就都知道了,对表单中 captcha、captchaid、dateline、password、usename、固定字符串 进行拼接,再进行md5,就可以得到sign值了
结语:
回到一开始观察的部分,因为我们hook md5 直接就看到了结果,后续的操作,并没有影响结果,所以我们可以不用关心他,也就不用关心v14和v15怎么来的,
在逆向so的时候,可以从结果向上hook的方式,来快速定位关键部分,有时候的so很长很吓人,但是关键点可能就一小部分,ida提供的伪c也只是参考,要耐心,敢于尝试,才能拨云见日