【Frida Android】基础篇8:Java层Hook基础——调用带对象参数的方法

文章目录

⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。

一、基础语法

在Java层Hook中,调用带有对象参数的方法是常见场景,核心在于通过Frida的Java桥接API(frida-java-bridge)完成类定位、对象实例化、属性赋值及方法调用的全流程,关键步骤如下:

  1. 定位目标类 :使用Java.use(className)获取类的引用,例如定位MainActivityChecker类;
  2. 创建对象实例 :通过类引用的$new()方法创建对象(若有构造函数需传入对应参数),如Checker.$new()创建Checker实例;
  3. 设置对象属性 :对于对象的成员变量,通过.value访问并赋值(需注意变量访问权限,私有变量可能需要额外处理),例如checker.num1.value = 1234
  4. 调用目标方法 :通过对象实例直接调用目标方法,并传入准备好的对象参数,如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=1234num2=4321时才执行解密逻辑。

2.2 源码逻辑分析

(1)Checker类(数据载体)
java 复制代码
public class Checker {
    int num1;  // 整数成员变量1
    int num2;  // 整数成员变量2
}
  • 功能:作为get_flag方法的参数,仅用于存储两个整数num1num2,无其他业务逻辑。
  • 关键:num1num2get_flag方法执行解密的核心条件,需同时满足12344321
(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.num1A.num2满足条件时,使用固定密钥解密固定密文,并将结果显示在TextView上。
  • 限制:若Checker参数不满足条件,解密逻辑不执行,无任何结果显示。

2.3 Hook实现方案

若需触发get_flag方法并获取Flag,需主动创建符合条件的Checker实例并调用方法,步骤如下:

  1. 搜索MainActivity的实例(确保能调用get_flag方法);
  2. 创建Checker实例,手动设置num1=1234num2=4321
  3. 调用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层对象交互,实现对带对象参数方法的主动调用,关键技术点如下:

  1. 对象实例的控制 :通过Java.use定位类、$new()创建实例、.value修改属性,实现对参数对象的完全控制,满足目标方法的条件验证;
  2. Frida Java层交互核心 :利用Java.choose搜索目标类实例,确保能调用非静态方法;通过延迟执行(setTimeout)规避初始化时序问题;
  3. 适用场景:适用于目标方法未被主动调用、或参数对象属性不满足条件的场景,通过"主动创建符合条件的参数+调用方法"的思路,绕过业务限制,触发目标逻辑。

这种思路是逆向分析中处理"对象参数验证"类问题的典型方案,可扩展到各类需要干预对象属性或主动调用方法的场景。

相关推荐
puyaCheer3 小时前
Android 13 启动的时候会显示一下logo,很不友好
android·gitee
long_hai_d4 小时前
Aosp14桌面壁纸和锁屏壁纸的设置和加载分析
android
2501_916007475 小时前
iOS 26 软件性能测试 新版系统下评估全流程 + 多工具辅助方案
android·macos·ios·小程序·uni-app·cocoa·iphone
云霄IT5 小时前
绕过Frida检测反调试的一些办法
android·javascript
sang_xb6 小时前
Android 如何开启 16KB 模式
android·kotlin
emma羊羊6 小时前
【SSRF漏洞】Server-Side Request Forgery 服务器端请求伪造
网络安全·pikachu·ssrf
alengan6 小时前
安卓上谷歌35版本
android
珹洺7 小时前
Java-Spring入门指南(二十五)Android 的历史,认识移动应用和Android 基础知识
android·java·spring
大白的编程日记.7 小时前
【MySQL】数据库表的CURD(二)
android·数据库·mysql