我想在我的变量上设置一个断点,当我进行读取访问时,我有以下代码:
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_PROCESS
或 DebugActiveProcess
调用 CreateProcess
时,系统内部调用 DbgUiConnectToDbg
- 此 api 检查 - 线程是否已具有相关调试对象(在TEB中),如果还没有 - 使用ZwCreateDebugObject
创建新对象并将其存储在TEB中(可以通过访问>DbgUiGetThreadDebugObject
并通过 DbgUiSetThreadDebugObject
进行更改)。只有在此之后您才能调用WaitForDebugEvent
。因为您没有通过 ZwCreateDebugObject
直接创建调试对象,并且没有使用标志 DEBUG_PROCESS
或 DebugActiveProcess
调用 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/