gpt4 book ai didi

c++ - 调试线程时无限循环

转载 作者:可可西里 更新时间:2023-11-01 10:33:19 25 4
gpt4 key购买 nike

我正在尝试将硬件断点附加到游戏进程,我成功了。然后我试图遍历异常并等待我放在那里的异常,它也工作正常。问题是,在它发生之后,它进入了我无法刹车的无限循环。你能建议吗?我这样做的原因是我想在此时停止线程,使用 Context 读取 EAX 值,然后继续该过程。

Header.h 包括在这里调用的函数,它们都工作正常,因此我现在不包括它。

#include "Header.h" #包括

int main() {

SetDebugPrivilege(TRUE);

DWORD dwProcessID = 0;
DWORD dwGame = 0;

printf("Looking for game process...\n");

while (dwProcessID == 0) {
dwProcessID = GetProcessID(L"PathOfExile.exe");
if (dwProcessID != 0)
dwGame = 1;

Sleep(100);
}

printf("dwProcessID = %p\n", dwProcessID);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
MODULEENTRY32 module;
module.dwSize = sizeof(MODULEENTRY32);
Module32First(snapshot, &module);

printf("PoE base address = %p\n", module.modBaseAddr);

hpChangeBreakpoint = (DWORD*)((char *)module.modBaseAddr + 0x1AAD20);

std::cout << hpChangeBreakpoint << std::endl;

//hpChangeBreakpoint = 0x013FB279;


HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);

BOOL bDebugging = DebugActiveProcess(dwProcessID);
printf("bDebugging = %d\n", bDebugging);


DWORD dwThreadID = GetProcessThreadID(dwProcessID);

HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);

CONTEXT parentCtx;

parentCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS;

if (GetThreadContext(hThread, &parentCtx))
{
parentCtx.Dr0 = (DWORD)hpChangeBreakpoint;
parentCtx.Dr7 = 0x00000001;

std::cout << "GetThreadContext successful" << std::endl;

SetThreadContext(hThread, &parentCtx);
}


DEBUG_EVENT DebugEvent;
DWORD dbgFlag = DBG_CONTINUE;
DWORD *currentHpPointerAddress = nullptr;
DWORD *maxHpPointerAddress = nullptr;
BOOLEAN bQuit = FALSE;

while (!bQuit && WaitForDebugEvent(&DebugEvent, INFINITE))
{
dbgFlag = DBG_CONTINUE;

switch (DebugEvent.dwDebugEventCode)
{

case EXCEPTION_DEBUG_EVENT:

switch (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{

case EXCEPTION_SINGLE_STEP:
if (DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress == (void*)hpChangeBreakpoint)
{
#define RESUME_FLAG 0x10000

CONTEXT childContext;
childContext.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(hThread, &childContext))
{
childContext.EFlags |= RESUME_FLAG;
SetThreadContext(hThread, &childContext);
std::cout << "current HP: " << childContext.Ecx << std::endl;

currentHpPointerAddress = (DWORD*)((char *)childContext.Edi + 0x8E0);
maxHpPointerAddress = (DWORD*)((char *)childContext.Edi + 0x8E4);

}

if (GetThreadContext(hThread, &parentCtx))
{
parentCtx.Dr0 = 0;
parentCtx.Dr7 = 0x400;
SetThreadContext(hThread, &parentCtx);

bQuit = TRUE;

}

}
else
dbgFlag = DBG_EXCEPTION_NOT_HANDLED;

break;

default:
dbgFlag = DBG_EXCEPTION_NOT_HANDLED;
}


break;

case LOAD_DLL_DEBUG_EVENT:
{
CloseHandle(DebugEvent.u.LoadDll.hFile);
break;
}
case CREATE_PROCESS_DEBUG_EVENT:
{
CloseHandle(DebugEvent.u.CreateProcessInfo.hFile);
break;
}
case EXIT_PROCESS_DEBUG_EVENT:
break;
default:
__nop();
}

if (!ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dbgFlag))
{
break;
}

if (bQuit)
DebugActiveProcessStop(dwProcessID);

}


while (1)
{
WORD currentHP = 0;
WORD maxHP = 0;
if (
ReadProcessMemory(hProcess, currentHpPointerAddress, &currentHP, sizeof(currentHP), NULL) == 0
|| ReadProcessMemory(hProcess, maxHpPointerAddress, &maxHP, sizeof(maxHP), NULL) == 0
)
{
printf("Failed to read memory: %u\n", GetLastError());
}
else {
std::cout << "HP: " << currentHP << " / " << maxHP << std::endl;
}

Sleep(1000);
}

system("pause>nul");
return 0;

当我运行它时,游戏运行正常,直到断点发生,当它发生时,我得到无限的“断点”cout 垃圾邮件,当我调试它时,这一行: 如果 (DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress == (void*)hpChangeBreakpoint)

始终为真,但 dwFirstChance 标志为 1,因此它始终为新异常?在这个无限循环中唯一改变的是 hThread,它总是不同的。我觉得我因为缺乏知识而错过了一些东西,因此会感谢任何帮助或正确方向的提示。谢谢!

最佳答案

你听/知道 Resume Flag (RF) 吗?你需要将它设置为 step over DrX brealpoint

所以代码必须是下一个

#define RESUME_FLAG 0x10000

CONTEXT Context = {};
Context.ContextFlags = CONTEXT_CONTROL;// not need CONTEXT_FULL here;
if (GetThreadContext(hThread, &Context))
{
Context.EFlags |= RESUME_FLAG; // !!! this line is key point
SetThreadContext(hThread, &Context);
}

这将从 win2003 或 windows vista 开始工作。不幸的是,XP 不允许您在 CONTEXT 中设置此标志。所以在这里你需要删除 Dr0 断点以跨过它(或修补 XP 内核 - 在 ntoskrnl 代码中搜索 0x003E0DD7 DWORD 并替换它到 0x003F0DD7 - 这是 Eflags 掩码 - 在 RESUME_FLAG 中不同)

还提供了一些优化建议 - 您不需要每次在 EXCEPTION_DEBUG_EVENT 时调用 OpenThread

一开始你已经有了这个线程句柄

HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);

在你调用 SetThreadContext

之后就不要关闭它

并且异常只能发生在该线程的上下文中,所有其他线程不受此影响。

在第二个你永远不会关闭线程句柄,在 EXCEPTION_DEBUG_EVENT 中打开 - 所以你已经有资源泄漏。

调试器在 CREATE_THREAD_DEBUG_EVENTCREATE_PROCESS_DEBUG_EVENT 上获得线程句柄并且必须关闭它(或者只是或通常维护它并在 EXIT_THREAD_DEBUG_EVENT 上关闭EXIT_PROCESS_DEBUG_EVENT )

您没有处理 LOAD_DLL_DEBUG_EVENT,因此没有关闭文件句柄。

您的代码有巨大的句柄泄漏!

SuspendThread/ResumeThread - 为了什么?!绝对没有意义 - 线程(以及进程中的所有线程)已经在此时暂停


struct CThread : LIST_ENTRY
{
HANDLE _hThread;
ULONG _dwThreadId;

CThread(HANDLE hThread, ULONG dwThreadId)
{
_hThread = hThread;
_dwThreadId = dwThreadId;
}

~CThread()
{
//CloseHandle(_hThread);// will be closed in ContinueDebugEvent
}

static CThread* get(ULONG dwThreadId, PLIST_ENTRY ThreadListHead, CThread* pHintThread)
{
if (pHintThread && pHintThread->_dwThreadId == dwThreadId)
{
return pHintThread;
}

PLIST_ENTRY entry = ThreadListHead;

while ((entry = entry->Flink) != ThreadListHead)
{
pHintThread = static_cast<CThread*>(entry);

if (pHintThread->_dwThreadId == dwThreadId)
{
return pHintThread;
}
}

return 0;//??
}

static void DeleteAll(PLIST_ENTRY ThreadListHead)
{
PLIST_ENTRY entry = ThreadListHead->Flink;

while (entry != ThreadListHead)
{
CThread* pThread = static_cast<CThread*>(entry);

entry = entry->Flink;

delete pThread;
}
}
};


void RunDebuggerLoop()
{
BOOL bQuit = FALSE;

LIST_ENTRY ThreadListHead = { &ThreadListHead, &ThreadListHead };

CThread* pThread = 0;

DEBUG_EVENT de;

BOOLEAN bFirst = TRUE;

while (!bQuit && WaitForDebugEvent(&de, INFINITE))
{
NTSTATUS status = DBG_CONTINUE;

switch(de.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
if (
!de.u.Exception.dwFirstChance
||
!(pThread = CThread::get(de.dwThreadId, &ThreadListHead, pThread))
)
{
bQuit = TRUE;
continue;
}

status = DBG_EXCEPTION_NOT_HANDLED;

switch (de.u.Exception.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
case STATUS_WX86_BREAKPOINT:
if (bFirst)
{
bFirst = FALSE;
status = DBG_CONTINUE;
}
break;

case STATUS_SINGLE_STEP:
case STATUS_WX86_SINGLE_STEP:
{
::CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_CONTROL;
if (GetThreadContext(pThread->_hThread, &ctx))
{
ctx.EFlags |= RESUME_FLAG;
SetThreadContext(pThread->_hThread, &ctx);
}
}
break;

case STATUS_ACCESS_VIOLATION:
if (de.u.Exception.ExceptionRecord.NumberParameters > 1)
{
ULONG_PTR ptr = de.u.Exception.ExceptionRecord.ExceptionInformation[1];
}

break;
}

break;

case CREATE_PROCESS_DEBUG_EVENT:
CloseHandle(de.u.CreateProcessInfo.hFile);
//CloseHandle(de.u.CreateProcessInfo.hProcess);// will be auto closed in ContinueDebugEvent
de.u.CreateThread.hThread = de.u.CreateProcessInfo.hThread;

case CREATE_THREAD_DEBUG_EVENT:
if (pThread = new CThread(de.u.CreateThread.hThread, de.dwThreadId))
{
InsertHeadList(&ThreadListHead, pThread);
}
break;

case EXIT_THREAD_DEBUG_EVENT:
if (pThread = CThread::get(de.dwThreadId, &ThreadListHead, pThread))
{
RemoveEntryList(pThread);
delete pThread;
pThread = 0;
}
break;

case LOAD_DLL_DEBUG_EVENT:
CloseHandle(de.u.LoadDll.hFile);
break;

case EXIT_PROCESS_DEBUG_EVENT:
bQuit = TRUE;
break;

case OUTPUT_DEBUG_STRING_EVENT:
case UNLOAD_DLL_DEBUG_EVENT:
__nop();
break;
default:
__nop();
}

if (!ContinueDebugEvent(de.dwProcessId, de.dwThreadId, status))
{
break;
}
}

CThread::DeleteAll(&ThreadListHead);
}
void Ep()
{
// tag by * in begin of CommandLine
PWSTR CommandLine = GetCommandLine();

if (!CommandLine || *CommandLine != '*')
{
// debugger case

WCHAR FileName[MAX_PATH];
if (ULONG n = GetModuleFileName(0, FileName, RTL_NUMBER_OF(FileName)))
{
if (n < MAX_PATH)
{
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
PWSTR newCommandLine = (PWSTR)alloca((wcslen(CommandLine) + 2)*sizeof(WCHAR));
*newCommandLine = '*';
wcscpy(newCommandLine + 1, CommandLine);

if (CreateProcessW(FileName, newCommandLine, 0, 0, 0, DEBUG_PROCESS, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

RunDebuggerLoop();
}
}
}
ExitProcess(0);
}
else
{
// main case

wcscpy(CommandLine, CommandLine + 1);

OutputDebugStringA("AAAAAA\n");

if (MessageBoxW(0, L"xxx", CommandLine, MB_YESNO) == IDYES)
{
OutputDebugStringW(L"WWWWWWWW\n");
}
ExitProcess(0);
}
}

关于c++ - 调试线程时无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41396240/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com