andorid 源码查看地址: Android Code Search AOSPXRef,AndroidXRef
通过android 逆向基础教程一学习了常见 frida hook的一些基本手法,本次接着上次学习案例继续学习frida hook 相关知识点。
hook Getenv 修改str 返回值为"Imyang"即可绕过,直接调用StartActivity执行指定Activity方式直接跳到第八关
因为重点学习Frida hook ,因此侧重 hook 解决以上问题,但实际生活中,以达到目的为重,尤其是相关比赛过程中,因此熟悉阅读 smali 很有必要。
androidkiller 快速修改到关键位置配合 hook 效果也很不错。
if 判断 next 参数bool,类构造函数可对next 修改next 变量,hook够着函数并调用 next=true;
smali 汇编下的构造函数,非常简单,因此修改哪里一眼能看出,熟悉构造函数在Smali 汇编中的声明定义。
frida hook 实现方式如下:
调用系统函数 startActivity 要了解app启动过程,方式为找到ActivityThread-->currentApplication-->getApplicationContext 获取当前上下文(查询android 源码方式)
function hook_MainActivity() {
Java.perform(function() {
var MainActivity = Java.use("com.example.androiddemo.MainActivity");
//frida -U --no-pause -f com.example.androiddemo -l hook.js
//--no-pause -f apk启动之前就把frida的脚本注入进apk进程里
var System = Java.use("java.lang.System");
System.getenv.overload('java.lang.String').implementation = function(name) {
var env = this.getenv(name);
if (name == "USER") {
env = "Imyang";
}
console.log("getenv:", name, env);
return env;
}
var FridaActivity7 = Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity7");
//hook 构造函数
FridaActivity7.$init.implementation = function() {
this.$init();
this.next.value = true;
}
});
}
function call_startActivity() {
Java.perform(function() {
//调用系统的类和函数
var ActivityThread = Java.use("android.app.ActivityThread");
var application = ActivityThread.currentApplication();
var context = application.getApplicationContext();
console.log(context);
var FridaActivity7 = Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity7");
var Intent = Java.use("android.content.Intent");
Java.scheduleOnMainThread(function() {
var intent = Intent.$new(context, FridaActivity7.$new().getClass());
intent.setFlags(0x10000000);
console.log(intent);
context.startActivity(intent);
})
var FridaActivity7=Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity7");
FridaActivity7.$init.implementation=function(){
this.$init();
this.next.value=true;
}
});
}
function main(){
hook_MainActivity();
}
setImmediate(main);
完成通关后,分析下一关的逻辑。
Android studio 编译解密算法(异或)为 Dex push到测试机
public class DecodeUtil {
private final String password = "\u0013YQWZQ\u0012Fx$/a.5a.&";
private String a(String str) {
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length / 2; i++) {
char c = charArray[i];
charArray[i] = (char) (charArray[(charArray.length - i) - 1] ^ 'A');
charArray[(charArray.length - i) - 1] = (char) (c ^ '2');
}
return new String(charArray);
}
}
/*dex 打包
android d8
```shell
AndroidDemo\app\build\intermediates\javac\debug\classes>Local\Android\Sdk\build-tools\30.0.2\d8.bat
adb push
```
在代码实现过程中我们将password 字符串解密,而通过修改smali 获取解密内容也是很容易,当然,修改跳转直接到第九关更没用难度。我们通过修改加密函数做解密 password ,与代码一样,异或的异或回去。 上面对 a加密方法改为解密后,修改传入password 字符串查看日志就可得到解密后的password 日志打印出来。 frida 动态加载dex 为了学习 frida 动态加载dex ,我们将解密算法打包为dex,frida 动态加载dex方式完成解密,因为大多数我们的解密算法没有那么简单。
//动态加载dex openClassFile -->load
function load_dex(){
var DecodeUitlsDex=Java.openClassFile("/data/local/tmp/DecodeUtil.dex");
console.log("DecodeUtilsDex:",DecodeUitlsDex);
Java.perform(function(){
DecodeUitlsDex.load();
var DecodeUtils=Java.use("com.example.androiddemo.DecodeUtil")
console.log(DecodeUtils);
var FridaActivity8=Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity8");
Java.scheduleOnMainThread(function(){
console.log(DecodeUtils.$new().a(FridaActivity8.$new().password.value)); //new dex 中的a方法传入解密字符串password
})
});
}
function hook_FridaActivity8(){
Java.perform(function(){
var FridaActivity8 = Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity8");
FridaActivity8.a.implementation=function(str){
str="go to next check!";
var result=this.a(str);
console.log(str,result);
return result;
}
})
}
注册Class, 注册接口的实现
最后一关通过调用接口方法做判断条件,通过frida 注册class,注册接口的实现check() 返回为真。
//注册Class, 注册接口的实现
function hook_FridaActivity9(){
Java.perform(function(){
var Frida9Interface=Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity9$Frida9Interface");
console.log(Frida9Interface);
var Frida9InterfaceImpl= Java.registerClass({
name:"com.github.lastingyang.androiddemo.Activity.FridaActivity9.Frida9InterfaceImpl",
implements:[Frida9Interface],
methods:{
check(){
console.log("Frida9InterfaceImpl.check");
return true;
}
}
});
var FridaActivity9=Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity9");
FridaActivity9.getInstance.implementation=function(){
console.log("FridaActivity9.getInstance");
return Frida9InterfaceImpl.$new();
}
});
}
打印调用栈
//打印调用栈
function printStackTrace() {
Java.perform(function() {
var Exception = Java.use("java.lang.Exception");
var exception = Exception.$new();
var stackTrace = exception.getStackTrace().toString();
console.log("==========================\r\n" + stackTrace.replaceAll(",", "\r\n")
+ "\r\n==========================");
exception.$dispose();
});
}
function hook_FridaActivity10(){
Java.perform(function(){
var FridaActivity10=Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity10");
FridaActivity10.onCheck.implementation=function(){
printStackTrace();
console.log("FridaActivity10.onCheck");
}
})
}