I have adapted some code from other sources (primarily here) and had no avail in my circumstance. I am attaching to a 64-bit application that has upwards of 100 threads at any given time. There are two issues I have, somewhat unrelated:
- Whenever the code hits
DebugActiveProcess(pid), the attached application freezes. - The code I have only sets a breakpoint on the main thread, but I need it on more than one - ideally all.
I have confirmed that when the code hits SetThreadContext(hThread, &ctx) the dr0 and dr7 registers change as intended, so that much is fine. The only issues I can see right now are the process freezing and setting more than one breakpoint (I thought of iterating for every single thread which would be fine one-time, but when it gets into the while loop that would obviously be problematic and very resource-consuming). I should also note that I can attach the CheatEngine debugger to the application, and breakpoints work fine with no issues. Below is the code I'm using:
DWORD GetProcessThreadID(DWORD dwProcessID)
{
THREADENTRY32 te = { sizeof(THREADENTRY32) };
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (Thread32First(hSnapshot, &te))
while (Thread32Next(hSnapshot, &te))
if (te.th32OwnerProcessID == dwProcessID)
return te.th32ThreadID;
return NULL;
}
BOOL SetDebugPrivilege(BOOL State)
{
HANDLE hToken;
TOKEN_PRIVILEGES token_privileges;
DWORD dwSize;
ZeroMemory(&token_privileges, sizeof(token_privileges));
token_privileges.PrivilegeCount = 1;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid))
{
CloseHandle(hToken);
return FALSE;
}
if (State)
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
if (!AdjustTokenPrivileges(hToken, FALSE, &token_privileges, 0, NULL, &dwSize))
{
CloseHandle(hToken);
return FALSE;
}
return CloseHandle(hToken);
}
void CreateBreakpoint(DWORD pid, DWORD64 addr) {
DebugActiveProcess(pid);
DebugSetProcessKillOnExit(false);
DWORD_PTR dwThreadID = GetProcessThreadID(pid);
std::cout << std::hex << dwThreadID << std::endl;
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
SetDebugPrivilege(true);
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_INTEGER;
ctx.Dr0 = addr;
ctx.Dr7 = 0x00000001;
SetThreadContext(hThread, &ctx);
DEBUG_EVENT dbgEvent;
while (true) {
if (WaitForDebugEvent(&dbgEvent, INFINITE) == 0)
break;
if (dbgEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) // EXCEPTION_BREAKPOINT
{
if (dbgEvent.u.Exception.ExceptionRecord.ExceptionAddress == (LPVOID)addr)
{
GetThreadContext(hThread, &ctx);
std::cout << ctx.Rax << "\n";
ctx.Dr7 = 0;
SetThreadContext(hThread, &ctx);
}
}
ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE);
}
}
It may be worth noting that this is a C++ extension to a python script, but that shouldn't really be relevant, and even if I run the code standalone it runs into the same issues. Also, I'm not an expert in C++ so I apologize if there are any misunderstandings.