这篇文章最后以分析UnCrackable-Level1.apk介绍frida脚本的使用,如果大佬们对前面介绍的adb、frida安装已经清楚,则可以直接拉到最后看UnCrackable-Level1.apk的分析。
一、安装frida
mac电脑安装python3,可以通过brew install python3指令进行安装,如下所示
如果觉得github下载速度慢,可以在公众号回复“frida-server”百度云下载,四个版本都打包一起哈 下载完android设备相对应的frida-server后,通过adb push将frida-server发送到android设备中(通常将frida-server保存在/data/local/tmp目录中),如下所示
修改frida-server的权限,使frida-server具有执行权限,如下所示
以后台模式运行frida-server,这样电脑上的frida CLI就能够与frida-server进行交互,我们可以在电脑上使用frida来与android设备中的app交互(当然前提是手机要通过usb数据线连接到电脑),如下所示
二、frida的使用
frida tools主要有Frida CLI、frida-ps、frida-trace、frida-discover、frida-ls-devices、frida-kill等命令工具
除了frida命令行使用外,frida还可以通过python及JavaScript脚本来hook android设备中的应用程序
下载安装UnCrackable-Level1.apk
https://github.com/OWASP/owasp-mstg/tree/master/Crackmes/Android/Level_01
运行UnCrackable-Level1,观察app的功能,可以发现该app主要是要校验我们输入的字符串是否正确。并出现了一个"Root detected!"弹框,表示app检测到我们的android设备已root,如下所示
确认我们需要完成任务即绕过app的root检测和找出app校验的正确的字符串是什么,现在可以开始分析app
静态分析app,可以通过jeb、jadx、Androidkiller等工具进行分析,这里我就使用jadx静态分析app。我们先分析app的检测android设备是否root的功能,如下所示
顺带看一下app中的检测app是否被调试的方法
主要有两种方式绕过root检测方法
setImmediate(function(){ //防止超时
console.log("[*] Staring script");
Java.perform(function(){ //JavaScript代码成功被附加到目标进程时调用,我们要hook app的代码都在Java.perform底下写,是个固定格式
//我们通过两种方法来绕过app的检测android设备是否root,如果root则退出app
//方法一 修改我们上面分析的3个root检测函数的返回值 使他们始终返回false
console.log("[*] Hooking calls to root detect");
//1.修改方法a的返回值,使返回值为false。方法a通过检测PATH(android系统环境变量)中是否有su文件来判断android系统是否被root
var rootDetect = Java.use("sg.vantagepoint.a.c"); //Java.use用于声明一个Java类 这里我们声明root检测的类
//类.函数.overload(参数类型).implementation = function(形参名称){
rootDetect.a.implementation = function(){ //这里我们需要hook的是rootDetect类中的a方法 a方法没有参数因此overload可以不用写
//function中不用写形参名称
console.log("-----hook su finder-----");
var suFinder = this.a(); //执行a方法并返回a的返回值Boolean值
console.log("su finder original return value is: ",suFinder.toString()); //打印返回值
suFinder = false; //修改返回值为false
console.log("su finder new return value is: ",suFinder.toString()); //打印修改的返回值
return suFinder; //返回我们修改的值 使a函数始终返回false
}
//2.修改方法b的返回值,使返回值为false。方法b通过检测Build.TAGS中是否包含字符串"test-keys"来判断android系统是否被root
rootDetect.b.implementation = function(){ //这里我们需要hook的是rootDetect类中的b方法 b方法没有参数因此overload可以不用写
//function中不用写形参名称
console.log("-----hook test-keys finder------");
var testKeysFinder = this.b(); //执行b方法并返回b的返回值Boolean值
console.log("test-keys finder original return value is: ",testKeysFinder.toString()); //打印返回值
testKeysFinder = false; //修改返回值为false
console.log("test-keys finder new return value is: ",testKeysFinder.toString()); //打印修改的返回值
return testKeysFinder; //返回我们修改的值 使b函数始终返回false
}
//3.修改方法c的返回值,使返回值为false。方法c通过检测指定路径下是否包含指定的文件来判断android系统是否被root
rootDetect.c.implementation = function(){ //这里我们需要hook的是rootDetect类中的c方法 c方法没有参数因此overload可以不用写
//function中不用写形参名称
console.log("-----hook superuser file finder-----");
var superuserFileFinder = this.c(); //执行c方法并返回c的返回值Boolean值
console.log("superuser file finder original return value is: ",superuserFileFinder.toString()); //打印返回值
superuserFileFinder = false; //修改返回值为false
console.log("superuser file finder new return value is: ",superuserFileFinder.toString()); //打印修改的返回值
return superuserFileFinder; //返回我们修改的值 使c函数始终返回false
}
//方法二 修改System.exit函数使app不退出 当app检测到android设备root时则会调用System.exit函数退出app
/*console.log("[*] Hooking calls to System.exit");
var exitClass = Java.use("java.lang.System"); //声明System类
exitClass.exit.implementation = function(){ //这里我们需要hook的是System类中的exit方法 exit方法没有参数因此overload可以不用写
//function中不用写形参名称
console.log("[*] System.exit called");
}*/
//hook app正确字符串生成算法得到解密后的正确字符串
console.log("[*] Hooking calls to AES decrypt");
var aesDecrypt = Java.use("sg.vantagepoint.a.a");
aesDecrypt.a.overload('[B',"[B").implementation = function(arg1,arg2){
console.log("[*]Hook a.Class");
var decryptValue = this.a(arg1,arg2);
var secret = '';
for(var i=0;i<decryptValue.length;i++){
secret+=String.fromCharCode(decryptValue[i]);
}
console.log("secret is : " + secret);
return decryptValue;
}
});
})
verifyString.py
下面是执行绕过app root检测方法脚本后,得到的结果,如下所示
为了验证app root检测方法的正确性,我们也可以到android设备中上面检测方法涉及的目录查看是否存在相应的文件,如下所示
我们已经分析完app的root检测功能,现在分析app的verify算法,查看app字符串校验的算法,确认app需要的正确的字符串是啥,如下所示
分析完verify校验算法后,我们即可通过frida hook最后的aes解密算法,得到它解密后的返回值再转成String后,就是我们想得到的正确的校验字符串,代码如下
下面是执行完aes解密方法脚本后,得到的结果,如下所示
综上所述,我们已经通过frida脚本完成了绕过app的检测及hook app校验字符串的方法从而得到真正的字符串。感兴趣的大佬可以试一试,完成项目代码可以在公众号回复“codeUncrackable1Test”,通过百度云下载。