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

Inline Hook目标程序函数后程序崩溃的原因排查

问题描述

目标程序代码

#include <iostream>

int sum(int x, int y) {
    std::cout << "function";
    return x + y;
}

int main()
{
    while (true) {
        std::cin.get();
        std::cout << sum(1, 2);
    }
}

Hook实现代码

// dllmain.cpp : Define o ponto de entrada para o aplicativo DLL.
#include "pch.h"
#include "Windows.h"
#include <iostream>

typedef int(__cdecl* sum) (int x, int y);

sum osum;

int __cdecl hsum(int x, int y) {
    return osum(x, y*5);
}

bool Detour32(void* src, void* dst, int len)
{
    if (len < 5) return false;

    DWORD curProtection;
    VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);

    memset(src, 0x90, len);

    uintptr_t relativeAddress = ((uintptr_t)dst - (uintptr_t)src) - 5;

    *(BYTE*)src = 0xE9;
    *(uintptr_t*)((uintptr_t)src + 1) = relativeAddress;

    DWORD temp;
    VirtualProtect(src, len, curProtection, &temp);

    return true;
}

char* TrampHook32(BYTE* src, BYTE* dst, const intptr_t len)
{
    // Make sure the length is greater than 5
    if (len < 5) return 0;

    // Create the gateway (len + 5 for the overwritten bytes + the jmp)
    BYTE* gateway = (BYTE*)VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    //Write the stolen bytes into the gateway
    memcpy(gateway, src, len);

    // Get the gateway to destination addy
    intptr_t  gatewayRelativeAddr = ((intptr_t)src - (intptr_t)gateway) - 5;

    // Add the jmp opcode to the end of the gateway
    *(char*)((intptr_t)gateway + len) = 0xE9;

    // Add the address to the jmp
    *(intptr_t*)((intptr_t)gateway + len + 1) = gatewayRelativeAddr;

    // Perform the detour
    Detour32(src, dst, len);

    return (char*)gateway;
}

DWORD WINAPI HackThread(HMODULE hModule) {
    //Create Console
    AllocConsole();
    FILE* f;
    freopen_s(&f, "CONOUT$", "w", stdout);

    uintptr_t moduleBase = (uintptr_t)GetModuleHandle(L"testtt.exe");
    osum = (sum)(moduleBase + 0x123d0);
    osum = (sum)TrampHook32((BYTE*)osum, (BYTE*)hsum, 5);

    fclose(f);
    FreeConsole();
    return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)HackThread, hModule, 0, nullptr));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

问题说明

已确认DLL注入逻辑正常,Cheat Engine调试显示跳转生效,程序进入自定义替换函数后执行部分指令触发崩溃,需定位崩溃原因。

崩溃原因与解决方案

1. 指令截断(最高概率)

当前调用TrampHook32时硬编码偷取原函数前5字节,如果5字节没有刚好覆盖完整的多条指令,而是截断了某一条指令,网关执行半条指令时会触发非法指令异常直接崩溃。
解决方案:到Ghidra中查看sum函数入口的汇编指令,统计前N条完整指令的总长度,只要总长度≥5,就将TrampHook32的第三个参数改为这个总长度,禁止硬编码为5。

2. 调用约定不匹配

当前函数指针使用__cdecl约定,如果原sum函数编译时采用__stdcall、__fastcall等其他约定,会导致栈平衡错误,栈结构混乱触发崩溃。
解决方案:通过原函数汇编结尾判断约定,结尾为ret是__cdecl,结尾为ret 8(两个int参数占8字节)是__stdcall,对应修改函数指针的调用约定即可。

3. 架构不匹配

该Hook是32位专用实现,若DLL编译为64位,或目标程序为64位,架构不一致必然触发崩溃。需确认目标程序和DLL均为32位架构。

4. 函数入口地址错误

硬编码的偏移0x123d0可能不是sum函数的正确入口,可在Cheat Engine中跳转到moduleBase + 0x123d0地址,对比汇编是否与Ghidra中sum函数开头汇编完全一致,确认地址正确性。

5. 控制台操作异常

Hook完成后立即执行fclose和FreeConsole可能带来额外运行时异常,可先注释这两行代码,等Hook逻辑稳定后再调试控制台相关逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:06:04