文章目录
-
- 一、基础语法
- 二、案例解析
-
- [2.1 案例背景](#2.1 案例背景)
- [2.2 源码逻辑分析](#2.2 源码逻辑分析)
- [2.3 Hook实现方案](#2.3 Hook实现方案)
-
- [(1)Frida Hook脚本(JavaScript)](#(1)Frida Hook脚本(JavaScript))
- (2)执行脚本(Python)
- [2.4 执行与效果](#2.4 执行与效果)
- 三、技术总结
⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。
一、基础语法
在Java层Hook中,调用带有对象参数的方法是常见场景,核心在于通过Frida的Java桥接API(frida-java-bridge
)完成类定位、对象实例化、属性赋值及方法调用的全流程,关键步骤如下:
- 定位目标类 :使用
Java.use(className)
获取类的引用,例如定位MainActivity
和Checker
类; - 创建对象实例 :通过类引用的
$new()
方法创建对象(若有构造函数需传入对应参数),如Checker.$new()
创建Checker
实例; - 设置对象属性 :对于对象的成员变量,通过
.value
访问并赋值(需注意变量访问权限,私有变量可能需要额外处理),例如checker.num1.value = 1234
; - 调用目标方法 :通过对象实例直接调用目标方法,并传入准备好的对象参数,如
activity.get_flag(checker)
。
二、案例解析
本章示例应用的链接:
https://pan.baidu.com/s/16EE2XE-OZS_xBRPlWUODbw?pwd=n2vb
提取码: n2vb
使用APK:Challenge 0x6.apk
2.1 案例背景
目标应用中,MainActivity
类的get_flag
方法负责解密并显示Flag,但该方法未被主动调用,且调用时需传入Checker
类型的参数,仅当Checker
实例的num1=1234
且num2=4321
时才执行解密逻辑。
2.2 源码逻辑分析
(1)Checker
类(数据载体)
java
public class Checker {
int num1; // 整数成员变量1
int num2; // 整数成员变量2
}
- 功能:作为
get_flag
方法的参数,仅用于存储两个整数num1
和num2
,无其他业务逻辑。 - 关键:
num1
和num2
是get_flag
方法执行解密的核心条件,需同时满足1234
和4321
。
(2)MainActivity
类(核心逻辑)
java
public class MainActivity extends AppCompatActivity {
TextView t1; // 用于显示结果的文本控件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.t1 = (TextView) findViewById(R.id.textview); // 初始化TextView
}
// 核心方法:接收Checker实例,验证条件后解密并显示结果
public void get_flag(Checker A) throws ... { // 省略异常声明
// 条件判断:仅当Checker实例的num1=1234且num2=4321时执行解密
if (1234 == A.num1 && 4321 == A.num2) {
// AES解密逻辑(密钥固定为"MySecureKey12345",密文固定)
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec secretKeySpec = new SecretKeySpec("MySecureKey12345".getBytes(), "AES");
cipher.init(2, secretKeySpec);
byte[] decryptedBytes = Base64.getDecoder().decode("QQzMj/JNaTblEHnIzgJAQkvWJV2oK9G2/UmrCs85fog=");
String decrypted = new String(cipher.doFinal(decryptedBytes));
this.t1.setText(decrypted); // 显示解密结果
}
}
}
- 核心逻辑:
get_flag
方法接收Checker
类型参数A
,仅当A.num1
和A.num2
满足条件时,使用固定密钥解密固定密文,并将结果显示在TextView
上。 - 限制:若
Checker
参数不满足条件,解密逻辑不执行,无任何结果显示。
2.3 Hook实现方案
若需触发get_flag
方法并获取Flag,需主动创建符合条件的Checker
实例并调用方法,步骤如下:
- 搜索
MainActivity
的实例(确保能调用get_flag
方法); - 创建
Checker
实例,手动设置num1=1234
、num2=4321
; - 调用
MainActivity
实例的get_flag
方法,传入上述Checker
实例。
(1)Frida Hook脚本(JavaScript)
javascript
import Java from 'frida-java-bridge';
Java.perform(function () {
// 定位目标类
var MainActivity = Java.use('com.ad2001.frida0x6.MainActivity');
var Checker = Java.use('com.ad2001.frida0x6.Checker');
// 延迟1秒,确保MainActivity初始化完成
setTimeout(function () {
// 搜索MainActivity实例
Java.choose('com.ad2001.frida0x6.MainActivity', {
onMatch: function (activity) {
console.log("[找到MainActivity实例] 准备调用get_flag");
// 创建Checker实例,并设置num1=1234、num2=4321
var checker = Checker.$new(); // 创建Checker实例
checker.num1.value = 1234; // 设置num1(用.value访问成员变量)
checker.num2.value = 4321; // 设置num2
// 调用get_flag方法,传入符合条件的Checker实例
try {
activity.get_flag(checker);
console.log("[调用成功] 已显示解密结果");
} catch (e) {
console.log("[调用异常] " + e.message);
}
},
onComplete: function () {
console.log("[搜索完成] MainActivity实例搜索结束");
}
});
}, 1000);
});
(2)执行脚本(Python)
python
import frida
import sys
import time
def on_message(message, data):
if message['type'] == 'send':
print(f"[Hook 日志] {message['payload']}")
elif message['type'] == 'error':
print(f"[错误] {message['stack']}")
# 目标应用包名
PACKAGE_NAME = "com.ad2001.frida0x6"
def main():
try:
device = frida.get_usb_device(timeout=10)
print(f"已连接设备:{device.name}")
print(f"启动进程 {PACKAGE_NAME}...")
pid = device.spawn([PACKAGE_NAME])
device.resume(pid)
time.sleep(2)
process = device.attach(pid)
print(f"已附加到进程 PID: {pid}")
with open("./js/compiled_hook.js", "r", encoding="utf-8") as f:
js_code = f.read()
script = process.create_script(js_code)
script.on('message', on_message)
script.load()
print("JS 脚本注入成功,开始监控...(按 Ctrl+C 退出)")
sys.stdin.read()
except frida.TimedOutError:
print("未找到USB设备")
except frida.ProcessNotFoundError:
print(f"应用 {PACKAGE_NAME} 未安装")
except FileNotFoundError:
print("未找到 js 脚本,请检查路径")
except Exception as e:
print(f"异常:{str(e)}")
finally:
if 'process' in locals():
process.detach()
print("程序退出")
if __name__ == "__main__":
main()
2.4 执行与效果
编译并执行上述Python脚本后,Frida会注入目标应用并执行Hook逻辑:

最终应用界面将显示解密后的Flag:

三、技术总结
本案例核心在于通过Frida干预Java层对象交互,实现对带对象参数方法的主动调用,关键技术点如下:
- 对象实例的控制 :通过
Java.use
定位类、$new()
创建实例、.value
修改属性,实现对参数对象的完全控制,满足目标方法的条件验证; - Frida Java层交互核心 :利用
Java.choose
搜索目标类实例,确保能调用非静态方法;通过延迟执行(setTimeout
)规避初始化时序问题; - 适用场景:适用于目标方法未被主动调用、或参数对象属性不满足条件的场景,通过"主动创建符合条件的参数+调用方法"的思路,绕过业务限制,触发目标逻辑。
这种思路是逆向分析中处理"对象参数验证"类问题的典型方案,可扩展到各类需要干预对象属性或主动调用方法的场景。