[安全] Frida Labs 0x1
Frida Labs 自带的 Solution 写得很好!!
分析过程
先使用工具 ( jadx, jeb … ) 查看反编译之后的代码, 代码主要逻辑在 MainActicity 中
/* JADX INFO: loaded from: classes.dex */
public class MainActivity extends AppCompatActivity {
/* JADX INFO: renamed from: t1 */
TextView f103t1;
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(C0536R.layout.activity_main);
final EditText editText = (EditText) findViewById(C0536R.id.editTextTextPassword);
Button button = (Button) findViewById(C0536R.id.button);
this.f103t1 = (TextView) findViewById(C0536R.id.textview1);
final int i = get_random();
button.setOnClickListener(new View.OnClickListener() { // from class: com.ad2001.frida0x1.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
String string = editText.getText().toString();
if (TextUtils.isDigitsOnly(string)) {
MainActivity.this.check(i, Integer.parseInt(string));
} else {
Toast.makeText(MainActivity.this.getApplicationContext(), "Enter a valid number !!", 1).show();
}
}
});
}
int get_random() {
return new Random().nextInt(100);
}
/* JADX WARN: Removed duplicated region for block: B:13:0x0031 A[PHI: r0
0x0031: PHI (r0v7 char) = (r0v5 char), (r0v11 char) binds: [B:19:0x0040, B:12:0x002f] A[DONT_GENERATE, DONT_INLINE]] */
/*
Code decompiled incorrectly, please refer to instructions dump.
*/
void check(int rnd, int input) {
if ((rnd * 2) + 4 == input) {
Toast.makeText(getApplicationContext(), "Yey you guessed it right", 1).show();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 20; i++) {
char cCharAt = "AMDYV{WVWT_CJJF_0s1}".charAt(i);
if (cCharAt >= 'a' && cCharAt <= 'z') {
cCharAt = (char) (cCharAt - 21);
if (cCharAt < 'a') {
}
} else if (cCharAt >= 'A' && cCharAt <= 'Z' && (cCharAt = (char) (cCharAt - 21)) < 'A') {
cCharAt = (char) (cCharAt + 26);
}
sb.append(cCharAt);
}
this.f103t1.setText(sb.toString());
return;
}
Toast.makeText(getApplicationContext(), "Try again", 1).show();
}
}可见程序的逻辑是将 输入的数字 和 预先生成的随机数 进行某种比较 ((rnd * 2) + 4 == input), 通过之后则解密 flag
由于是 Frida 的学习, 不展示静态解法
Frida 是一款 Hook 工具, 可以在程序运行过程中修改其中的某些内容
这里想要 check 中的解密成功被运行, 有两种 hook 思路
- hook
get_random函数, 打印其返回值或者更改其返回值 - hook
check函数, 使其一定通过判断
Frida 前期准备
你需要模拟器或者真机, 这里试过 Android Studio 的模拟器 和 MuMu模拟器 都可以用
Android Studio 模拟器的性能不太好, 建议选别的
模拟器记得开 root
安装 Frida 客户端
pip install frida frida-tools
从 Frida 的仓库中下载对应版本的 Frida server
使用 frida --version 来查看 Frida 的版本
使用 adb shell getprop ro.product.cpu.abi 来查看运行平台的版本 (Frida 也可以 hook Windows 程序之类的, 但是 Frida labs 都是安卓题, 所以这里查看安卓平台的版本)
下载的服务器务必与 服务器运行的平台版本 和 客户端Frida版本 统一
接下来我们运行 frida-server, 下方以你的服务器的文件名为准
- 将 frida-server 推送到模拟器上
adb push frida-server /data/local/tmp/ - 进入 adb shell
adb shell - 设置运行权限
chmod +x /data/local/tmp/frida-server - 运行 frida-server
/data/local/tmp/frida-server &
注: 通常在这里需要新开一个终端来执行剩下的操作
如果你想获取设备上安装的软件包列表,可以使用以下命令:
frida-ps -Uai
frida-ps: 显示 Android 设备上正在运行的进程信息。-U: 此选项用于列出 USB 连接设备(物理设备或模拟器)上的进程。-a: 此选项用于列出所有进程,而不仅仅是当前用户拥有的进程。-i: 此选项用于包含每个进程的详细信息,例如进程 ID (PID) 和进程名称。
你也可以用该命令确定已经能正确连接上 frida-server
Hook 一个 Java 层方法
Java.perform(() => {
const <class_reference> = Java.use("<package_name>.<class>");
<class_reference>.<method_to_hook>.implementation =
function(<args>) {
/*
我们自己对该方法的实现
*/
};
});-
Java.perform是 Frida 中的一个函数,用于为你的脚本创建一个特殊的上下文,以便与 Android 应用程序中的 Java 代码进行交互。它就像打开了一扇门,可以访问和操作 App 内部运行的 Java 代码。一旦进入这个上下文,你就可以执行诸如 Hook 方法或访问 Java 类等操作,以控制或观察 App 的行为。 -
const <class_reference> = Java.use("<package_name>.<class>");在这里,你声明一个变量
<class_reference>来表示目标 Android 应用程序中的一个 Java 类。你使用Java.use函数指定要使用的类,该函数将类名作为参数。<package_name>代表 Android 应用程序的包名,<class>代表你想要交互的类。 -
<class_reference>.<method_to_hook>.implementation = function(<args>) {}在选定的类中,你可以通过使用
<class_reference>.<method_to_hook>符号来访问你想要 Hook 的方法。在这里你可以定义当 Hook 的方法被调用时要执行的逻辑。<args>代表传递给函数的参数。当处理带有参数的方法 Hook 时,重要的是使用
overload(arg_type)关键字指定预期的参数类型。
不能使用箭头函数, 这样会没办法获取到 this
具体实现可以参考示例代码, 代入之后就知道是什么意思了
示例代码
import Java from "frida-java-bridge";
if (Java.available) {
Java.perform(() => {
const MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");
// MainActivity.get_random.implementation =
// function () {
// let v = this.get_random();
// console.log(`the random number is: ${v}`);
// return v;
// // return 0;
// };
MainActivity.check.overload("int", "int").implementation =
function (rnd: number, input: number) {
console.log(`the input number should be: ${rnd * 2 + 4}`);
this.check(rnd, rnd * 2 + 4);
};
});
} else {
console.log("No Java VM in this process");
}比较舒服的 Frida 脚本编写流程推荐
下载 frida-agent-example 项目, 根据其中的 README.md 文件设置开发环境, 这样你的 Frida 脚本可以使用现代化的 TypeScript 来编写, 同时有了代码补全和提示
git clone https://github.com/oleavr/frida-agent-example.gitcd frida-agent-example/- 编辑
./agent/index.ts这个文件, 这是你的 Frida 脚本所在的文件 npm install
这一步可能会需要npm audit fix, 跟着你的 npm 的提示做就好- 可选, 使用
npm run watch进行及时编译, 能让你在更改脚本之后立即编译, 不需要过多执行npm install frida -U -f com.example.android -l _agent.js
_agent.js是你编写的 ts 代码经过编译后的样子, 可以直接作为 Frida 脚本运行
注: 通常在
npm run watch之后需要重新开一个终端来执行其它操作