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

C++中如何保护内存清理线程,防止被外部程序暂停?

解决方案

要实现对内存清理线程的保护,核心思路是通过独立监控线程检测目标线程的运行状态——一旦发现目标线程被外部暂停或终止,立即调用ExitProcess()终止整个进程。以下是两种可行的实现方案:

方案一:基于事件触发的无侵入监控

该方案通过让清理线程定期触发事件,监控线程等待事件信号,超时则判定线程异常。优点是不会干扰清理线程的正常运行。

代码实现

首先定义全局资源(用于跨线程共享事件和线程句柄):

#include <windows.h>

HANDLE hMonitorEvent = NULL;
HANDLE hCleanupThread = NULL;

修改DllMain创建事件、清理线程和监控线程:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        // 创建手动重置事件(初始无信号)
        hMonitorEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!hMonitorEvent) return FALSE;

        // 创建内存清理线程并保存句柄
        hCleanupThread = CreateThread(NULL, 0, CleanupThreadProc, NULL, 0, NULL);
        if (!hCleanupThread)
        {
            CloseHandle(hMonitorEvent);
            hMonitorEvent = NULL;
            return FALSE;
        }

        // 创建监控线程
        CreateThread(NULL, 0, MonitorThreadProc, NULL, 0, NULL);
        break;
    case DLL_PROCESS_DETACH:
        // 清理资源
        if (hCleanupThread)
        {
            TerminateThread(hCleanupThread, 0);
            CloseHandle(hCleanupThread);
        }
        if (hMonitorEvent) CloseHandle(hMonitorEvent);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}

内存清理线程(新增事件触发逻辑):

DWORD WINAPI CleanupThreadProc(LPVOID lpvParam) {
    while (TRUE)
    {
        Sleep(10000);
        SetProcessWorkingSetSize(GetCurrentProcess(), 102400, 614400);
        // 触发监控事件,告知监控线程自己正常运行
        SetEvent(hMonitorEvent);
    }
    return 0;
}

监控线程(检测事件超时):

DWORD WINAPI MonitorThreadProc(LPVOID lpvParam) {
    while (TRUE)
    {
        // 等待事件触发,超时时间设为11秒(比清理线程间隔多1秒,避免调度延迟误判)
        DWORD waitResult = WaitForSingleObject(hMonitorEvent, 11000);
        if (waitResult == WAIT_TIMEOUT)
        {
            // 超时说明清理线程被暂停或终止,直接终止进程
            ExitProcess(0);
        }
        else if (waitResult == WAIT_OBJECT_0)
        {
            // 事件正常触发,重置事件等待下一轮检测
            ResetEvent(hMonitorEvent);
        }
        else
        {
            // 等待出错,终止进程
            ExitProcess(0);
        }
    }
    return 0;
}

方案二:基于线程挂起计数的状态检测

该方案通过尝试挂起目标线程,根据返回的挂起计数判断是否被外部暂停。优点是无需修改原清理线程代码,但会短暂挂起目标线程(影响极小)。

代码实现

仅需修改监控线程逻辑,原DllMain和清理线程代码可保留(只需保存清理线程句柄):

DWORD WINAPI MonitorThreadProc(LPVOID lpvParam) {
    while (TRUE)
    {
        Sleep(1000); // 每秒检测一次
        // 尝试挂起清理线程
        DWORD suspendCount = SuspendThread(hCleanupThread);
        if (suspendCount == (DWORD)-1)
        {
            // 线程已终止,直接终止进程
            ExitProcess(0);
        }
        if (suspendCount > 0)
        {
            // 挂起计数大于0,说明线程已被外部程序暂停
            ExitProcess(0);
        }
        // 恢复线程运行
        ResumeThread(hCleanupThread);
    }
    return 0;
}

注意事项

  • 两种方案均为用户态实现,能应对Process Hacker 2等常规工具的线程暂停操作;若需更高级的保护,需结合内核级技术(如驱动),但复杂度会大幅提升。
  • 方案一中的超时时间需略大于清理线程的休眠间隔,避免因系统调度延迟导致误判。
  • 需确保线程句柄拥有足够权限,CreateThread默认返回的句柄已具备所需权限,无需额外设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:50:32