Frida-labs

项目地址: https://github.com/DERE-ad2001/Frida-Labs

0x1

frida-ps -Uai

相较于-U更详细

-a all processes

-i include details

js语法:https://www.runoob.com/js/js-syntax.html

可以不加;但是部分情况如()等需手动添加分隔,其余靠ASI机制自行插入;

hook方法记得设置返回值

frida -U -f com.ad2001.frida0x1 -l 1.js

1
2
3
4
5
6
7
8
9
10
Java.perform(function(){
var a=Java.use("com.ad2001.frida0x1.MainActivity");
a.get_random.implementation=function(){
console.log("method get_random has been hooked!");
var ret=this.get_random();
var i=ret*2+4;
console.log("ret is "+ret+" input is "+i);
return ret;
}
})

ptrace注入

frida -U ‘Frida 0x1’ -l 1.js

涉及重载,参数类型和传参确认

1
2
3
4
5
6
7
8
Java.perform(function(){
var a=Java.use("com.ad2001.frida0x1.MainActivity");
a.check.overload('int','int').implementation=function(i,i2){
console.log("i is "+i+" i2 is "+i2);
var t=i*2+4;
console.log("true is t "+t);
}
})

0x2

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

Spawned com.ad2001.frida0x2. Resuming main thread!

spawn进入会有个暂停机制,默认会暂停应用的所有线程,以便有机会设置 Hook 后再让应用运行,避免错过关键初始化代码。

spawn进入后输入js或者直接attach调试调用js

0x3

满足条件调用blowfish解密即可

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

0x4

MainActivity未加载该实例,手动创建调用check

1
2
3
4
5
6
Java.perform(function(){
var check=Java.use("com.ad2001.frida0x4.Check");
var a=check.$new(); //创建Check类
var ret=a.get_flag(1337);
console.log("flag is "+ret);
})

0x5

wrong eg.

1
2
3
4
5
Java.perform(function(){
var a =Java.use("com.ad2001.frida0x5.MainActivity");
var get=a.$new();
get.flag(1337);
})

Android 组件,如Activity子类,依赖于应用程序上下文来正常运行

Android UI 组件通常需要一个特定的线程以及与之关联的Looper

所以不能直接use实例而是现有实例上调用

1
2
3
4
5
6
7
8
9
Java.perform(function() {
Java.choose('com.ad2001.frida0x5.MainActivity', {
onMatch: function(instance) { // "instance" is the instance for the MainActivity
console.log("Instance found");
instance.flag(1337); // Calling the function
},
onComplete: function() {}
});
});

注:Java.performNow()在新版本中被移除

0x6

1
2
3
4
5
6
7
8
9
10
11
12
13
Java.perform(function(){
Java.choose("com.ad2001.frida0x6.MainActivity",{
onMatch:function(instance){
console.log("Instance found");
var a=Java.use("com.ad2001.frida0x6.Checker");
var hoge=a.$new();
hoge.num1.value=1234;
hoge.num2.value=4321;
instance.get_flag(hoge);
},
onComplete:function(){}
})
})

0x7

多了个构造方法

1
2
3
4
5
6
7
8
9
10
11
Java.perform(function(){
Java.choose("com.ad2001.frida0x7.MainActivity",{
onMatch:function(instance){
console.log("Instance found");
var a=Java.use("com.ad2001.frida0x7.Checker");
var hoge=a.$new(666,666);
instance.flag(hoge);
},
onComplete:function(){}
})
})

0x8

一个native层的strcmp

源码

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
#include <jni.h>
#include <string.h>
#include <cstdio>
#include <android/log.h>

extern "C"
JNIEXPORT jint JNICALL
Java_com_ad2001_frida0x8_MainActivity_cmpstr(JNIEnv *env, jobject thiz, jstring str) {
const char *inputStr = env->GetStringUTFChars(str, 0);
const char *hardcoded = "GSJEB|OBUJWF`MBOE~";
char password[100];

for (int i = 0; i < strlen(hardcoded) ; i++) {

password[i] = (char)(hardcoded[i] - 1);
}

password[strlen(hardcoded)] = '\0';
int result = strcmp(inputStr, password);
__android_log_print(ANDROID_LOG_DEBUG, "input ", "%s",inputStr);
__android_log_print(ANDROID_LOG_DEBUG, "Password", "%s",password);
env->ReleaseStringUTFChars(str, inputStr);

// Returning result: 1 if equal, 0 if not equal
return (result == 0) ? 1 : 0;
}

关注变量类型:JNIEnv *env, jobject thiz, jstring str

hook思路是获取对应native function地址调用Interceptor.attach处理

1
2
3
4
5
Module.enumerateExports()
Module.getExportByName()
Module.findExportByName()
Module.getBaseAddress() + add()
Module.enumerateImports()//
1
2
3
4
5
6
7
8
Interceptor.attach(targetAddress, {
onEnter: function (args) {
console.log('Entering ' + functionName);
},
onLeave: function (retval) {
console.log('Leaving ' + functionName);
}
});

Module.enumerateExports()

enumerate:枚举

Module.enumerateExports(“libfrida0x8.so”)

新版本frida已移除该api,笔者这里17.3.2未果,14.2.18可以,对应objection版本

frida -U -f com.ad2001.frida0x8 -l 1.js –no-pause

或者挂起后手动输入%resume恢复进程

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
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.enumerateExports("libfrida0x8.so")
[
{
"address": "0x763877f768c0",
"name": "Java_com_ad2001_frida0x8_MainActivity_cmpstr",
"type": "function"
},
{
"address": "0x763877f76aa0",
"name": "_ZN7_JNIEnv17GetStringUTFCharsEP8_jstringPh",
"type": "function"
},
{
"address": "0x763877f76ae0",
"name": "_ZN7_JNIEnv21ReleaseStringUTFCharsEP8_jstringPKc",
"type": "function"
}
]
[Android Emulator 5554::com.ad2001.frida0x8]->

[Android Emulator 5554::com.ad2001.frida0x8]-> Module.enumerateExports("libfrida0x8.so")[0]
{
"address": "0x763877f768c0",
"name": "Java_com_ad2001_frida0x8_MainActivity_cmpstr",
"type": "function"
}

此地址因android默认ASLR会发生改变

Module.enumerateImports(“libfrida0x8.so”)同理

Module.getExportByName()

Module.getExportByName(modulename, exportName)

module不确定下可用null替代

1
2
3
4
5
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.enumerateExports("libfrida0x8.so")[0]["address"]
"0x763877f768c0"
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.getExportByName("libfrida0x8.so","Java_com_ad2001_frida0x8_MainAc
tivity_cmpstr")
"0x763877f768c0"

Module.findExportByName()

与 Module.getExportByName()相同。唯一的区别在于,如果导出项不存在,Module.getExportByName() 会抛出异常,而 Module.findExportByName()`在导出项不存在时会返回 null

Module.getBaseAddress()

1
2
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.getBaseAddress("libfrida0x8.so")
"0x763877f76000"

1
2
3
4
5
6
7
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.findExportByName("libfrida0x8.so","Java_com_ad2001_frida0x8_MainA
ctivity_cmpstr")
"0x763877f768c0"
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.getBaseAddress("libfrida0x8.so")
"0x763877f76000"
[Android Emulator 5554::com.ad2001.frida0x8]-> Module.getBaseAddress("libfrida0x8.so").add(0x8c0)
"0x763877f768c0"

wp

filter strcmp

1
2
3
4
5
6
7
8
9
10
11
12
var address=Module.getExportByName("libc.so","strcmp");
Interceptor.attach(address,{
onEnter: function(args){ //这里args[]的1和2不一定分别对应哪个,但就两次尝试
var v1=Memory.readUtf8String(args[0]); //此处v1为输入
var v2=Memory.readUtf8String(args[1]);
if(v1.includes("Hello")){
console.log("succeed in hooking");
console.log("the input is "+v1+"\nthe flag is "+v2);
}
},
onLeave:function(retval){}
});

0x9

对native的return 1方法hook

1
2
3
4
5
6
7
8
9
var addr=Module.getExportByName("liba0x9.so","Java_com_ad2001_a0x9_MainActivity_check_1flag");
Interceptor.attach(addr,{
onEnter:function(args){},
onLeave:function(retval){
console.log("oraginal ret is "+retval);
retval.replace(1337);
console.log("now the ret is "+retval);
}
})

0xA

雷电模拟器+一加,疯狂闪退

仅描述思路

需调用native的一个函数,构造NativePointer实现

1
2
3
4
5
6
var native_adr = new NativePointer(<address_of_the_native_function>);
const native_function = new NativeFunction(native_adr, '<return type>', ['argument_data_type']);
native_function(<arguments>);
// 第一个参数应该是 NativePointer 对象
// 第二个参数是本机函数的返回类型
// 第三个参数是要传递给本机函数的参数的数据类型列表。

1
2
3
4
var adr = Module.findBaseAddress("libfrida0xa.so").add(0x18BB0) 
var get_flag_ptr = new NativePointer(adr);
const get_flag = new NativeFunction(get_flag_ptr, 'void', ['int', 'int']);
get_flag(1,2);
特性 var const
作用域 函数作用域或全局作用域 块级作用域(由 {} 界定)
变量提升 存在提升,声明会被提升到作用域顶部,初始值为 undefined 存在暂时性死区,声明前访问会报错
重复声明 允许在同一作用域内重复声明 不允许在同一作用域内重复声明
重新赋值 可以随时重新赋值 不可重新赋值(对于基本数据类型)
初始化 可以不初始化,默认值为 undefined 必须在声明时初始化

对应const有个let重新赋值,rust这一块

0xB

依旧闪退,物色真机去了,笔者自己是鸿蒙的,难搞

get_Flag初看无内容

frida 实现nop

涉及 X86Writer 和 Arm64Writer

相关api文档

https://frida.re/docs/javascript-api/#x86writer

https://frida.re/docs/javascript-api/#arm64writer

X86Writer

6个opcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var jnz = Module.getBaseAddress("libfrida0xb.so").add(0x10E2A);
Memory.protect(jnz, 0x1000, "rwx"); //.text区块不可写入,修改权限
var writer = new X86Writer(jnz);
try { // 插入指令
writer.putNop()
writer.putNop()
writer.putNop()
writer.putNop()
writer.putNop()
writer.putNop()
//刷新patch
writer.flush();

} finally {
//资源释放
writer.dispose();
}

插入指令如图

Arm64Writer

1
2
3
4
5
6
7
8
9
10
11
var adr = Module.findBaseAddress("libfrida0xb.so").add(0x15248);  
Memory.protect(adr, 0x1000, "rwx");
var writer = new Arm64Writer(adr);
var target = Module.findBaseAddress("libfrida0xb.so").add(0x1524c);
try {
writer.putBImm(target);
writer.flush();
console.log(`${adr}处指令插入成功`);
} finally {
writer.dispose();
}

Frida-labs
https://alenirving.github.io/2025/10/06/Frida-Labs/
作者
Ma5k
许可协议
CC-BY-NC-SA