我正在尝试将硬件断点附加到游戏过程中并且我已经成功了。然后我试图遍历异常并等待我放在那里的那个,这也工作正常。问题是它发生后会进入无限循环,我无法制动。你能建议吗? 我这样做的原因是我想在此时停止线程,使用Context读取EAX值然后继续该过程。
Header.h包含这里调用的函数,它们都可以正常工作,因此我现在不包括它。
#include“Header.h” #include
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, ¤tHP, 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的垃圾邮件,当我调试它时,这一行: if(DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress ==(void *)hpChangeBreakpoint)
始终为true,但dwFirstChance标志为1,所以它总是一个新的异常?在这个无限循环中唯一改变的是hThread,总是不同的。我觉得因为缺乏知识而缺少某些东西,因此会感谢任何帮助或暗示正确的方向。谢谢!
答案 0 :(得分:1)
Resume Flag (RF)
?您需要将其设置为步入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
)
还提供一些优化建议 - 每次OpenThread
时都不需要致电EXCEPTION_DEBUG_EVENT
。
首先你已经有了这个线程句柄
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
在致电SetThreadContext
之后,根本不关闭它
并且异常只能在此线程的上下文中发生,所有其他线程不受此影响。
第二个你永远不会关闭在EXCEPTION_DEBUG_EVENT
中打开的线程句柄 - 所以你已经有资源泄漏了。
调试器获得CREATE_THREAD_DEBUG_EVENT
上的线程句柄和CREATE_PROCESS_DEBUG_EVENT
以及必须关闭它(或者只是或通常维护它并关闭EXIT_THREAD_DEBUG_EVENT
和{{1} })
你没有处理EXIT_PROCESS_DEBUG_EVENT
因此没有关闭文件句柄。
您的代码有巨大的句柄泄漏!
SuspendThread / ResumeThread - 为了什么?!绝对无意义 - 线程(以及进程中的所有线程)已经暂停了
LOAD_DLL_DEBUG_EVENT
答案 1 :(得分:0)
非常感谢你花时间回答我。如果有些问题很奇怪,我很抱歉,但我是一个JS开发者,我在这里做的是我的爱好。我所知道的是,感觉就像一个与我的JS不同而且更深刻的世界......;)
我编辑了代码,也删除了你提到的冗余。线程的暂停/恢复是因为它们之间我有一些内存修饰,但根据你的说法,线程在这一点暂停,即使我要修改内存,也没有必要吗? / p>
回到主题,无限循环仍在这里。我添加了RF标志,但我刚刚开始阅读文章,除了添加它之外,我也理解为什么。与此同时,你能不能给我另一个暗示,为什么它可能仍然不起作用? 另外,我已经添加了LOAD_DLL_DEBUG_EVENT处理,我正在关闭处理程序,因为此时我不需要做任何其他事情(我呢?)。我不完全得到的是,当我应该关闭从CREATE_PROCESS和CREATE_THREAD调试事件收到的处理程序时?我试图将我的思想包含在调试器的工作方式中,这是我到目前为止的第四天,但正如我所看到的,这就是发生的事情:
WaitForDebugEvent接收一个调试事件,只要它不是我的,它由ContinueDebugEvent用DBG_EXCEPTION_NOT_HANDLED处理,所以它被传回并且游戏处理它。 最后WaitForDebugEvent接收我的调试事件,即EXCEPTION_SINGLE_STEP,我在那里做我的东西,然后继续使用DBG_CONTINUE - 标记我处理的异常,系统继续跟踪它。这是对的吗?
我的实际代码仍然循环并在无限循环中打印“断点”:
#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;
}