You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何定义EAX传参的C++函数?Detours hook游戏mbstowcs问题

解决自定义调用约定函数的Detours Hook问题

1. 明确目标函数的调用约定细节

从你的IDA反编译代码可以拆解出这个mbstowcs的参数传递规则:

  • 第一个参数LPWSTR lpWideCharStr:通过EAX寄存器传递
  • 第二个参数LPCSTR lpMultiByteStr:通过EDX寄存器传递
  • 第三个参数int cchWideChar:通过ECX寄存器传递(代码开头push ecx后存入栈中作为局部变量)
  • 返回值:标准int类型,通过EAX寄存器返回

这不是MSVC支持的标准调用约定(比如__fastcall是ECX/EDX传前两个参数),属于旧游戏自定义的调用规则,必须手动处理寄存器和栈帧。

2. 定义符合该调用约定的Hook函数

使用MSVC的__declspec(naked)关键字定义无栈帧的函数,手动编写汇编处理参数传递,再调用C++实现的逻辑函数:

核心逻辑函数

负责实际Hook逻辑(参数修改、日志记录等),用标准C++写法:

#include <windows.h>

// 参数顺序对应目标函数的三个参数
int MyMbstowcs_Impl(LPWSTR lpWideCharStr, LPCSTR lpMultiByteStr, int cchWideChar) {
    // 自定义逻辑示例:打印参数、替换字符串、修改转换长度等
    // ...

    // 可在这里调用原函数并处理返回值,或直接返回自定义结果
    return 0;
}

Naked Hook函数

完全用汇编编写,处理寄存器参数的保存、调用逻辑函数、转发到原函数:

// 原函数指针,由Detours填充地址
extern "C" int(*OriginalMbstowcs)();

__declspec(naked) int MyMbstowcs() {
    __asm {
        // 保存原函数用到的寄存器,避免后续调用破坏环境
        push ebx
        push esi
        push edi
        push ebp

        // 将寄存器参数压栈,供核心逻辑函数调用
        push ecx    // 第三个参数:cchWideChar
        push edx    // 第二个参数:lpMultiByteStr
        push eax    // 第一个参数:lpWideCharStr

        // 调用核心逻辑函数
        call MyMbstowcs_Impl

        // 清理栈中压入的三个参数
        add esp, 0Ch

        // 恢复之前保存的寄存器
        pop ebp
        pop edi
        pop esi
        pop ebx

        // 跳转到原函数的trampoline(Detours生成),执行原逻辑
        jmp OriginalMbstowcs
    }
}

3. 使用Detours完成Hook

按照Detours标准流程,获取目标函数地址并挂载Hook:

#include <detours.h>

int main() {
    // 获取游戏模块基地址,替换为你的游戏EXE/DLL名称
    HMODULE hGameModule = GetModuleHandleA("YourGame.exe");
    if (!hGameModule) return 1;

    // 计算目标函数绝对地址(IDA中偏移为0x43A9D4)
    OriginalMbstowcs = (int(*)())((BYTE*)hGameModule + 0x43A9D4);

    // 启动Detours事务
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());

    // 挂载Hook:将目标函数替换为我们的MyMbstowcs
    DetourAttach(&(PVOID&)OriginalMbstowcs, MyMbstowcs);

    // 提交事务
    LONG error = DetourTransactionCommit();
    if (error != NO_ERROR) {
        // 处理Hook失败逻辑
        return 1;
    }

    // 保持进程运行,或注入到游戏进程中
    // ...

    return 0;
}

关键注意事项

  • 必须用__declspec(naked):禁止编译器自动生成栈帧和寄存器处理代码,完全手动控制执行流程
  • 寄存器保存:原函数用到EBX/ESI/EDI/EBP,必须在调用逻辑函数前保存、调用后恢复,避免破坏原函数执行环境
  • 原函数指针类型:因是自定义调用约定,直接用int(*)()即可,参数在汇编中处理
  • 注入方式:如果是外部工具,需将Hook代码注入游戏进程(可使用Detours的DetourCreateProcessWithDll或其他注入方法)

内容的提问来源于stack exchange,提问作者panel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:06:03