Frida Windows API Hook 原理和实践 - 实战 PicoCTF 2025 两道re题
字数 1923 2025-08-29 08:30:06

Frida Windows API Hook 原理与实践教程

一、Frida 简介与环境配置

Frida 是一款强大的动态插桩工具,允许将 JavaScript 代码注入到正在运行的进程中,拦截和修改函数调用。在安全研究和 CTF 竞赛中有广泛应用。

环境配置步骤

  1. 安装 Python

    • 从 Python 官网下载安装
    • 安装时勾选"Add Python to PATH"选项
    • 确保可通过命令行调用 pythonpip
  2. 安装 Frida 工具

    pip install frida-tools
    
  3. 验证安装

    frida --version
    

    成功安装会显示类似 16.x.x 的版本号

二、Frida Hook Windows API 原理

基本原理流程

  1. 查找目标函数地址

    • 通过加载相应 DLL (如 kernel32.dlluser32.dll)
    • 使用 Module.findExportByName()Module.getExportByName() 获取函数地址
  2. 保存原始指令

    • 保存目标函数开头的几条指令(通常5-10字节)
    • 用于Hook后仍能调用原始函数
  3. 写入跳转指令

    • 用跳转指令(通常是JMP指令)覆盖目标函数开头
    • 将执行流重定向到Frida的JavaScript Hook函数
  4. JavaScript Hook函数处理

    • 读取和修改函数参数
    • 执行自定义逻辑
    • 决定是否调用原始函数
    • 读取和修改函数返回值
  5. 调用原始函数(可选)

    • 将参数传递给原始函数
    • 执行原始函数并获取返回值
  6. 恢复执行

    • Hook函数执行完毕后,控制权返回调用方

技术实现细节

Frida采用Inline Hook方式实现:

  1. 跳转到frida-agent.dll处理寄存器环境
  2. 实现对参数的修改
  3. 恢复被覆盖的字节完成函数调用

三、实战案例1:PicoCTF 2025 Binary Instrumentation 1 (200 pts)

题目描述

"Can you wake up my program to get the flag?"
程序运行后长时间无响应。

逆向分析

  1. 程序通过API读取PEB结构体获取ImageBase
  2. 经过PE格式内存映射过程(类似壳的功能)
  3. 解密后进入真正程序逻辑
  4. 真实程序包含大量Sleep函数调用,导致长时间等待

Frida解决方案

  1. 检测API调用

    frida-trace.exe -i "!Sleep*" -f bininst1.exe
    

    确认程序调用了Sleep函数

  2. Hook Sleep函数脚本

    // frida_WinAPI_Sleep_hook.js
    const sleep = Module.findExportByName("kernel32.dll", "Sleep");
    Interceptor.attach(sleep, {
        onEnter: function(args) {
            console.log("Original Sleep time: " + args[0].toInt32() + "ms");
            args[0] = ptr(1); // 修改Sleep时间为1ms
        }
    });
    
  3. 执行脚本

    frida -l frida_WinAPI_Sleep_hook.js bininst1.exe
    

    直接跳过长时间等待获取flag

获取的flag

cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YWNjMzh9 (base64解码后得到真实flag)

四、实战案例2:PicoCTF 2025 Binary Instrumentation 2 (300 pts)

题目描述

程序本应创建文件并写入flag,但出现问题,要求拦截文件写入函数查看问题。

逆向分析

  1. 同样是PE文件内存映射加载过程
  2. 真正执行部分调用CreateFileA和WriteFile
  3. 问题在于文件名为<Insert path here>,包含非法字符导致失败

Frida解决方案

  1. 检测API调用

    frida-trace -f bininst2.exe -i CreateFile* -i WriteFile*
    
  2. Hook CreateFileA

    // CreateFileA.js
    const createFileA = Module.findExportByName("kernel32.dll", "CreateFileA");
    Interceptor.attach(createFileA, {
        onEnter: function(args) {
            console.log("Original filename: " + args[0].readAnsiString());
            // 修改文件名为合法路径
            args[0] = Memory.allocUtf8String("C:\\temp\\flag.txt");
        },
        onLeave: function(retval) {
            console.log("CreateFileA returned: " + retval);
        }
    });
    
  3. Hook WriteFile

    // WriteFile.js
    const writeFile = Module.findExportByName("kernel32.dll", "WriteFile");
    Interceptor.attach(writeFile, {
        onEnter: function(args) {
            this.fileHandle = args[0];
            this.buffer = args[1];
            this.length = args[2].toInt32();
        },
        onLeave: function(retval) {
            if (this.length > 0) {
                const data = this.buffer.readByteArray(this.length);
                console.log("WriteFile content: " + data);
            }
        }
    });
    
  4. 获取的flag
    cGljb0NURntmcjFkYV9mMHJfYjFuX2luNXRydW0zbnQ0dGlvbiFfYjIxYWVmMzl9 (base64解码后得到真实flag)

五、关键API Hook模板

1. 基本Hook模板

const func = Module.findExportByName("dllname.dll", "functionName");
Interceptor.attach(func, {
    onEnter: function(args) {
        // 访问参数: args[0], args[1], ...
        // 修改参数: args[0] = newValue
    },
    onLeave: function(retval) {
        // 访问返回值: retval
        // 修改返回值: retval.replace(newValue)
    }
});

2. 常用Windows API Hook示例

Sleep Hook

const sleep = Module.findExportByName("kernel32.dll", "Sleep");
Interceptor.attach(sleep, {
    onEnter: function(args) {
        console.log("Sleep time: " + args[0].toInt32() + "ms");
        args[0] = ptr(1); // 修改Sleep时间
    }
});

CreateFileA Hook

const createFileA = Module.findExportByName("kernel32.dll", "CreateFileA");
Interceptor.attach(createFileA, {
    onEnter: function(args) {
        const filename = args[0].readAnsiString();
        console.log("Creating file: " + filename);
        // 修改文件名
        args[0] = Memory.allocUtf8String("new_path.txt");
    }
});

WriteFile Hook

const writeFile = Module.findExportByName("kernel32.dll", "WriteFile");
Interceptor.attach(writeFile, {
    onEnter: function(args) {
        this.buffer = args[1];
        this.length = args[2].toInt32();
    },
    onLeave: function(retval) {
        const data = this.buffer.readByteArray(this.length);
        console.log("Written data: " + data);
    }
});

六、调试技巧与注意事项

  1. 使用frida-trace快速定位API

    frida-trace -i "!Sleep*" -f target.exe
    
  2. 处理不同参数类型

    • 字符串参数: args[0].readAnsiString()args[0].readUtf16String()
    • 数值参数: args[0].toInt32()args[0].toInt64()
    • 指针参数: args[0] 直接使用
  3. 内存分配

    const newStr = Memory.allocUtf8String("new string");
    
  4. 错误处理

    try {
        const value = args[0].readAnsiString();
    } catch (e) {
        console.log("Error reading string: " + e);
    }
    
  5. 多线程注意事项

    • Frida Hook是线程安全的
    • 但要注意共享数据的同步问题

七、总结

通过本教程,我们学习了:

  1. Frida的基本原理和Hook机制
  2. Windows API Hook的具体实现方式
  3. 两个实际CTF题目的解决方案
    • 通过Hook Sleep跳过等待
    • 通过Hook文件操作修复错误并获取flag
  4. 常用API的Hook模板和调试技巧

Frida的强大之处在于其动态插桩能力,可以无需源代码即可修改程序行为,在逆向工程和安全研究中具有重要价值。

Frida Windows API Hook 原理与实践教程 一、Frida 简介与环境配置 Frida 是一款强大的动态插桩工具,允许将 JavaScript 代码注入到正在运行的进程中,拦截和修改函数调用。在安全研究和 CTF 竞赛中有广泛应用。 环境配置步骤 安装 Python 从 Python 官网下载安装 安装时勾选"Add Python to PATH"选项 确保可通过命令行调用 python 和 pip 安装 Frida 工具 验证安装 成功安装会显示类似 16.x.x 的版本号 二、Frida Hook Windows API 原理 基本原理流程 查找目标函数地址 通过加载相应 DLL (如 kernel32.dll 、 user32.dll ) 使用 Module.findExportByName() 或 Module.getExportByName() 获取函数地址 保存原始指令 保存目标函数开头的几条指令(通常5-10字节) 用于Hook后仍能调用原始函数 写入跳转指令 用跳转指令(通常是JMP指令)覆盖目标函数开头 将执行流重定向到Frida的JavaScript Hook函数 JavaScript Hook函数处理 读取和修改函数参数 执行自定义逻辑 决定是否调用原始函数 读取和修改函数返回值 调用原始函数(可选) 将参数传递给原始函数 执行原始函数并获取返回值 恢复执行 Hook函数执行完毕后,控制权返回调用方 技术实现细节 Frida采用Inline Hook方式实现: 跳转到 frida-agent.dll 处理寄存器环境 实现对参数的修改 恢复被覆盖的字节完成函数调用 三、实战案例1:PicoCTF 2025 Binary Instrumentation 1 (200 pts) 题目描述 "Can you wake up my program to get the flag?" 程序运行后长时间无响应。 逆向分析 程序通过API读取PEB结构体获取ImageBase 经过PE格式内存映射过程(类似壳的功能) 解密后进入真正程序逻辑 真实程序包含大量Sleep函数调用,导致长时间等待 Frida解决方案 检测API调用 确认程序调用了Sleep函数 Hook Sleep函数脚本 执行脚本 直接跳过长时间等待获取flag 获取的flag cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YWNjMzh9 (base64解码后得到真实flag) 四、实战案例2:PicoCTF 2025 Binary Instrumentation 2 (300 pts) 题目描述 程序本应创建文件并写入flag,但出现问题,要求拦截文件写入函数查看问题。 逆向分析 同样是PE文件内存映射加载过程 真正执行部分调用CreateFileA和WriteFile 问题在于文件名为 <Insert path here> ,包含非法字符导致失败 Frida解决方案 检测API调用 Hook CreateFileA Hook WriteFile 获取的flag cGljb0NURntmcjFkYV9mMHJfYjFuX2luNXRydW0zbnQ0dGlvbiFfYjIxYWVmMzl9 (base64解码后得到真实flag) 五、关键API Hook模板 1. 基本Hook模板 2. 常用Windows API Hook示例 Sleep Hook CreateFileA Hook WriteFile Hook 六、调试技巧与注意事项 使用frida-trace快速定位API 处理不同参数类型 字符串参数: args[0].readAnsiString() 或 args[0].readUtf16String() 数值参数: args[0].toInt32() 或 args[0].toInt64() 指针参数: args[0] 直接使用 内存分配 错误处理 多线程注意事项 Frida Hook是线程安全的 但要注意共享数据的同步问题 七、总结 通过本教程,我们学习了: Frida的基本原理和Hook机制 Windows API Hook的具体实现方式 两个实际CTF题目的解决方案 通过Hook Sleep跳过等待 通过Hook文件操作修复错误并获取flag 常用API的Hook模板和调试技巧 Frida的强大之处在于其动态插桩能力,可以无需源代码即可修改程序行为,在逆向工程和安全研究中具有重要价值。