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

如何检测外部进程通过OpenProcess打开我方进程句柄并获通知?

检测外部作弊器的进程句柄读取行为

一、用户态检测方案(无需内核驱动)

1. 未公开API句柄枚举与权限校验

Windows没有公开的全局句柄枚举函数,但可以通过NtQuerySystemInformation(需动态加载)获取系统所有句柄信息,再筛选指向目标游戏进程且带有PROCESS_VM_READ权限的句柄。

示例C++实现:

#include <windows.h>
#include <winternl.h>
#include <stdio.h>

// 定义未公开API与结构体
typedef NTSTATUS(WINAPI* pNtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
    PVOID Object;
    HANDLE UniqueProcessId;
    HANDLE HandleValue;
    ULONG GrantedAccess;
    USHORT CreatorBackTraceIndex;
    USHORT ObjectTypeIndex;
    ULONG HandleAttributes;
    ULONG Reserved;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;

typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
    ULONG NumberOfHandles;
    ULONG Reserved;
    SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;

void ScanSuspiciousHandles(DWORD gamePid) {
    HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
    pNtQuerySystemInformation NtQuerySystemInfo = (pNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");

    ULONG bufSize = 0x10000;
    PVOID buf = malloc(bufSize);
    NTSTATUS status;

    // 动态调整缓冲区大小
    while ((status = NtQuerySystemInfo((SYSTEM_INFORMATION_CLASS)0x10, buf, bufSize, &bufSize)) == STATUS_INFO_LENGTH_MISMATCH) {
        free(buf);
        buf = malloc(bufSize);
    }

    if (NT_SUCCESS(status)) {
        PSYSTEM_HANDLE_INFORMATION_EX handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)buf;
        for (ULONG i = 0; i < handleInfo->NumberOfHandles; i++) {
            auto& handle = handleInfo->Handles[i];
            // ObjectTypeIndex=7对应进程对象(不同Windows版本可能需验证调整)
            if (handle.ObjectTypeIndex != 7) continue;
            // 跳过游戏进程自身的句柄
            if ((DWORD)handle.UniqueProcessId == gamePid) continue;
            // 检查目标是否为游戏进程且拥有读权限
            if ((DWORD)handle.Object == gamePid && (handle.GrantedAccess & PROCESS_VM_READ)) {
                printf("可疑进程[%d]持有游戏进程句柄,权限包含PROCESS_VM_READ\n", (DWORD)handle.UniqueProcessId);
            }
        }
    }
    free(buf);
}

2. API挂钩监控OpenProcess/ReadProcessMemory

使用Detours或EasyHook等库,在用户态挂钩目标API,拦截对游戏进程的读取请求:

  • 挂钩OpenProcess:检测是否有进程以PROCESS_VM_READ权限打开游戏进程
  • 挂钩ReadProcessMemory:监控对游戏进程内存的读取操作

示例Detours挂钩OpenProcess的代码:

#include <windows.h>
#include <detours.h>
#include <stdio.h>

#define GAME_PID 1234 // 替换为你的游戏进程ID

typedef HANDLE(WINAPI* pOpenProcess)(
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    DWORD dwProcessId
);

pOpenProcess OriginalOpenProcess = NULL;

HANDLE WINAPI HookedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
    if (dwProcessId == GAME_PID && (dwDesiredAccess & PROCESS_VM_READ)) {
        DWORD callerPid = GetCurrentProcessId();
        printf("进程[%d]尝试以PROCESS_VM_READ权限打开游戏进程\n", callerPid);
        // 可选:拒绝请求,返回NULL
        // return NULL;
    }
    return OriginalOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
}

void InitHook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    OriginalOpenProcess = (pOpenProcess)DetourFindFunction("kernel32.dll", "OpenProcess");
    DetourAttach(&(PVOID&)OriginalOpenProcess, HookedOpenProcess);
    DetourTransactionCommit();
}

3. 内存页保护陷阱

通过VirtualProtect给游戏敏感内存区域添加PAGE_GUARD属性,当外部进程读取该区域时触发异常,在游戏进程的异常处理中捕获并告警:

#include <windows.h>
#include <stdio.h>

#define SENSITIVE_MEM_ADDR 0x00000000 // 替换为游戏敏感内存地址

LONG WINAPI GuardPageExceptionHandler(PEXCEPTION_POINTERS ep) {
    if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_GUARD_PAGE) {
        DWORD callerPid;
        GetWindowThreadProcessId(GetForegroundWindow(), &callerPid);
        printf("进程[%d]访问受保护的游戏内存区域\n", callerPid);
        // 移除保护,避免重复触发
        VirtualProtect(ep->ExceptionRecord->ExceptionAddress, 4096, PAGE_READWRITE, NULL);
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

void SetupMemoryGuard() {
    SetUnhandledExceptionFilter(GuardPageExceptionHandler);
    DWORD oldProtect;
    VirtualProtect((PVOID)SENSITIVE_MEM_ADDR, 4096, PAGE_READWRITE | PAGE_GUARD, &oldProtect);
}

二、关键注意事项

  • NtQuerySystemInformation是未公开API,不同Windows版本的结构体定义可能有变化,需做好兼容性测试
  • 全局API挂钩需要注入到所有潜在作弊进程中,可使用EasyHook等支持跨进程挂钩的库
  • VAC等商业反作弊会结合句柄枚举、API挂钩与行为分析(如频繁读取特定内存区域的进程)提升检测准确率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 07:50:55