2016-12-30 12 views
2

ハードウェアブレークポイントをゲームプロセスにアタッチしようとしています。それから、私は例外をループして、そこに入れたものを待っています。これもうまくいきます。問題はそれが起こった後、私はブレーキをかけることができない無限ループに入ります。アドバイスできますか? 私はこれをやっている理由は、この時点でスレッドを停止し、コンテキストを使用して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, &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; 

}

私はそれを実行すると、ブレークポイントが発生するまで、ゲームが正常に動作し、ときそれは、私は無限の "ブレークポイント"傷のスパムを取得し、私はそれをデバッグするとき、この行: if(DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress ==(void *)hpChangeBreakpoint)

は常にtrueですが、dwFirstChanceフラグは1なので、常に新しい例外ですか?この無限ループで変化するのはhThreadだけですが、常に異なっています。私は知識の欠如のために何かを見逃しているように感じるので、正しい方向への助けやヒントを感謝するでしょう。ありがとうございました!

答えて

1

あなたは約Resume Flag (RF)を聞く/知っていますか?あなたはとてもコードが

#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から始めなければなりませんDrX brealpoint

上のステップのためにそれを設定する必要があります。残念ながらXPはCONTEXTにこのフラグを設定させません。ので、ここであなたはそれの上にステップのためDr0ブレークポイントを削除する必要があります(またはパッチXPカーネルを - NTOSKRNLコードで0x003E0DD7DWORDの検索と0x003F0DD7にそれを交換する - これはEflagsマスクです - RESUME_FLAGに異なる)

また、いくつかの最適化のアドバイスを聞かせて - EXCEPTION_DEBUG_EVENTのたびにOpenThreadに電話する必要はありません。

最初にあなたは既にこのスレッドが

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

を処理しているだけで、あなたがSetThreadContext

と例外を呼び出した後、唯一このスレッドのコンテキストでこの影響を受けない他のすべてのスレッドを発生することがあります、それを閉じていません。

あなたは決してスレッドハンドルを閉じないで、EXCEPTION_DEBUG_EVENTで開いています。既にリソースリークがあります。

デバッガは、LOAD_DLL_DEBUG_EVENT結果として接近していないファイルハンドルを処理しませを閉じる(または単にまたは通常それを維持し、EXIT_THREAD_DEBUG_EVENTEXIT_PROCESS_DEBUG_EVENTに近い)しなければならない

スレッドがCREATE_THREAD_DEBUG_EVENTCREATE_PROCESS_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); 
    } 
} 
0

ビッグ感謝を停止しました。質問のいくつかが変わってもごめんなさい、JS Devと私がここでやっていることは私の趣味です。何を私が知っていることは...それは私のJSその後、異なる方法で、より深い世界のように感じているということです。私は、コードを編集しました

)、また、どのようなあなたが言及したことは冗長で削除。スレッドの中断/再開はそこにありました。メモリの変更があったとしても、あなたが言ったことに基づいて、スレッドはこの時点で中断されていました。たとえメモリを変更しても、それらの必要はありません。

バック対象に行って、無限ループはまだここにいます。 IveはRFフラグを追加しましたが、追加するだけでなく、その理由も理解しています。その間に、なぜそれがまだ機能していないのかという別のヒントを私はあまりにも親切にしてくれますか? また、LOAD_DLL_DEBUG_EVENTの処理を追加しました。この時点で他に何もする必要がないので、すぐにハンドラを終了します(do i?)。私が完全には得られないのは、CREATE_PROCESSとCREATE_THREADデバッグイベントから受け取ったハンドラをexcatlyで閉じるべきかどうかです。私はデバッガがどのように働いているのか心配するつもりですが、これまでの4日目ですが、私はそれを見ています。

WaitForDebugEventはデバッグイベントを受け取りませんDBG_EXCEPTION_NOT_HANDLEDを指定してContinueDebugEventによって処理されます。そのため、戻され、ゲームで処理されます。 最後に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; 

}

+0

「バック被験者に行くには、無限ループは、まだここでアイブは、RFフラグを追加しました。」 - しかしあなたは "SetThreadContext"を呼び出さない!単純に 'CONTEXT Context'を初期化するのはどういう意味ですか?" SetThreadContext "を呼び出さずに、この問題を最初に解決してください。あなたはXPの下で実行されていない場合。 "SuspendThread' /' ResumeThread'を呼び出す必要はありません。 "メモリを変更しても、それらは必要ありません。 " - はい、必要はありません – RbMm

+0

ああ私の犬、とても明白:)私はそれに乗ってみましょう、あなたを知らせる!ありがとうalb RbMm! – MTM

+0

それは仲間を通り抜けているように見えます! :) ありがとうございました!あなたには別の問題があります。この例外を渡した後、EXCEPTION_ACCESS_VIOLATIONがあります。もしそれを処理しなければ、2回目にアプリケーションをクラッシュさせてください。私がやっていることに関連することができますか? – MTM