一枚酸心果子

果子果子果子果子果子~~~

Frida Hook技术入门:从零开始掌握动态分析神器

Frida简介

什么是Frida

Frida是一个动态代码分析工具包,主要用于:

  • 动态Hook应用程序
  • 实时修改程序行为
  • 分析应用程序逻辑
  • 绕过安全检测

核心特点

  • 跨平台:支持Windows、macOS、Linux、Android、iOS
  • 多语言:支持JavaScript、Python、C等
  • 易上手:简单的API设计,学习成本低
  • 功能强大:可以Hook几乎所有系统调用和API

Frida工作原理

基本架构

1
2
3
目标应用 ←→ Frida Server ←→ Frida Client ←→ 你的脚本

注入进程 → Hook函数 → 修改行为 → 返回结果

Hook机制

1
2
3
4
5
1. 注入Frida Agent到目标进程
2. 定位目标函数地址
3. 替换函数入口点
4. 执行自定义逻辑
5. 调用原函数或返回自定义值

Frida安装配置

1. 安装Frida

1
2
3
4
5
# 安装Frida客户端
pip install frida-tools

# 验证安装
frida --version

2. Android环境配置

1
2
3
4
5
6
7
8
9
# 下载Frida Server
# 从 https://github.com/frida/frida/releases 下载对应版本

# 推送到设备
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server

# 启动Frida Server
adb shell /data/local/tmp/frida-server &

3. 连接设备

1
2
3
4
5
6
7
8
9
10
import frida

# 连接设备
device = frida.get_usb_device()
print(f"设备: {device}")

# 列出进程
processes = device.enumerate_processes()
for process in processes:
print(f"进程: {process.name} (PID: {process.pid})")

基础Hook示例

1. Hook Java方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Hook Java方法示例
Java.perform(function() {
// Hook String类的equals方法
var String = Java.use("java.lang.String");
String.equals.implementation = function(obj) {
console.log("String.equals被调用");
console.log("参数: " + obj);

// 调用原方法
var result = this.equals(obj);
console.log("返回值: " + result);

return result;
};
});

2. Hook Native函数

1
2
3
4
5
6
7
8
9
10
11
12
13
// Hook Native函数示例
var libc = Module.findExportByName("libc.so", "strlen");
if (libc) {
Interceptor.attach(libc, {
onEnter: function(args) {
console.log("strlen被调用");
console.log("参数: " + Memory.readUtf8String(args[0]));
},
onLeave: function(retval) {
console.log("返回值: " + retval);
}
});
}

3. Hook系统调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Hook系统调用示例
var openat = Module.findExportByName("libc.so", "openat");
if (openat) {
Interceptor.attach(openat, {
onEnter: function(args) {
var path = Memory.readUtf8String(args[1]);
console.log("打开文件: " + path);

// 隐藏特定文件
if (path.includes("su")) {
console.log("隐藏su文件访问");
args[1] = Memory.allocUtf8String("/dev/null");
}
}
});
}

实用Hook技巧

1. 绕过Root检测

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
// 绕过Root检测
Java.perform(function() {
// Hook文件存在检查
var File = Java.use("java.io.File");
File.exists.implementation = function() {
var path = this.getAbsolutePath();
console.log("检查文件: " + path);

// 隐藏Root相关文件
if (path.includes("su") || path.includes("magisk")) {
console.log("隐藏Root文件: " + path);
return false;
}

return this.exists();
};

// Hook系统属性获取
var SystemProperties = Java.use("android.os.SystemProperties");
SystemProperties.get.overload("java.lang.String", "java.lang.String").implementation = function(key, def) {
console.log("获取属性: " + key);

// 伪造Root相关属性
if (key === "ro.debuggable") {
return "0";
}
if (key === "ro.secure") {
return "1";
}

return this.get(key, def);
};
});

2. 绕过SSL Pinning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 绕过SSL Pinning
Java.perform(function() {
// Hook X509TrustManager
var X509TrustManager = Java.use("javax.net.ssl.X509TrustManager");
X509TrustManager.checkClientTrusted.implementation = function(chain, authType) {
console.log("绕过客户端证书检查");
};

X509TrustManager.checkServerTrusted.implementation = function(chain, authType) {
console.log("绕过服务端证书检查");
};

X509TrustManager.getAcceptedIssuers.implementation = function() {
return Java.use("java.util.ArrayList").$new();
};
});

3. 监控网络请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 监控网络请求
Java.perform(function() {
// Hook OkHttp
var OkHttpClient = Java.use("okhttp3.OkHttpClient");
var Request = Java.use("okhttp3.Request");

// Hook Request.Builder
var RequestBuilder = Java.use("okhttp3.Request$Builder");
RequestBuilder.build.implementation = function() {
var request = this.build();
var url = request.url().toString();
console.log("HTTP请求: " + url);

return request;
};
});

进阶Hook技术

1. 动态类加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 动态类加载
Java.perform(function() {
// 等待类加载
Java.choose("com.example.TargetClass", {
onMatch: function(instance) {
console.log("找到目标实例: " + instance);

// Hook实例方法
instance.targetMethod.implementation = function() {
console.log("目标方法被调用");
return this.targetMethod();
};
},
onComplete: function() {
console.log("搜索完成");
}
});
});

2. 内存操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 内存操作
Java.perform(function() {
// 读取内存
var baseAddr = Module.getBaseAddress("libtarget.so");
var value = Memory.readU32(baseAddr.add(0x1000));
console.log("内存值: " + value);

// 写入内存
Memory.writeU32(baseAddr.add(0x1000), 0x12345678);

// 分配内存
var buffer = Memory.alloc(1024);
Memory.writeUtf8String(buffer, "Hello Frida");
});

3. 函数替换

1
2
3
4
5
6
7
8
9
10
11
12
// 函数替换
var targetFunc = Module.findExportByName("libtarget.so", "target_function");
if (targetFunc) {
Interceptor.replace(targetFunc, new NativeCallback(function(arg1, arg2) {
console.log("替换函数被调用");
console.log("参数1: " + arg1);
console.log("参数2: " + arg2);

// 返回自定义值
return 0x12345678;
}, 'int', ['int', 'int']));
}

常用命令

1. 基础命令

1
2
3
4
5
6
7
8
9
10
11
# 列出设备
frida-ls-devices

# 列出进程
frida-ps -U

# 附加进程
frida -U -f com.example.app -l script.js

# 启动应用
frida -U -f com.example.app -l script.js --no-pause

2. 高级命令

1
2
3
4
5
6
7
8
# 生成Hook模板
frida-trace -U -i "*open*" com.example.app

# 监控系统调用
frida-trace -U -j "*" com.example.app

# 导出函数
frida -U com.example.app -e "console.log(Module.enumerateExports('libc.so'))"

结语

这篇文章主要是讲解了官方版本的Frida,另外还有一些第三方魔改的基于一定特性修改的版本这里就不展开了,有兴趣的可以自行去翻阅一下,或者后面讲一篇关于自定义自己的frida该怎么做。

本文关键要点

  • 基本原理:进程注入 + 函数Hook
  • 核心功能:动态修改程序行为
  • 应用场景:安全研究、逆向分析、漏洞挖掘
持续输出技术分享,您的支持将鼓励我继续创作!