介绍

下载地址:

DERE-ad2001/Frida-Labs:该仓库包含一系列学习 Frida for Android Exploitation 的挑战。 — DERE-ad2001/Frida-Labs: The repo contains a series of challenges for learning Frida for Android Exploitation. (github.com)

image-20240727173730434

介绍

项目中包含了11个不同的实战案例,分别从java层到Native层,介绍了常见的Frida API使用场景:

  • challenge 0x01:hook普通方法
  • challenge 0x02:调用静态方法
  • challenge 0x03:更改变量的值
  • challenge 0x04:创建实例对象
  • challenge 0x05:在现有实例上调用方法
  • challenge 0x06:调用带有对象参数的方法
  • challenge 0x07:hook构造函数
  • challenge 0x08:hook so层函数
  • challenge 0x09:更改so层函数返回值
  • challenge 0x0A:调用原生函数
  • challenge 0x0B:使用 X86Writer 和 ARM64Writer 修补汇编

challenge 0x01

image.png

1、提示【Try again】。使用jadx反编译后打开,定位到关键代码处:

  • 可以直接搜索 “Try again”,适用于代码较多的情况下

image.png

image.png

  • 代码比较少,可以直接看MainActivity类

image.png

image.png

2、分析代码,可以先定位到 check 函数

当(i * 2) + 4 == i2的时候,可以执行下一步的代码

(i * 2) + 4 == i2

image.png

3、查看调用了check函数的地方,定位到了 oncreate 函数

image.png

MainActivity.this.check(i, Integer.parseInt(obj));

其中参数 i 和 Integer.parseInt(obj)分别为:

final int i = get_random();   //通过get_random得到
String obj = editText.getText().toString(); //用户输入

3、所以,可以得到逻辑为:

通过get_random()函数得到的随机值,经过运算后,得到我们输入的值即可通过校验。

所以,这块只需要hook掉 get_random()函数,让他返回一个固定值即可。

image.png

4、Frida代码如下:

function main(){
Java.perform(function(){
var className = Java.use("com.ad2001.frida0x1.MainActivity");
var method = className.get_random;

method.implementation = function(){
console.log("get_random function called");
console.log("Returning 5");
return 5;
}
});
}

setImmediate(main);

直接让 get_random 函数的返回值为5,则用户输入应该为 5*2+4=14

image.png

challenge 0x02

image.png

1、定位到MainActivity类中,找到了get_flag函数

image.png

2、全局搜索,没有发现调用 get_flag函数的地方,也就是说,这块定义了一个函数,但是没有做引用

image.png

3、所以,这块使用Frida调用 get_flag函数,并且要求传入的参数为 4919

image.png

4、代码如下:

function main(){
Java.perform(function(){
var a = Java.use("com.ad2001.frida0x2.MainActivity");

a.get_flag(4919); // method name
});
}

setImmediate(main);

image.png

5、也可以不写脚本,直接frida中输入代码hook即可:

image-20240727175406935

challenge 0x03

image.png

1、jadx查看MainActivity类,定位到了onClick方法:

image.png

2、查看代码逻辑,当Checker.code == 512的时候,执行后续代码,当不等于512的时候,返回 try again!

定位到Checker.code处:

image.png

code是一个静态成员变量。

3、这块有两种方法进行HOOk:

①直接hook修改静态成本变量Checker.code的值

②hook increase方法,使用for循环执行 512/2=216次

方法一:Hook成员变量

function main(){
Java.perform(function(){
var a = Java.use("com.ad2001.frida0x3.Checker"); // class reference
a.code.value = 512;
});
}

setImmediate(main);

image.png

方法二:Hook对应方法

function main(){
Java.perform(function(){

//方法一
// var a = Java.use("com.ad2001.frida0x3.Checker"); // class reference
// a.code.value = 512;

//方法二
var className = Java.use("com.ad2001.frida0x3.Checker"); // class reference
for (var i = 1; i <= 256; i++) {
console.log("Calling increase() method " + i + " times");
className.increase();

var code_value = className.code.value;
console.log("Current variable value: " + code_value);
}

});
}

setImmediate(main);

image.png

challenge 0x04

image.png

1、jadx反编译后定位到了MainActivity,查看后没有发现有用信息:

image.png

2、查看另一个类Check,里面定义了一个 get_flag方法

image.png

3、要求传入的参数值a = 1337,才会继续向下执行。

由于没有在MainActivity中发现实例化的Check类。

所以,可以先使用$new()新建一个Check的实例对象,然后调用get_flag方法,打印输出即可。

function main(){
Java.perform(function(){
var check = Java.use("com.ad2001.frida0x4.Check");
var check_obj = check.$new(); // Class Object

var res = check_obj.get_flag(1337); // Calling the method
console.log("FLAG--1 " + res);

});
}

setImmediate(main);

image.png

这块的get_flag方法是非静态方法,创建实例后也可以使用Java.choose来进行hook定位

function main(){
Java.perform(function(){
var check = Java.use("com.ad2001.frida0x4.Check");
var check_obj = check.$new(); // Class Object

//方法一
var res = check_obj.get_flag(1337); // Calling the method
console.log("FLAG--1 " + res);

//方法二
Java.choose('com.ad2001.frida0x4.Check', {
onMatch: function(instance){
console.log("Found `HookedObject` instance:", instance);
var res = instance.get_flag(1337);
console.log("FLAG--2 " + res);
},
onComplete: function(){
console.log("Found Completed");
}
});
});
}

setImmediate(main);

image.png

challenge 0x05

image.png

jadx反编译,定位到关键函数:

image.png

查看关键代码 if (code == 1337) 的执行函数后续代码:

所以,这块可以参考上节demo的做法。

这块有个问题,就是不能直接 $new 创建一个实例后再调用 flag 方法。

原因:flag函数在MainActivity类中,一般MainActivity是由程序直接创建的,不会通过代码来调用。

所以,这块使用 Java.choose 定位到实例,然后再调用即可:

function main(){
Java.perform(function(){
Java.choose("com.ad2001.frida0x5.MainActivity",{
onMatch: function(instance){
console.log("Found MainActivity instance: " + instance);
instance.flag(1337);
},
onComplete: function(){}
} )
});
}

setImmediate(main);

be5e86773b1bc66d0102b73b08a3bd8.png

challenge 0x06

image.png

image.png

if (1234 == A.num1 && 4321 == A.num2)

image.png MainActivity中的get_flag方法,传参为 Checker的一个实例。

但是没有在MainActivity中发现调用get_flag方法的代码,所以,这块需要定位到实例后主动调用;

因为if判断中对Check类的两个成员变量有要求,所以,还需要实例化一个Check类并对成员变量进行初始化。

代码如下:

function main() {
Java.perform(function() {
Java.choose('com.ad2001.frida0x6.MainActivity', {
onMatch: function(instance) {
console.log("Instance found");

var checker = Java.use("com.ad2001.frida0x6.Checker");
var checker_obj = checker.$new(); // Class Object
checker_obj.num1.value = 1234; // num1
checker_obj.num2.value = 4321; // num2
instance.get_flag(checker_obj); // invoking the get_flag method

},
onComplete: function() {}
});
});
}

setImmediate(main)

image.png

challenge 0x07

本质是要Hook构造函数 : $init

image.png

image.png

代码如下:

function main() {
Java.perform(function() {
Java.choose("com.ad2001.frida0x7.MainActivity", {
onMatch: function(instance) {
console.log("Found instance of MainActivity");
var check_class = Java.use("com.ad2001.frida0x7.Checker");
// check_class.$init.implementation = function(arg1, arg2) {
// console.log("Check class initialized");
// arg1 = 513;
// arg2 = 513;
// return this.$init(arg1, arg2);
// }
instance.flag(check_class.$new(513, 513));
},
onComplete: function() {
console.log("Done");
}
});
});
}

setImmediate(main);

image.png