C++ 调试线程时执行无限循环
我试图将硬件断点附加到游戏进程,但我成功了。然后,我尝试循环遍历异常,等待我放入的异常,它也可以正常工作。问题是,在它发生后,它进入无限循环,我无法刹车。你能提出建议吗? 我这样做的原因是我想在这一点上停止线程,使用上下文读取EAX值,然后继续进程 h包含在这里调用的函数,它们都可以正常工作,因此我现在不包括它 #包括“Header.h” #包括 int main(){C++ 调试线程时执行无限循环,c++,windows,debugging,reverse-engineering,C++,Windows,Debugging,Reverse Engineering,我试图将硬件断点附加到游戏进程,但我成功了。然后,我尝试循环遍历异常,等待我放入的异常,它也可以正常工作。问题是,在它发生后,它进入无限循环,我无法刹车。你能提出建议吗? 我这样做的原因是我想在这一点上停止线程,使用上下文读取EAX值,然后继续进程 h包含在这里调用的函数,它们都可以正常工作,因此我现在不包括它 #包括“Header.h” #包括 int main(){ SetDebugPrivilege(TRUE); DWORD dwProcessID=0; DWORD dwGame=0; p
SetDebugPrivilege(TRUE);
DWORD dwProcessID=0;
DWORD dwGame=0;
printf(“寻找游戏过程…\n”);
while(dwProcessID==0){
dwProcessID=GetProcessID(L“PathOfExile.exe”);
如果(dwProcessID!=0)
dwGame=1;
睡眠(100);
}
printf(“dwProcessID=%p\n”,dwProcessID);
HANDLE snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwProcessID);
模块Entry32模块;
module.dwSize=sizeof(MODULEENTRY32);
模块32第一个(快照和模块);
printf(“PoE基址=%p\n”,module.modBaseAddr);
hpChangeBreakpoint=(DWORD*)((char*)module.modBaseAddr+0x1AAD20);
std::cout您是否在收听/了解恢复标志(RF)
?您需要将其设置为step overDrX
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不允许您在上下文中设置此标志。因此,在这里您需要删除Dr0
断点以跳过它(或修补程序XP内核-在ntoskrnl代码中搜索0x003E0DD7
DWORD
,并将其替换为0x003F0DD7
-这是Eflags
掩码-在恢复标志中不同)
另外,请给出一些优化建议-您不需要每次在异常调试事件
时调用OpenThread
首先,您已经有了这个线程句柄
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
调用SetThreadContext
异常只能在该线程的上下文中发生,所有其他线程不受此影响
在第二秒钟,您从未关闭在异常\u调试\u事件中打开的线程句柄,所以您已经有了资源泄漏
调试器在CREATE\u thread\u DEBUG\u EVENT
和CREATE\u PROCESS\u DEBUG\u EVENT
上获得了线程句柄,并且必须关闭它(或者只是或通常维护它并关闭EXIT\u thread\u DEBUG\u EVENT
和EXIT\u PROCESS\u DEBUG\u EVENT
)
您无法处理加载\u DLL\u调试\u事件,因此无法关闭文件句柄
您的代码有大量句柄泄漏
SuspendThread/ResumeThread-为了什么?!绝对没有意义-线程(以及进程中的所有线程)在这一点上已经挂起
struct CThread:LIST\u条目
{
句柄线程;
乌隆(ULONG)杜维德;;
CThread(HANDLE-hThread,ULONG-dwThreadId)
{
_hThread=hThread;
_dwThreadId=dwThreadId;
}
~CThread()
{
//CloseHandle(_hThread);//将在ContinuedBugEvent中关闭
}
静态CThread*get(ULONG dwThreadId,PLIST_条目threadlisthhead,CThread*phinthread)
{
if(pHintThread&&pHintThread->\u dwThreadId==dwThreadId)
{
返回非线程;
}
PLIST_ENTRY=螺纹列表头;
而((entry=entry->Flink)!=ThreadListHead)
{
pHintThread=静态转换(条目);
如果(pHintThread->_dwThreadId==dwThreadId)
{
返回非线程;
}
}
返回0;/??
}
静态void DeleteAll(PLIST\u入口螺纹列表头)
{
PLIST_ENTRY=ThreadListHead->Flink;
while(条目!=ThreadListHead)
{
CThread*pThread=static_cast(条目);
入口=入口->燧石;
删除pThread;
}
}
};
void RunDebuggerLoop()
{
BOOL bkuit=假;
列表\项目ThreadListHead={&ThreadListHead,&ThreadListHead};
CThread*pThread=0;
调试事件de;
布尔bFirst=TRUE;
while(!bguit&&WaitForDebugEvent(&de,无限))
{
NTSTATUS status=DBG\u CONTINUE;
开关(de.dwDebugEventCode)
{
案例异常\u调试\u事件:
如果(
!de.u.Exception.dwFirstChance
||
!(pThread=CThread::get(de.dwThreadId和线程列表头,pThread))
)
{
bkuit=TRUE;
继续;
}
状态=DBG\u异常未处理;
开关(de.u.Exception.ExceptionRecord.ExceptionCode)
{
案例状态\u断点:
案例状态\u WX86\u断点:
如果(bFirst)
{
bFirst=假;
状态=DBG_继续;
}
打破
案例状态\u单个步骤:
案例状态\u WX86\u单个步骤:
{
::CONTEXT ctx={};
ctx.ContextFlags=CONTEXT\u控件;
if(GetThreadContext(pThread->hThread,&ctx))
{
ctx.EFlags |=恢复标志;
SetThreadContext(pThread->hThread,&ctx);
}
}
打破
案例状态\访问\违规:
如果(de.u.Exception.ExceptionRecord.NumberParameters>1)
{
ULONG_PTR PTR=de.u.Exception.Exception记录。Exception信息[1];
}
打破
}
打破
案例创建\流程\调试\事件:
CloseHandle(de.u.CreateProcessInfo.hFile);
//CloseHandle(de.u.CreateProcessInfo.h
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
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);
}
}
#include "Header.h"
#include <iostream>
int main() {
hpChangeBreakpoint = 0x013FB279;
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 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 context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (GetThreadContext(hThread, &context))
{
context.Dr0 = hpChangeBreakpoint;
context.Dr7 = 0x00000001;
std::cout << "GetThreadContext successful" << std::endl;
SetThreadContext(hThread, &context);
}
DEBUG_EVENT DebugEvent;
BOOL bContinueDebugging = false;
for(;;)
{
WaitForDebugEvent(&DebugEvent, INFINITE);
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 Context;
Context.ContextFlags = CONTEXT_CONTROL;
Context.EFlags |= RESUME_FLAG;
std::cout << "Breakpoint" << std::endl;
bContinueDebugging = true;
}
if (bContinueDebugging)
{
// DBG_CONTINUE to tell the program we have handled the exception
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
bContinueDebugging = false;
}
else // if the exception was not handled by our exception-handler, we want the program to handle it, so..
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
break;
default:
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
}
break;
case LOAD_DLL_DEBUG_EVENT:
{
std::cout << "load dll debug event" << std::endl;
CloseHandle(DebugEvent.u.LoadDll.hFile);
break;
}
default:
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
}
}
system("pause>nul");
return 0;