斷點攔截局部數據



  逆向開發經常有這個需求:攔截局部數據。一般的做法是hook,通過修改代碼的流程來獲得數據。還有一種辦法是下斷點調試。這里聊聊怎樣通過下斷點來攔截局部數據。

零、原理簡介

  下斷點攔截數據,原理就是對目標進程進行下斷點調試。

  設置斷點的原理就是在某個地址寫入0xCC。對某個地址設置斷點之后,當被調試的目標進程運行到這個地址,就會報錯拋出異常給我們的調試進程。我們的調試進程就可以拿到當前的環境數據。

  拿到數據之后,就要讓目標進程繼續正常執行了,這時候是先把0xCC恢復成原本的內容;然后EIP減一,讓當前的指令重新正常執行;

  但這個時候斷點已經恢復,想重復攔截數據的話就需要重新設置斷點:設置單步標志,當前的指令重新正常執行之后,觸發單步異常,這個時候再重新下斷點就可以了。

一、調試進程

// 被調試的進程ID
static DWORD g_processID = 0;

// 將進程改為被調試狀態
DebugActiveProcess(g_processID);

// 退出調試的時候,不關閉被調試進程
BOOL kRet = DebugSetProcessKillOnExit(false);

二、設置斷點

// 保存斷點地址和對應的內存內容,用於恢復斷點
static map<DWORD, BYTE> g_mBpAddress2Content;

// 添加斷點,原理就是寫入0xCC,程序運行到這里,會觸發異常
BOOL CBreakPointHelper::AddBreakPoint(DWORD address)
{
    BYTE content;
    SIZE_T bytesRead;
    BOOL rRet = ReadProcessMemory(g_hProcess, (LPCVOID)address, &content, 1, &bytesRead);

    BYTE intInst = 0xCC;
    SIZE_T byteWriten;
    BOOL wRet = WriteProcessMemory(g_hProcess, (LPVOID)address, &intInst, 1, &byteWriten);
    if (wRet) g_mBpAddress2Content[address] = content;

    return rRet && wRet;
}

// 刪除斷點,原理就是把原本的內存內容寫回去
BOOL CBreakPointHelper::DelBreakPoint(DWORD address)
{
    if (g_mBpAddress2Content.count(address) <= 0) return false; 
	
    SIZE_T byteWriten;
    BYTE content = g_mBpAddress2Content[g_resetUserBpAddress];
    WriteProcessMemory(g_hProcess, (LPVOID)(address), &(content), 1, &byteWriten);

    return true;
}

三、監聽消息

DEBUG_EVENT debugEvent;
while (WaitForDebugEvent(&debugEvent, INFINITE)) 
{
    switch (debugEvent.dwDebugEventCode) 
    {
	case EXCEPTION_DEBUG_EVENT:
            OnException(&debugEvent);
  	    break;
    }

    ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
}

四、處理異常

void CBreakPointHelper::OnException(const DEBUG_EVENT* pEvent) 
{
    const EXCEPTION_DEBUG_INFO* pInfo = &(pEvent->u.Exception);
    switch (pInfo->ExceptionRecord.ExceptionCode) 
    {
    case EXCEPTION_BREAKPOINT:   // 斷點
	OnBreakPoint(pEvent);
            break;
	case EXCEPTION_SINGLE_STEP:  // 單步
            OnSingleStep(pEvent);
        break;
    }
}

void CBreakPointHelper::OnBreakPoint(const DEBUG_EVENT* pEvent)
{
    // 獲取當前地址
    const EXCEPTION_DEBUG_INFO* pInfo = &(pEvent->u.Exception);
    DWORD address = (DWORD)pInfo->ExceptionRecord.ExceptionAddress;
    g_resetUserBpAddress = address;
    DelBreakPoint(address);//刪除斷點,當前指令恢復正常
  
    // 獲取環境
    CONTEXT context;
    context.ContextFlags = CONTEXT_FULL;
    GetThreadContext(hThread, &context);
  
    // 攔截數據
    BreakPointCB(address, &context);
  
    // 修改環境
    context.Eip -= 1;        // eip減一,重新執行當前指令
    context.EFlags |= 0x100; // 設置單步標記, 用於恢復斷點 
    SetThreadContext(hThread, &context);
}

void CBreakPointHelper::OnSingleStep(const DEBUG_EVENT* pEvent)
{
    // 恢復斷點 
    AddBreakPoint(g_resetUserBpAddress);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM