windows中如何检测自己的程序被下了硬件断点


写了调试器A(好吧这是个外挂)和测试程序B
用A给B下硬件断点,hook了 Wow64GetThreadContext ,处理断点异常时,先取ESP+8(最先进栈的最右参,寄存器的缓存结构体),对着*(*(ESP+8)+4)WriteProcessMemory了24位0(**(ESP)是寄存器结构体的第一个字节,从4至28是DR0,DR1,DR2,DR3,DR6,DR7)。在B中用 Wow64GetThreadContext GetThreadContext 都读不出DR0-DR7了。测了无数遍调试器A和程序B都没bug。

但是在11对战平台还是被检测了,log上 Wow64GetThreadContext 都没被执行。。。

所以想问除了 Wow64GetThreadContext GetThreadContext 之外有其他的获取硬件断点的方法吗?11又是用了哪种?

调试器A处理异常的代码如下

#define Wow64GetThreadContext_ADDRESS       0x279BC
#define Wow64GetThreadContext_ADDRESS_END   0x279CF
#define BREAK_OPEN 0x405

//hopen是B进程句柄,FindKernel32是自己写的暴力搜索Kernel32基址的方法,保证没bug,11也没隐藏Kernel32
FindKernel32(hopen,&kernel32Handle);

DWORD wow64GetThreadContextBreakBegin = kernel32Handle + Wow64GetThreadContext_ADDRESS;
DWORD wow64GetThreadContextBreakEnd = kernel32Handle + Wow64GetThreadContext_ADDRESS_END;



if(exceptionAddress == wow64GetThreadContextBreakBegin)
{
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEv.dwThreadId);
    SuspendThread(hThread);
    CONTEXT Regs = {0};
    Regs.ContextFlags = CONTEXT_DEBUG_REGISTERS|CONTEXT_INTEGER|CONTEXT_CONTROL;
    ::GetThreadContext(hThread, &Regs);
    Regs.Dr1=wow64GetThreadContextBreakEnd;
    Regs.Dr7=BREAK_OPEN;
    DWORD contextPointer = Regs.Esp + 0x8;
    bret=ReadProcessMemory(hopen,(LPVOID)(contextPointer),&wow64GetContextEAX,4,0);
    ::SetThreadContext(hThread, &Regs);
    ResumeThread(hThread);
    CloseHandle(hThread);
}
if(exceptionAddress == wow64GetThreadContextBreakEnd)
{
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEv.dwThreadId);
    SuspendThread(hThread);
    CONTEXT Regs = {0};
    Regs.ContextFlags = CONTEXT_ALL;//CONTEXT_DEBUG_REGISTERS|CONTEXT_INTEGER;
    ::GetThreadContext(hThread, &Regs);
    Regs.Dr1=wow64GetThreadContextBreakBegin;
    Regs.Dr7=BREAK_OPEN;
    if(wow64GetContextEAX)
    {
        DWORD buffer[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        SIZE_T writedCount;
        bret=WriteProcessMemory(hopen, (LPVOID)(wow64GetContextEAX + 4), &buffer, 24, &writedCount);
    }
    ::SetThreadContext(hThread, &Regs);
    ResumeThread(hThread);
    CloseHandle(hThread);
}

测试程序B的代码

int main(int argc, char* argv[])
{
    while(1)
    {
        Sleep(1000);
        HANDLE thread = GetCurrentThread();
        {
            WOW64_CONTEXT context;
            context.ContextFlags = CONTEXT_ALL;
            BOOL status = Wow64GetThreadContext(thread, &context);

            if (!status)
            {
                return -1;
            }

            printf("WGTC %08x %08x %08x %08x %08x %08x %08x %08x\n", &context, context.ContextFlags, context.Dr0, context.Dr1, context.Dr2, context.Dr3, context.Dr6, context.Dr7);
        }

        {
            static CONTEXT threadContext;
            memset(&threadContext, 0, sizeof(CONTEXT));
            threadContext.ContextFlags = CONTEXT_ALL;
            BOOL status = GetThreadContext(thread, &threadContext);

            printf("GTC %08x %08x %08x %08x %08x %08x %08x %08x\n",
                &threadContext,
                threadContext.ContextFlags,
                threadContext.Dr0,
                threadContext.Dr1,
                threadContext.Dr2,
                threadContext.Dr3,
                threadContext.Dr6,
                threadContext.Dr7);
        }
    }

    return 0;
}

win32 windows win32api

天然星☆↗ 11 years, 4 months ago

内核模式PSGetThreadContext和捕获异常也可以拿到寄存器

靈夢D靈喵 answered 11 years, 4 months ago

Your Answer