在C++中使用HOOK修改sleep函数的方法

在 C++ 中使用 HOOK 技术修改 sleep 函数(通常指 Windows API 的 Sleep 函数或 Unix/Linux 的 sleep/usleep)是一种常见的底层编程技术,主要用于拦截和修改函数的行为。下面我将分别介绍在 ​Windows​ 和 ​Linux​ 环境下的实现方法。

图片[1]_在C++中使用HOOK修改sleep函数的方法_知途无界

🪟 Windows 环境(Hook Sleep API)

方法 1:使用 Detours(微软官方推荐库)

Detours 是微软研究院开发的 DLL 注入和 API Hook 库。

步骤:

  1. 下载并配置 Detours
    从 GitHub 获取:https://github.com/microsoft/Detours
  2. 编写 Hook 代码
// hook_sleep.cpp
#include <windows.h>
#include <detours.h>
#include <iostream>

// 原始 Sleep 函数指针
static VOID(WINAPI* OriginalSleep)(DWORD dwMilliseconds) = Sleep;

// Hook 后的 Sleep 函数
VOID WINAPI HookedSleep(DWORD dwMilliseconds) {
    std::cout << "Sleep called with: " << dwMilliseconds << " ms" << std::endl;
    
    // 修改睡眠时间:例如减半
    DWORD newTime = dwMilliseconds / 2;
    if (newTime == 0 && dwMilliseconds != 0)
        newTime = 1;

    // 调用原始函数
    OriginalSleep(newTime);
}

// 安装 Hook
void InstallHook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)OriginalSleep, HookedSleep);
    DetourTransactionCommit();
}

// 卸载 Hook
void UninstallHook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&(PVOID&)OriginalSleep, HookedSleep);
    DetourTransactionCommit();
}

// DLL 入口点(如果是 DLL 注入方式)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        InstallHook();
        break;
    case DLL_PROCESS_DETACH:
        UninstallHook();
        break;
    }
    return TRUE;
}
  1. 编译并注入目标进程
    使用 Detours 提供的 withdll.exe 或手动注入 DLL。

方法 2:Inline Hook(直接修改机器码)

适用于无第三方库的场景,但更复杂。

#include <windows.h>
#include <iostream>

typedef void(WINAPI* SleepFunc)(DWORD);

SleepFunc originalSleep = &Sleep;

__declspec(naked) void HookedSleep(DWORD ms) {
    __asm {
        push ebp
        mov ebp, esp
        pushad
    }

    // 这里可以修改 ms 参数
    // 注意:参数在栈上 [ebp + 8]

    __asm {
        popad
        jmp originalSleep  // 跳回原始函数
    }
}

void SetupInlineHook() {
    DWORD oldProtect;
    VirtualProtect((LPVOID)Sleep, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    
    // JMP rel32 指令覆盖前5字节
    BYTE jmpCode[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 };
    DWORD offset = (DWORD)((BYTE*)HookedSleep - (BYTE*)Sleep - 5);
    memcpy(jmpCode + 1, &offset, 4);
    
    memcpy((LPVOID)Sleep, jmpCode, 5);
    VirtualProtect((LPVOID)Sleep, 5, oldProtect, &oldProtect);
}

⚠️ 注意:Inline Hook 可能被反病毒软件检测,且需处理不同编译器/架构的差异。


🐧 Linux 环境(Hook sleep/sleep_us)

Linux 下可使用 LD_PRELOAD 劫持共享库函数。

示例:劫持 sleep() 函数

// hook_sleep.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>

// 原始 sleep 函数指针
static unsigned int (*original_sleep)(unsigned int seconds) = NULL;

unsigned int sleep(unsigned int seconds) {
    if (!original_sleep)
        original_sleep = dlsym(RTLD_NEXT, "sleep");

    printf("Hooked sleep: %u seconds\n", seconds);
    
    // 修改睡眠时间,例如减半
    unsigned int new_seconds = seconds / 2;
    if (new_seconds == 0 && seconds != 0)
        new_seconds = 1;

    return original_sleep(new_seconds);
}

编译与使用

gcc -shared -fPIC -o hook_sleep.so hook_sleep.c -ldl

运行目标程序时预加载该库:

LD_PRELOAD=./hook_sleep.so ./your_program

劫持 usleep()nanosleep()

类似地,可以劫持更精确的时间函数:

// hook_usleep.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>

static int (*original_usleep)(useconds_t usec) = NULL;

int usleep(useconds_t usec) {
    if (!original_usleep)
        original_usleep = dlsym(RTLD_NEXT, "usleep");

    printf("Hooked usleep: %d us\n", usec);
    
    useconds_t new_usec = usec / 2;
    if (new_usec == 0 && usec != 0)
        new_usec = 1;

    return original_usleep(new_usec);
}

编译方式相同。


⚠️ 注意事项

  1. 权限问题​:Hook 通常需要管理员/root 权限。
  2. 稳定性​:错误的 Hook 可能导致程序崩溃或死锁。
  3. 兼容性​:不同系统版本、编译器可能影响 Hook 效果。
  4. 法律与道德​:仅在授权环境下使用,勿用于恶意目的。
  5. 线程安全​:确保 Hook 函数是线程安全的。

✅ 总结

平台方法优点缺点
WindowsDetours稳定、易用需第三方库
WindowsInline Hook无需库、灵活复杂、易被检测
LinuxLD_PRELOAD简单、无需修改目标程序仅适用于动态链接库函数
通用源码替换最可靠需有源码控制权

如果你只是想在自己的程序中修改 sleep 行为,更简单的方法是封装自己的 MySleep 函数,而不是全局 Hook。但如果是调试或监控外部程序,上述 HOOK 技术则非常有用。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞62 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容