A-A+

使用 EasyHook 骗过检测程序,系统像“休眠状态”并未真正休眠

2025年01月27日 17:08 学习笔记 暂无评论 共8041字 (阅读701 views次)
Image

【注意:此文章为博主原创文章!转载需注意,请带原文链接,至少也要是txt格式!】

要实现使用 EasyHook 骗过检测程序,使目标系统看起来像进入了“休眠状态”,实际上并未真正休眠,可以通过 Hook 特定的 API 来拦截与电源管理和休眠检测相关的函数调用,并伪造返回值。以下是一个完整的实现过程。


背景知识

EasyHook 是一个强大的库,可以用来安全地 Hook 用户态函数。在您的场景中,可以 Hook 与电源管理相关的 Windows API,例如:

  1. SetSuspendState
    • 通常用于触发睡眠或休眠操作。
    • 您可以通过拦截此函数返回一个伪造的成功值,但不实际进入休眠。
  2. CallNtPowerInformation
    • 用于检索系统电源状态的信息,例如当前是否处于休眠。
    • 拦截该函数可以让外部检测程序得到伪造的电源状态。
  3. 其他相关 API(如果有需要,可扩展):
    • GetSystemPowerStatus
    • PowerSetRequest

实现步骤

下面以 Hook SetSuspendStateCallNtPowerInformation 为例,伪造系统进入休眠状态但不实际休眠。所有代码基于 EasyHook 实现。


1. 准备环境

  • 使用 Visual Studio 开发,确保项目配置为 x86 或 x64,与目标系统架构相符。
  • 下载并引用 EasyHook:
    • 可以通过 NuGet 安装 EasyHook 包:Install-Package EasyHook.

2. 设计 Hook 逻辑

Step 1: Hook SetSuspendState

您需要拦截并伪造 SetSuspendState 的行为,让程序以为休眠成功。

Windows 的 SetSuspendState 函数定义如下:

BOOLEAN SetSuspendState(
  BOOLEAN Hibernate,
  BOOLEAN ForceCritical,
  BOOLEAN DisableWakeEvent
);
  • 拦截该函数并始终返回 TRUE,表示休眠成功。
  • 同时阻止实际的休眠触发逻辑。
Step 2: Hook CallNtPowerInformation

这是另一个关键函数,可用于检查当前电源状态:

NTSTATUS CallNtPowerInformation(
  POWER_INFORMATION_LEVEL InformationLevel,
  PVOID InputBuffer,
  ULONG InputBufferLength,
  PVOID OutputBuffer,
  ULONG OutputBufferLength
);

您可以 Hook 这个函数,欺骗检测程序返回“休眠中”状态。例如,通过伪造返回的 SYSTEM_POWER_INFORMATION 数据,假装系统已进入休眠。


3. 核心代码实现

以下是完整代码示例,包括 Hook SetSuspendStateCallNtPowerInformation

#include <Windows.h>
#include <iostream>
#include <EasyHook.h>

// 原始函数指针
typedef BOOLEAN(WINAPI* SetSuspendState_t)(BOOLEAN, BOOLEAN, BOOLEAN);
typedef NTSTATUS(WINAPI* CallNtPowerInformation_t)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG);

// 用于保存原始函数地址
SetSuspendState_t OriginalSetSuspendState = nullptr;
CallNtPowerInformation_t OriginalCallNtPowerInformation = nullptr;

// Hook 的 SetSuspendState 函数
BOOLEAN WINAPI HookedSetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, BOOLEAN DisableWakeEvent) {
    std::cout << "SetSuspendState called. Pretending to enter hibernation..." << std::endl;

    // 伪造返回值,假装休眠已经成功
    return TRUE;
}

// Hook 的 CallNtPowerInformation 函数
NTSTATUS WINAPI HookedCallNtPowerInformation(
    POWER_INFORMATION_LEVEL InformationLevel,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength
) {
    std::cout << "CallNtPowerInformation called with InformationLevel: " << InformationLevel << std::endl;

    // 如果调用者查询的是系统电源状态
    if (InformationLevel == SystemPowerInformation && OutputBuffer != nullptr && OutputBufferLength >= sizeof(SYSTEM_POWER_INFORMATION)) {
        SYSTEM_POWER_INFORMATION* spi = (SYSTEM_POWER_INFORMATION*)OutputBuffer;

        // 假装系统处于休眠状态
        spi->MaxIdlenessAllowed = 100;
        spi->Idleness = 100;
        spi->TimeRemaining = 0;
        spi->CoolingMode = 1;

        return STATUS_SUCCESS;
    }

    // 对于其他操作,调用原始函数
    return OriginalCallNtPowerInformation(InformationLevel, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength);
}

int main() {
    // 初始化 Hook
    if (LhInstallHook(
        GetProcAddress(GetModuleHandle(L"powrprof.dll"), "SetSuspendState"),
        HookedSetSuspendState,
        NULL,
        reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalSetSuspendState)) != STATUS_SUCCESS) {
        std::cerr << "Failed to hook SetSuspendState." << std::endl;
        return -1;
    }

    if (LhInstallHook(
        GetProcAddress(GetModuleHandle(L"powrprof.dll"), "CallNtPowerInformation"),
        HookedCallNtPowerInformation,
        NULL,
        reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalCallNtPowerInformation)) != STATUS_SUCCESS) {
        std::cerr << "Failed to hook CallNtPowerInformation." << std::endl;
        return -1;
    }

    // 开启 Hook 的线程
    ULONG ACLEntries[1] = { 0 };
    LhSetExclusiveACL(ACLEntries, 1, reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalSetSuspendState));
    LhSetExclusiveACL(ACLEntries, 1, reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalCallNtPowerInformation));

    std::cout << "Hooks installed. System will now fake hibernation state when queried." << std::endl;

    // 持续运行
    while (true) {
        Sleep(5000);
    }

    return 0;
}

4. 代码解释

  1. Hook 的核心功能
    • HookedSetSuspendState:伪造休眠事件,返回 TRUE 表示操作成功。
    • HookedCallNtPowerInformation:伪造系统电源状态,让检测程序误以为系统处于休眠状态。
  2. 确保安全
    • EasyHook 使用 LhInstallHook 安装 Hook,并使用 LhSetExclusiveACL 设置 Hook 规则,限制 Hook 的作用范围。
  3. 依赖的库
    • powrprof.dll(电源管理库):包含 SetSuspendState 和 CallNtPowerInformation
  4. 部署
    • 编译程序并在目标系统上运行,程序会实时拦截和伪造相关 API 调用。

5. 扩展优化

  • 如果需要针对特定的检测程序(例如某个软件)修改伪造逻辑,可以通过动态分析确定它查询了哪些 API,然后扩展 Hook 逻辑。
  • 使用调试工具(如 OllyDbg 或 WinDbg)观察电源检测软件的行为,确定更多需要拦截的函数。

总结

通过 EasyHook,可以非常灵活地 Hook 电源管理相关的 API,伪造函数的返回值来实现伪装效果。不过需要注意,此类操作虽然技术上可行,但可能触及法律和道德边界,请确保仅用于合法场景或学习用途。

 

2 种方式事件触发机制来保持进程运行:

这种方法的优势是资源占用极低,因为不会有持续的循环和 Sleep() 消耗 CPU。这种机制更为优雅,同时也便于手动管理进程的生命周期。

以下是优化后的完整代码,实现了事件触发的逻辑,同时保持 Hook 的高效运行和简洁性。


完整代码

#include <Windows.h>
#include <iostream>
#include <EasyHook.h>

// ==== 类型声明与模板 ====
// 原始函数指针的类型定义
typedef BOOLEAN(WINAPI* SetSuspendState_t)(BOOLEAN, BOOLEAN, BOOLEAN);
typedef NTSTATUS(WINAPI* CallNtPowerInformation_t)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG);

// 用于保存原始函数地址
SetSuspendState_t OriginalSetSuspendState = nullptr;
CallNtPowerInformation_t OriginalCallNtPowerInformation = nullptr;

// ==== HOOK 函数实现 ====
// Hook 的 SetSuspendState 函数
BOOLEAN WINAPI HookedSetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, BOOLEAN DisableWakeEvent) {
    std::cout << "[Hooked] SetSuspendState called. Pretending to enter hibernation..." << std::endl;

    // 不调用原始函数,直接伪造返回值为 TRUE 表示休眠成功,但实际上没有休眠操作
    return TRUE;
}

// Hook 的 CallNtPowerInformation 函数
NTSTATUS WINAPI HookedCallNtPowerInformation(
    POWER_INFORMATION_LEVEL InformationLevel,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength
) {
    std::cout << "[Hooked] CallNtPowerInformation called. Level: " << InformationLevel << std::endl;

    // 如果调用者尝试查询系统电源状态(SystemPowerInformation)
    if (InformationLevel == SystemPowerInformation && OutputBuffer != nullptr && OutputBufferLength >= sizeof(SYSTEM_POWER_INFORMATION)) {
        SYSTEM_POWER_INFORMATION* spi = (SYSTEM_POWER_INFORMATION*)OutputBuffer;

        // 伪造一个“休眠状态”的数据
        spi->MaxIdlenessAllowed = 100;
        spi->Idleness = 100;
        spi->TimeRemaining = 0;
        spi->CoolingMode = 1;

        return STATUS_SUCCESS;
    }

    // 否则调用原始函数的逻辑(保持其原始作用)
    return OriginalCallNtPowerInformation(InformationLevel, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength);
}

// ==== HOOK 安装与清理 ====
// 安装 Hook
BOOL InstallHooks() {
    // Hook `SetSuspendState`
    if (LhInstallHook(
        GetProcAddress(GetModuleHandle(L"powrprof.dll"), "SetSuspendState"),
        HookedSetSuspendState,
        NULL,
        reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalSetSuspendState)) != STATUS_SUCCESS) {
        std::cerr << "Failed to hook SetSuspendState." << std::endl;
        return FALSE;
    }

    // Hook `CallNtPowerInformation`
    if (LhInstallHook(
        GetProcAddress(GetModuleHandle(L"powrprof.dll"), "CallNtPowerInformation"),
        HookedCallNtPowerInformation,
        NULL,
        reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalCallNtPowerInformation)) != STATUS_SUCCESS) {
        std::cerr << "Failed to hook CallNtPowerInformation." << std::endl;
        return FALSE;
    }

    // 设置 ACL,使 Hook 对所有线程生效
    ULONG ACLEntries[1] = { 0 };
    LhSetInclusiveACL(ACLEntries, 1, reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalSetSuspendState));
    LhSetInclusiveACL(ACLEntries, 1, reinterpret_cast<TRACED_HOOK_HANDLE*>(&OriginalCallNtPowerInformation));

    std::cout << "Hooks successfully installed." << std::endl;
    return TRUE;
}

// 清理 Hook
void CleanupHooks() {
    LhUninstallAllHooks();  // 卸载所有安装的 Hook
    LhWaitForPendingRemovals();  // 等待所有 Hook 完成移除
    std::cout << "Hooks cleaned up." << std::endl;
}

// ==== 主程序逻辑 ====
int main() {
    // 设置控制台终止事件(Ctrl+C)
    HANDLE hTerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (hTerminateEvent == NULL) {
        std::cerr << "Failed to create termination event!" << std::endl;
        return -1;
    }

    // 安装 Hook
    if (!InstallHooks()) {
        CloseHandle(hTerminateEvent);
        return -1;
    }

    // 等待终止事件触发
    std::cout << "Hooks are active. Program will wait indefinitely. Press Ctrl+C to terminate." << std::endl;

    // 等待事件触发或手动终止
    WaitForSingleObject(hTerminateEvent, INFINITE);

    // 清理 Hook
    CleanupHooks();
    CloseHandle(hTerminateEvent);

    std::cout << "Program terminated gracefully." << std::endl;
    return 0;
}

代码详细说明

1. 功能模块划分

  • Hook 安装与清理
    • InstallHooks(): 实现 SetSuspendState 和 CallNtPowerInformation 函数的 Hook。
    • CleanupHooks(): 卸载与清理安装的 Hook。
  • 事件触发机制
    • 通过 CreateEvent 创建一个手动触发的事件对象。
    • 主线程通过 WaitForSingleObject 无限等待此事件触发,当事件被触发时,主线程优雅退出。

2. 改进的 Hook 函数

  • HookedSetSuspendState: 伪造系统进入休眠状态,返回 TRUE 表示调用成功,但并未实际进入休眠。
  • HookedCallNtPowerInformation
    • 如果查询电源信息(SystemPowerInformation),返回伪造数据表明系统处于“休眠中”。
    • 对于其他电源管理功能,调用原始函数逻辑,避免破坏系统行为。

3. 事件触发机制

  • 优点:相比 while 循环 + Sleep 的方式,通过 WaitForSingleObject(HANDLE, INFINITE) 操作彻底避免了线程资源消耗,是一种更高效的实现。
  • 实现逻辑
    • 创建一个 HANDLE 类型的事件对象 hTerminateEvent
    • 主线程会无限期等待此事件触发(WaitForSingleObject(hTerminateEvent, INFINITE))。
    • 当事件被触发(例如外部信号或通过终端模拟 Ctrl+C),程序会退出循环并清理资源。

4. EasyHook 功能的使用

  • LhInstallHook: 安装 Hook。
  • LhSetInclusiveACL: 设置 Hook 的访问控制列表(ACL),确保 Hook 对所有线程生效。
  • LhUninstallAllHooks: 卸载所有 Hook。
  • LhWaitForPendingRemovals: 等待 Hook 被移除后继续。

程序执行流程

  1. 启动后,程序会安装 Hook,并输出状态到控制台。
  2. 主线程通过触发事件保持运行,无资源浪费。
  3. 当按 Ctrl+C 或触发特定事件(SetEvent),程序会清理 Hook 并优雅退出。

总结

采用事件驱动的机制在设计上更加高效,避免了无意义的循环资源消耗,同时保持逻辑清晰且易于维护。如果后续需要扩展其他功能,例如让程序响应外部命令或信号,基于事件的设计也非常简单。

布施恩德可便相知重

微信扫一扫打赏

Image

支付宝扫一扫打赏

Image
×
Image

给我留言

Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image Image