當讀者需要獲取到特定進程內的寄存器信息時,則需要在上述代碼中進行完善,首先需要編寫`CREATE_PROCESS_DEBUG_EVENT`事件,程式被首次載入進入記憶體時會被觸發此事件,在該事件內首先我們通過`lpStartAddress`屬性獲取到當前程式的入口地址,並通過`SuspendThrea... ...
當讀者需要獲取到特定進程內的寄存器信息時,則需要在上述代碼中進行完善,首先需要編寫CREATE_PROCESS_DEBUG_EVENT
事件,程式被首次載入進入記憶體時會被觸發此事件,在該事件內首先我們通過lpStartAddress
屬性獲取到當前程式的入口地址,並通過SuspendThread
暫停程式的運行,當被暫停後則我沒就可以通過ReadProcessMemory
讀取當前位置的一個位元組機器碼,目的是保存以便於後期的恢復,接著通過WriteProcessMemory
向對端(void*)dwAddr
地址寫出一個0xCC
斷點,該斷點則是int3
停機指令,最後ResumeThread
恢復這個線程的運行,此時程式中因存在斷點,則會觸發一個EXCEPTION_DEBUG_EVENT
異常事件。
case CREATE_PROCESS_DEBUG_EVENT:
{
// 獲取入口地址 0x0 可以增加偏移到入口後任意位置
DWORD dwAddr = 0x0 + (DWORD)de.u.CreateProcessInfo.lpStartAddress;
// 暫停線程
SuspendThread(de.u.CreateProcessInfo.hThread);
// 讀取入口地址處的位元組碼
ReadProcessMemory(de.u.CreateProcessInfo.hProcess, (const void*)dwAddr, &bCode, sizeof(BYTE), &dwNum);
// 在入口地址處寫入 0xCC 即寫入 INT 3 暫停進程執行
WriteProcessMemory(de.u.CreateProcessInfo.hProcess, (void*)dwAddr, &bCC, sizeof(BYTE), &dwNum);
// 恢複線程
ResumeThread(de.u.CreateProcessInfo.hThread);
break;
}
當異常斷點被觸發後,則下一步就會觸發兩次異常,第一次異常我們可以使用break
直接跳過,因為此斷點通常為系統斷點,而第二次斷點則是我們自己設置的int3斷點,此時需要將該請求發送至OnException
異常處理函數對其進行處理,在傳遞時需要給與&de
調試事件,以及&bCode
原始的機器碼;
case EXCEPTION_DEBUG_EVENT:
{
switch (dwCC_Count)
{
// 第0次是系統斷點,這裡我們直接跳過
case 0:
dwCC_Count++; break;
// 第1次斷點,我們讓他執行下麵的函數
case 1:
OnException(&de, &bCode); dwCC_Count++; break;
}
}
異常事件會被流轉到OnException(DEBUG_EVENT* pDebug, BYTE* bCode)
函數內,在本函數內我們首先通過使用OpenProcess/OpenThread
兩個函數得到當前進程的句柄信息,接著使用SuspendThread(hThread)
暫時暫停進程內線程的執行,通過調用ReadProcessMemory
得到線程上下文異常產生的首地址,當得到首地址後,則可以調用GetThreadContext(hThread, &context)
得到當前線程的上下文,一旦上下文被獲取到則讀者即可通過context.
的方式得到當前程式的所有寄存器信息,為了讓程式正常執行當讀取結束後,通過WriteProcessMemory
我們將原始機器碼寫回到記憶體中,並SetThreadContext
設置當前上下文,最後使用ResumeThread
運行該線程;
void OnException(DEBUG_EVENT* pDebug, BYTE* bCode)
{
CONTEXT context;
DWORD dwNum;
BYTE bTmp;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pDebug->dwProcessId);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pDebug->dwThreadId);
// 暫停指定的線程
SuspendThread(hThread);
// 讀取出異常首地址
ReadProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, &bTmp, sizeof(BYTE), &dwNum);
context.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &context);
printf("\n");
printf("EAX = 0x%08X | EBX = 0x%08X | ECX = 0x%08X | EDX = 0x%08X \n",
context.Eax, context.Ebx, context.Ecx, context.Edx);
printf("EBP = 0x%08X | ESP = 0x%08X | ESI = 0x%08X | EDI = 0x%08X \n\n",
context.Ebp, context.Esp, context.Esi, context.Edi);
printf("EIP = 0x%08X | EFLAGS = 0x%08X\n\n", context.Eip, context.EFlags);
// 將剛纔的CC斷點取消,也就是回寫原始指令集
WriteProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, bCode, sizeof(BYTE), &dwNum);
context.Eip--;
// 設置線程上下文
SetThreadContext(hThread, &context);
// printf("進程句柄: 0x%08X \n", pDebug->u.CreateProcessInfo.hProcess);
// printf("主線程句柄: 0x%08X \n", pDebug->u.CreateProcessInfo.hThread);
printf("虛擬入口點: 0x%08X \n", pDebug->u.CreateProcessInfo.lpBaseOfImage);
// 恢複線程執行
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProcess);
}
當這段程式被運行後,讀者可看到如下圖所示的輸出信息,該進程中當前寄存器的狀態基本上都可以被獲取到;
本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/94ad4ba.html
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
文章出處:https://www.cnblogs.com/LyShark/p/17741912.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!