ctf中的Frida——脚本详解(零基础)
字数 1233 2025-08-22 12:23:18

Frida脚本详解与实战指南

一、Frida基础概念

1.1 什么是Hook

Hook(钩子)是一种在程序运行时拦截和修改函数行为的技术。在Frida中,我们可以通过编写脚本来"钩住"目标函数,实现参数修改、返回值替换、函数调用监控等操作。

1.2 Frida脚本基本框架

Java.perform(function () {
    // 在这里编写hook代码
    console.log("Frida脚本已附加到进程");
});
  • Java.perform(fn):确保当前线程连接到Java虚拟机并执行回调函数
  • console.log():在控制台输出信息
  • JavaScript语法:对缩进无要求,分号可选

二、Frida核心API详解

2.1 获取Java类

Java.use("完整类名")

示例:

var LoginActivity = Java.use("com.example.LoginActivity");

2.2 主动调用函数

var result = LoginActivity.a("123", "123");
console.log(result);

2.3 修改函数实现

LoginActivity.a.implementation = function(x, y) {
    // 修改原始逻辑
    return "修改后的返回值";
};

2.4 调用非静态函数

Java.choose("com.example.TargetClass", {
    onMatch: function(instance) {
        instance.nonStaticMethod();
    },
    onComplete: function() {
        console.log("搜索完成");
    }
});

2.5 修改成员变量

instance._variableName.value = newValue;

注意:当成员变量名与函数名相同时,需要在变量名前加下划线

2.6 处理动态加载的Dex

Java.enumerateClassLoaders({
    onMatch: function(loader) {
        try {
            if (loader.findClass("动态加载的类名")) {
                Java.classFactory.loader = loader;
            }
        } catch (e) {}
    },
    onComplete: function() {}
});

三、实战场景与解决方案

3.1 场景一:修改返回值绕过验证

问题:函数返回的字符串与固定值比较,需要修改返回值使其匹配

解决方案

TargetClass.targetMethod.implementation = function() {
    return "需要匹配的固定值";
};

3.2 场景二:调用非静态方法

问题:需要调用没有static修饰的成员方法

解决方案

Java.choose("com.example.TargetClass", {
    onMatch: function(instance) {
        instance.setBool_var();
    },
    onComplete: function() {}
});

3.3 场景三:修改成员变量

问题:需要修改类的成员变量值

解决方案

Java.choose("com.example.TargetClass", {
    onMatch: function(instance) {
        instance._bool_var.value = true;
    }
});

3.4 场景四:Hook动态加载的类

问题:目标类通过DexClassLoader动态加载,直接Hook会找不到类

解决方案

  1. 枚举所有类加载器
  2. 找到能加载目标类的loader
  3. 设置当前classFactory的loader
Java.enumerateClassLoaders({
    onMatch: function(loader) {
        try {
            if (loader.findClass("com.example.DynamicCheck")) {
                Java.classFactory.loader = loader;
                var DynamicCheck = Java.use("com.example.DynamicCheck");
                DynamicCheck.check.implementation = function() {
                    return true;
                };
            }
        } catch (e) {}
    }
});

3.5 场景五:从Native层获取数据

问题:关键数据(如加密密钥)存储在native层

解决方案

// Hook native方法获取key
var NativeClass = Java.use("com.example.NativeHelper");
NativeClass.getKey.implementation = function() {
    var original = this.getKey();
    console.log("获取到Key: " + original);
    return original;
};

// Hook native方法获取IV
NativeClass.getIV.implementation = function() {
    var original = this.getIV();
    console.log("获取到IV: " + original);
    return original;
};

四、CTF实战案例解析

4.1 案例一:SHA256验证绕过

题目逻辑

  • a方法接受两个相同参数,返回第一个参数的SHA256值
  • 验证条件:username的SHA256值与password相等

解决方案

Java.perform(function () {
    var LoginActivity = Java.use("com.example.LoginActivity");
    var result = LoginActivity.a("123", "123");
    console.log("Password should be: " + result);
});

4.2 案例二:字符串比较绕过

题目逻辑

  • 函数返回的字符串与固定值比较
  • 需要修改返回值使其匹配

解决方案

TargetClass.a.implementation = function() {
    return "R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=";
};

4.3 案例三:动态DEX检查绕过

题目逻辑

  • check方法在动态加载的DEX中实现
  • 需要Hook动态加载的类的方法

解决方案

Java.perform(function() {
    Java.enumerateClassLoaders({
        onMatch: function(loader) {
            try {
                if (loader.findClass("com.example.DynamicCheck")) {
                    Java.classFactory.loader = loader;
                    var DynamicCheck = Java.use("com.example.DynamicCheck");
                    DynamicCheck.check.implementation = function() {
                        return true;
                    };
                }
            } catch (e) {}
        }
    });
});

五、最佳实践与技巧

  1. 错误处理:在Hook脚本中加入try-catch块防止崩溃
  2. 调试输出:使用console.log输出关键信息
  3. 多线程处理:确保在主线程执行Java.perform
  4. 性能考虑:避免在频繁调用的函数中实现复杂逻辑
  5. 脚本模块化:将常用功能封装为函数便于复用

六、总结

Frida提供了强大的动态插桩能力,掌握以下核心技能:

  • 理解Java.perform的作用和用法
  • 熟练使用Java.use获取目标类
  • 掌握implementation修改函数实现
  • 了解Java.choose处理非静态方法
  • 能够处理动态加载的DEX
  • 熟悉从Native层获取数据的方法

通过实际CTF题目练习,可以快速提升Frida脚本编写能力,灵活应对各种逆向分析场景。

Frida脚本详解与实战指南 一、Frida基础概念 1.1 什么是Hook Hook(钩子)是一种在程序运行时拦截和修改函数行为的技术。在Frida中,我们可以通过编写脚本来"钩住"目标函数,实现参数修改、返回值替换、函数调用监控等操作。 1.2 Frida脚本基本框架 Java.perform(fn) :确保当前线程连接到Java虚拟机并执行回调函数 console.log() :在控制台输出信息 JavaScript语法:对缩进无要求,分号可选 二、Frida核心API详解 2.1 获取Java类 示例: 2.2 主动调用函数 2.3 修改函数实现 2.4 调用非静态函数 2.5 修改成员变量 注意:当成员变量名与函数名相同时,需要在变量名前加下划线 2.6 处理动态加载的Dex 三、实战场景与解决方案 3.1 场景一:修改返回值绕过验证 问题 :函数返回的字符串与固定值比较,需要修改返回值使其匹配 解决方案 : 3.2 场景二:调用非静态方法 问题 :需要调用没有static修饰的成员方法 解决方案 : 3.3 场景三:修改成员变量 问题 :需要修改类的成员变量值 解决方案 : 3.4 场景四:Hook动态加载的类 问题 :目标类通过DexClassLoader动态加载,直接Hook会找不到类 解决方案 : 枚举所有类加载器 找到能加载目标类的loader 设置当前classFactory的loader 3.5 场景五:从Native层获取数据 问题 :关键数据(如加密密钥)存储在native层 解决方案 : 四、CTF实战案例解析 4.1 案例一:SHA256验证绕过 题目逻辑 : a方法接受两个相同参数,返回第一个参数的SHA256值 验证条件:username的SHA256值与password相等 解决方案 : 4.2 案例二:字符串比较绕过 题目逻辑 : 函数返回的字符串与固定值比较 需要修改返回值使其匹配 解决方案 : 4.3 案例三:动态DEX检查绕过 题目逻辑 : check方法在动态加载的DEX中实现 需要Hook动态加载的类的方法 解决方案 : 五、最佳实践与技巧 错误处理 :在Hook脚本中加入try-catch块防止崩溃 调试输出 :使用console.log输出关键信息 多线程处理 :确保在主线程执行Java.perform 性能考虑 :避免在频繁调用的函数中实现复杂逻辑 脚本模块化 :将常用功能封装为函数便于复用 六、总结 Frida提供了强大的动态插桩能力,掌握以下核心技能: 理解Java.perform的作用和用法 熟练使用Java.use获取目标类 掌握implementation修改函数实现 了解Java.choose处理非静态方法 能够处理动态加载的DEX 熟悉从Native层获取数据的方法 通过实际CTF题目练习,可以快速提升Frida脚本编写能力,灵活应对各种逆向分析场景。