【Frida Android】基础篇8:Java层Hook基础——调用带对象参数的方法
文章目录
- 一、基础语法
- 二、案例解析
- 2.1 案例背景
- 2.2 源码逻辑分析
- (1)`Checker`类(数据载体)
- (2)`MainActivity`类(核心逻辑)
- 2.3 Hook实现方案
- (1)Frida Hook脚本(JavaScript)
- (2)执行脚本(Python)
- 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
类(数据载体)
public class Checker {int num1; // 整数成员变量1int num2; // 整数成员变量2
}
- 功能:作为
get_flag
方法的参数,仅用于存储两个整数num1
和num2
,无其他业务逻辑。 - 关键:
num1
和num2
是get_flag
方法执行解密的核心条件,需同时满足1234
和4321
。
(2)MainActivity
类(核心逻辑)
public class MainActivity extends AppCompatActivity {TextView t1; // 用于显示结果的文本控件@Overrideprotected 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)
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=4321var 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)
import frida
import sys
import timedef 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
)规避初始化时序问题; - 适用场景:适用于目标方法未被主动调用、或参数对象属性不满足条件的场景,通过“主动创建符合条件的参数+调用方法”的思路,绕过业务限制,触发目标逻辑。
这种思路是逆向分析中处理“对象参数验证”类问题的典型方案,可扩展到各类需要干预对象属性或主动调用方法的场景。