【快速定位键值对】通过hook常用函数HashMap方法及混淆后筛选思路

未被混淆或者自定义方法

HashMap 是 Java 中用于存储键值对的类,一般参数的组成都会通过这个方法,hook 代码如下:

function showStacks() {
    Java.perform(function () {
      // Log.getStackTraceString()‌:将异常堆栈转换为可读字符串,便于输出调试‌
      console.log(Java.use("android.util.Log").getStackTraceString(
      // Throwable.$new()‌:创建一个新的异常对象,其构造函数会‌自动记录当前线程的调用栈‌‌
        Java.use("java.lang.Throwable").$new()
    ));
 })
}

// HashMap.put 方法
function hook_hashMap(){
    var hashMap = Java.use("java.util.HashMap");
    // implementation 属性‌:替换 put 方法的具体逻辑,拦截所有调用‌
    hashMap.put.implementation = function (a,b){
    	// 当 App 执行 map.put("username", value) 时,if (a === "username") 条件成立,触发调用栈打印。
        if (a === "username"){
            // 查看调用栈
            showStacks()
        }
     console.log('hook_hashMap输出-->',a,b)
     return this.put(a,b)
    }
}
Java.perform(function() {
    hook_hashMap()
});

打印日志信息:

java.lang.Throwable
        at java.util.HashMap.put(Native Method)
        at com.dodonew.online.ui.LoginActivity.login(LoginActivity.java:127)
        at com.dodonew.online.ui.LoginActivity.onClick(LoginActivity.java:103)
        at android.view.View.performClick(View.java:6597)
        at android.view.View.performClickInternal(View.java:6574)
        at android.view.View.access$3100(View.java:778)
        at android.view.View$PerformClick.run(View.java:25885)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6718)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

a: username b: 123354

通过com.dodonew.online.ui.LoginActivity.login(LoginActivity.java:127)可以定位到hashMap调用的入口函数,从而得到关键信息代码
在这里插入图片描述

混淆并自定义HashMap 方法

场景描述‌
某 App 在提交请求时,使用自定义的 MyHashMap 类存储参数,但该类被混淆为 a.a.b.c。目标是通过动态分析找到该类的真实名称,并 Hook 其 put() 方法以捕获参数。

步骤 1:枚举所有已加载的类

使用 ‌Frida‌ 的 Java.enumerateLoadedClasses() 遍历当前内存中所有类,筛选出可能实现 Map 接口的候选类。

Java.perform(function() {
    Java.enumerateLoadedClasses({
        onMatch: function(className) {
            // 筛选包名包含应用专属前缀的类(如 com.example.xxx)
            if (className.startsWith("com.example")) {
                console.log("[候选类] ", className);
            }
        },
        onComplete: function() {}
    });
});

输出示例‌:

[候选类] com.example.a.a.b.c
[候选类] com.example.d.e.f.g
...

步骤 2:分析类的继承关系和方法签名

对候选类进行深度检查,判断其是否继承或实现了 Map 接口,并验证是否包含 put() 方法

function analyzeClass(targetClass) {
    Java.perform(function() {
        var clazz = Java.use(targetClass);
        
        // 检查是否实现 java.util.Map 接口
        var interfaces = clazz.class.getInterfaces();  // 获取当前类‌直接实现的所有接口‌(不包含父类实现的接口)
        interfaces.forEach(function(intf) {
            if (intf.getName().contains("java.util.Map")) {
                console.log("[实现Map接口] ", targetClass);
            }
        });

        // 检查是否存在 put(Object, Object) 方法
        var methods = clazz.class.getDeclaredMethods();  // 获取当前类‌声明的所有方法‌(包括 private/protected 方法,但不包含继承的方法)
        methods.forEach(function(method) {
            if (method.getName() === "put" && 
                method.getParameterTypes().length === 2) {
                console.log("[包含put方法] ", targetClass);
            }
        });
    });
}

// 调用示例
analyzeClass("com.example.a.a.b.c");

‌输出关键信息‌:

[实现Map接口] com.example.a.a.b.c
[包含put方法] com.example.a.a.b.c

步骤 3:动态 Hook 候选类的 put() 方法

对筛选出的类进行动态 Hook,观察参数传递和调用栈。

function hookCandidateClass(className) {
    Java.perform(function() {
        var targetClass = Java.use(className);
        targetClass.put.implementation = function(key, value) {
            console.log(`[${className}] put被调用: key=${key}, value=${value}`);
            // 打印调用栈
            var stackTrace = Java.use("android.util.Log").getStackTraceString(
                Java.use("java.lang.Throwable").$new()
            );
            console.log(stackTrace);
            return this.put(key, value);
        };
    });
}

// 调用示例
hookCandidateClass("com.example.a.a.b.c");

‌输出示例‌

[com.example.a.a.b.c] put被调用: key=sign, value=5c8d7a3b
android.util.Log.getStackTraceString(Native Method)
com.example.a.a.b.c.put(Native Method)
com.example.network.RequestBuilder.buildParams(RequestBuilder.java:20)
...

步骤 4:验证目标类

通过以下特征确认目标类:

  1. ‌参数内容匹配‌:key 为业务关键词(如 sign、token)。
  2. ‌调用栈合理‌:堆栈显示参数构建逻辑(如 RequestBuilder.buildParams())。
  3. ‌高频调用‌:仅在关键操作(如网络请求)时触发。

步骤 5:静态分析辅助验证(可选)

若动态分析结果模糊,可结合 ‌Jadx/Ghidra‌ 反编译 APK:

  1. 搜索 put( ) 方法调用,定位参数构建代码。
  2. 查找交叉引用,确认调用链中的类名。
  3. 对比动态分析结果,确认最终目标类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值