c - 使用winapi为当前进程设置硬件断点

标签 c debugging winapi

我想在我的变量上设置一个断点,当我进行读取访问时,我有以下代码:

char * lpBuffer = NULL;

void proc(PVOID)
{
    for (int i = 0; i < 10; i++) {
        Sleep(100);

        MessageBoxA(0, 0, 0, 0);
        char * h = lpBuffer;

        h[0x4] = 0x88;
    }
}

int main()
{
    lpBuffer = malloc(20);
    SetDebugPrivilege(TRUE);

    HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)proc, 0, CREATE_SUSPENDED, 0);

    CONTEXT ctx = {};
    BOOL st = GetThreadContext(hThread, &ctx);

    ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    ctx.Dr0 = (DWORD)&lpBuffer;
    ctx.Dr7 = 0x30002;
    st = SetThreadContext(hThread, &ctx);

    ResumeThread(hThread);

    DEBUG_EVENT dbgEvent;

    int status = WaitForDebugEvent(&dbgEvent, INFINITE);

    //..
}

我总是从int status = WaitForDebugEvent(&dbgEvent, INFINITE);得到0,它不执行任何等待,只是立即返回0,我放置MessageBoxA来测试,基本上我没有收到任何通知并等待在 lpBuffer 上执行读取。我想我做错了什么,也许这与 dr7 标志有关? 0x30002是00110000000000000010,所以应该是硬件读/写bp。

最佳答案

关于调试。为了进行调试,需要创建特殊的 DebugObject 并将进程(您要调试的)与此调试对象相关联。此后,当与调试对象关联的进程中发生某些事件时,系统挂起进程中的所有线程,将调试事件插入调试对象并将其设置为信号状态。在调试器中,等待调试对象的线程(例如通过 WaitForDebugEvent)(但也可以直接传递调试对象的句柄来表示 MsgWaitForMultipleObjectsEx)被唤醒并处理此调试事件。但如果线程来自调试进程 - 它将被挂起,因为进程中的所有线程都不会处理此事件。在这种情况下进程挂起。 so - 进程无法自行调试,因为当发生调试事件(例如异常)时,系统挂起进程中的所有线程

about WaitForDebugEvent 不执行任何等待。 WaitForDebugEvent 内部调用 ZwWaitForDebugEvent 并从哪里获取 HANDLE hDebugObject ?来自线程TEB(这里存在用于保存它的特殊字段)。当您使用标志 DEBUG_PROCESSDebugActiveProcess 调用 CreateProcess 时,系统内部调用 DbgUiConnectToDbg - 此 api 检查 - 线程是否已具有相关调试对象(在TEB中),如果还没有 - 使用ZwCreateDebugObject创建新对象并将其存储在TEB中(可以通过访问>DbgUiGetThreadDebugObject 并通过 DbgUiSetThreadDebugObject 进行更改)。只有在此之后您才能调用WaitForDebugEvent。因为您没有通过 ZwCreateDebugObject 直接创建调试对象,并且没有使用标志 DEBUG_PROCESSDebugActiveProcess 调用 CreateProcess - 没有调试与您的线程关联的对象,并调用 WaitForDebugEvent 当然会失败

只有一个选项可以在自己的进程中捕获硬件断点 - 使用VEX。例如:

LONG NTAPI OnVex(PEXCEPTION_POINTERS ExceptionInfo)
{
    WCHAR buf[1024], *sz = buf, wz[64];
    PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;

    swprintf(wz, L"%x> %x at %p", GetCurrentThreadId(), ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress);

    *buf = 0;

    if (ULONG NumberParameters = ExceptionRecord->NumberParameters)
    {
        sz += swprintf(sz, L"[ ");

        PULONG_PTR ExceptionInformation = ExceptionRecord->ExceptionInformation;
        do 
        {
            sz += swprintf(sz, L"%p, ", *ExceptionInformation++);
        } while (--NumberParameters);

        sz += swprintf(sz - 2, L" ]");
    }

    MessageBoxW(0, buf, wz, 0);

    return ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}

DWORD HardwareTest(PVOID pv)
{
    WCHAR sz[64];
    swprintf(sz, L"hThread = %p\n", *(void**)pv);
    return MessageBoxW(0, 0, sz, MB_ICONINFORMATION);
}

void ep()
{
    if (PVOID handler = AddVectoredExceptionHandler(TRUE, OnVex))
    {
        if (HANDLE hThread = CreateThread(0, 0, HardwareTest, &hThread, CREATE_SUSPENDED, 0))
        {
            CONTEXT ctx = {};
            ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
            ctx.Dr3 = (ULONG_PTR)&hThread;
            ctx.Dr7 = 0xF0000040;

            SetThreadContext(hThread, &ctx);

            ResumeThread(hThread);

            WaitForSingleObject(hThread, INFINITE);

            CloseHandle(hThread);
        }

        RemoveVectoredExceptionHandler(handler);
    }
}

关于c - 使用winapi为当前进程设置硬件断点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45829159/

相关文章:

c++ - 为什么不能释放堆栈上的变量?

c - 使用 GDB 打印/观察大型代码库文件中的变量?

c++ - 如何在 Windows 10 上从提升的管理员上下文启动非提升的管理员进程?

c++ - 获取当前目录下的所有文件

windows - 如何在 Delphi 中使用 Windows IME?

不能比较两个以上的字符串吗?

c - 我在 C 语言的签名数中遗漏了什么吗?

C: 未定义的楼层引用

javascript - 使用控制台调试 JavaScript

python - 如何有效地调试在计算密集型程序结束时调用的部分代码?