Frida 学习(Frida-Labs)

不能当Ai高手,还得学学

练习项目地址:DERE-ad2001/Frida-Labs: The repo contains a series of challenges for learning Frida for Android Exploitation.

Frida 0x1

i是random出来的,我们要向输出可以重新调用check

image-20251203131629772

1
2
3
4
5
6
7
Java.perform(function(){
let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");
MainActivity["check"].implementation = function (i, i2) {
console.log('check is called' + ', ' + 'i: ' + i + ', ' + 'i2: ' + i2);
this.check(1, 6);
};
})
1
2
3
4
5
6
7
Java.perform(function(){
let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");
MainActivity.check.implementation = function (i, i2) {
console.log('check is called' + ', ' + 'i: ' + i + ', ' + 'i2: ' + i2);
this.check(1, 6);
};
})

都行

1
frida -U -F -l .\frida0x1.js

1
frida -U -f com.ad2001.frida0x2 -l frida1.js

Frida 0x2

image-20251203133944934

未被调用,需要主动调用

1
2
3
4
function frida_2() {
let MainActivity = Java.use("com.ad2001.frida0x2.MainActivity");
MainActivity.get_flag(4919);
}

Frida 0x3

image-20251203134118423

需要hook checker.code

1
2
3
4
Java.perform(function() {
var a = Java.use("com.ad2001.frida0x3.Checker");
a.code.value = 0x200;
});

Frida 0x4

image-20251203202613186

image-20251203202555760

没有对类实例化

1
2
3
4
5
6
function frida_5() {
var a = Java.use("com.ad2001.frida0x4.Check");
var check = a.$new();
var flag = check.get_flag(0x539);
console.log("flag: ",flag);
}

Frida 0x5

与上题不同,已经初始化了这个实例

image-20251203203001191

1
2
3
4
5
6
7
8
9
function frida_5() {
Java.choose('com.ad2001.frida0x5.MainActivity',{
onMatch: function(instance){
instance.flag(1337)
},
onComplete: function(){
}
})
}

Frida 0x6

接受一个对象实例化

image-20251203204332491

image-20251203204341947

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function frida_6() {
Java.choose('com.ad2001.frida0x6.MainActivity',{
onMatch: function(instance){
var checker = Java.use("com.ad2001.frida0x6.Checker");
var C_New = checker.$new();
C_New.num1.value = 0x4D2;
C_New.num2.value = 0x10E1;

instance.get_flag(C_New);
},
onComplete: function(){
}
})
}

Frida 0x7

与上题不同的是

image-20251203204502792

法一,同上题,无非是多了个构造函数,我们按构造函数传参即可

1
2
3
4
5
6
7
8
9
10
11
12
function frida_7() {
Java.choose('com.ad2001.frida0x7.MainActivity',{
onMatch: function(instance){
var checker = Java.use("com.ad2001.frida0x7.Checker");
var C_New = checker.$new(0x201,0x201);
instance.flag(C_New);
},
onComplete: function(){
}
})
}

法2:hook构造函数

1
2
3
4
5
6
function frida_7_5() {
var a = Java.use("com.ad2001.frida0x7.Checker");
a.$init.implementation = function(param){
this.$init(0x201,0x201);
}
}

Frida 0x8

cmpstr来自so层

image-20251203205838224

image-20251203210004300

可以看到Java_com_ad2001_frida0x8_MainActivity_cmpstr中获取了我们的输入,并将这段输入使用strcmp函数与一段密文s2进行比较,当它们相等时,将会返回0

所以我们可以直接hook strcmp函数,输出他的两个参数,第二个参数就是密文了

需要输入Closure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
function frida_1() {
let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");
MainActivity.check.implementation = function (i, i2) {
console.log('check is called' + ', ' + 'i: ' + i + ', ' + 'i2: ' + i2);
this.check(1, 6);
};
}

function frida_2() {
let MainActivity = Java.use("com.ad2001.frida0x2.MainActivity");
MainActivity.get_flag(4919);
}

function frida_3() {
let Checker = Java.use("com.ad2001.frida0x3.Checker");
Checker.code.value = 0x200;
}

function frida_4() {
var a = Java.use("com.ad2001.frida0x4.Check");
var check = a.$new();
var flag = check.get_flag(0x539);
console.log("flag: ",flag);
}

function frida_5() {
Java.choose('com.ad2001.frida0x5.MainActivity',{
onMatch: function(instance){
instance.flag(1337)
},
onComplete: function(){
}
})
}

function frida_6() {
Java.choose('com.ad2001.frida0x6.MainActivity',{
onMatch: function(instance){
var checker = Java.use("com.ad2001.frida0x6.Checker");
var C_New = checker.$new();
C_New.num1.value = 0x4D2;
C_New.num2.value = 0x10E1;

instance.get_flag(C_New);
},
onComplete: function(){
}
})
}

function frida_7() {
Java.choose('com.ad2001.frida0x7.MainActivity',{
onMatch: function(instance){
var checker = Java.use("com.ad2001.frida0x7.Checker");
var C_New = checker.$new(0x201,0x201);
instance.flag(C_New);
},
onComplete: function(){
}
})
}

function frida_7_5() {
var a = Java.use("com.ad2001.frida0x7.Checker");
a.$init.implementation = function(param){
this.$init(0x201,0x201);
}
}

function frida_8() {
//枚举所有导出函数
var all_0x8_exp = Module.enumerateExports("libfrida0x8.so");
console.log("libfrida0x8.so 所有导出函数:\n",JSON.stringify(all_0x8_exp, null, 2));

//从lib中寻找指定函数的地址,若不知道lib名称可以传NULL,找不到会抛出异常
var cmpstr_addr = Module.getExportByName("libfrida0x8.so","Java_com_ad2001_frida0x8_MainActivity_cmpstr")
var strcmp_addr = Module.getExportByName("libc.so", "strcmp")
var strcmp_null_addr = Module.getExportByName(null, "strcmp")
console.log("\ncmpstr_addr:",cmpstr_addr);
console.log("strcmp_addr:",strcmp_addr);
console.log("strcmp_null_addr:",strcmp_null_addr);

//功能与getExportByName相同,找不到返回null
var Closure_addr = Module.findExportByName("libfrida0x8.so","Closure")
console.log("Closure_addr:",Closure_addr);

//获取基地址
var libc_base = Module.getBaseAddress("libfrida0x8.so")
console.log("libc_base:",libc_base);
var libc_base_add_cmpstr = Module.getBaseAddress("libfrida0x8.so").add(0x8c0)
console.log("libc_base_add_cmpstr:",libc_base_add_cmpstr);

//获取所有导入
var all_0x8_imp = Module.enumerateImports("libfrida0x8.so")
console.log("libfrida0x8.so 所有导入函数:\n",JSON.stringify(all_0x8_imp, null, 2));

var strcmp_addr = Module.findExportByName("libc.so", "strcmp");
var out_put; //全局变量,接收第一个参数
Interceptor.attach(strcmp_addr, { //将回调附加到指定的函数地址
onEnter: function (args) { //进入回调函数时调用
var arg0 = Memory.readUtf8String(args[0]);
var flag = Memory.readUtf8String(args[1]);
out_put = arg0;
if (arg0.includes("Closure")) { //过滤器
console.log("args[0]: ",arg0);
console.log("args[1]: ",flag);
}

},
onLeave: function (retval) { //退出后调用
if (out_put.includes("Closure")) { //过滤器,根据第一个参数的值,防止修改所有的strcmp
retval.replace(0); //返回0
}
}
});
}

Java.perform(function(){
frida_8();
});

Frida 0x9

image-20251203211113158

checkflag返回1

image-20251203211138241

1
2
3
4
5
6
7
8
9
10
11
function frida_9() {
var flag_addr = Module.findExportByName("liba0x9.so", "Java_com_ad2001_a0x9_MainActivity_check_1flag");
Interceptor.attach(flag_addr, {
onEnter: function (args) {

},
onLeave: function (retval) {
retval.replace(0x539);
}
});
}

Frida 0xA

image-20251203211958615

没有什么,但是so层有个get_flag需要主动调用才能输出flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function frida_A() {
var get_flag_addr = Module.findExportByName("libfrida0xa.so","get_flag")
console.log("get_flag_addr:",get_flag_addr);

//主动调用一个没有被导入的函数需要通过基地址+偏移的方式
var get_flag_addr = Module.findBaseAddress("libfrida0xa.so").add(0x206B0)
console.log("get_flag_addr:",get_flag_addr);

//创建NativePointer对象
var get_flag_ptr = new NativePointer(get_flag_addr);

//创建NativeFunction对象,参数为NativePointer对象,返回类型,原函数参数
const get_flag = new NativeFunction(get_flag_ptr, 'void', ['int', 'int']);
get_flag(1,2); //主动调用
}

Java.perform(function(){
frida_A();
});

Frida 0xB

程序加载了frida0xb库,引用getFlag函数,点击按钮将调用getFlag函数:

image-20251203213240071

定位到getflag

image-20251203213423304

能看到在汇编中对比了0xDEADBEEF和0x539,这当然是不相等的

程序将会直接返回,我们需要让getFlag执行关于flag的相关代码,将JNZ改为JMP或者修改0xDEADBEEF为0x539,或者nop掉相关校验逻辑

image-20251203221012066

nop完为

image-20251203221003539

image-20251203221034830

我这是Arm架构的使用Arm64Writer(真机)

x86_64可以看通过Frida-Labs入门Frida | Closure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function frida_B() {
var soName = "libfrida0xb.so";
var base = Module.getBaseAddress(soName);

console.log("arch:", Process.arch);
console.log("base:", base);
var offset = 0x15248;
var target = base.add(offset);

console.log("patch addr:", target);

// 看一下原来是什么指令
var orig = Instruction.parse(target);
console.log("before:", orig.toString());
var orig2 = Instruction.parse(base.add(0x000000000001524C));
console.log("before2:", orig2.toString());

Memory.patchCode(target, 1, function (code) {
var cw = new Arm64Writer(code, { pc: target });
cw.putNop(); // 把原来的 B.NE 改成 NOP
cw.flush();
});

var now = Instruction.parse(target);
console.log("after:", now.toString());
var now2 = Instruction.parse(base.add(0x000000000001524C));
console.log("after2:", now2.toString());
}

Java.perform(function () {
frida_B();
});