偵錯程式開啟子程序和附加子程序注入DLL
阿新 • • 發佈:2019-02-12
//網上找的一段程式碼改了改,調了調,只能當測試用哦...
#include <windows.h> #include <strsafe.h> #include <stddef.h> #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #define new new( _CLIENT_BLOCK, __FILE__, __LINE__) // 檢測記憶體洩漏 // _CrtDumpMemoryLeaks();//一般放main返回處 #pragma comment(lib,"strsafe") //B8 00000000 mov eax, &szDllPath //50 push eax //B9 00000000 mov ecx, &LoadLibrary //FFD1 call ecx //CC int3 //結構必須位元組對齊! #pragma pack(1) typedef struct _INJECT_CODE { BYTE byMOV_EAX; DWORD dwMOV_EAX_VALUE; BYTE byPUSH_EAX; BYTE byMOV_ECX; DWORD dwMOV_ECX_VALUE; WORD wCALL_ECX; BYTE byINT3; CHAR szDllPath[MAX_PATH]; }INJECT_CODE,*PINJECT_CODE; #pragma pack() //程式碼注入函式 BOOL InjectDebuggeeCode(HANDLE hProcess,LPVOID lpBaseAddress,PCHAR szDllPath) { BOOL fSuccess = FALSE; INJECT_CODE ic = {0}; ic.byMOV_EAX = 0xB8; ic.dwMOV_EAX_VALUE = (DWORD)lpBaseAddress + offsetof(INJECT_CODE,szDllPath); ic.byPUSH_EAX = 0x50; ic.byMOV_ECX = 0xB9; ic.dwMOV_ECX_VALUE = (DWORD)&LoadLibrary; ic.wCALL_ECX = 0xD1FF; ic.byINT3 = 0xCC; StringCbCopy(ic.szDllPath,MAX_PATH,szDllPath); fSuccess = WriteProcessMemory(hProcess,lpBaseAddress,&ic,sizeof(ic),NULL); if(!fSuccess)printf("Error:%d,Inject Debuggee Code Failed.",GetLastError()); fSuccess = FlushInstructionCache(hProcess,lpBaseAddress,sizeof(ic)); if(!fSuccess)printf("Error:%d,Flush Debuggee Code Failed.",GetLastError()); return fSuccess; } int main(int argc,char **argv) { BOOL fSuccess = FALSE; DWORD dwProcessId = 0; LPVOID lpBaseAddress = NULL; HANDLE hThread = NULL; HANDLE hProcess = NULL; DEBUG_EVENT dbgEvent = {0}; CONTEXT ctxOld = {CONTEXT_FULL}; CONTEXT ctxNew = {CONTEXT_FULL}; INJECT_CODE ic = {0}; STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {0}; //Debug_Attach 為0時測試除錯開啟子程序注入dll方式,為 1 時沒測試根據配置dwProcessId的值附加註入dll到被調程序 #define Debug_Attach 0 #if Debug_Attach dwProcessId = 12656; //被附加時的程序ID,每次進行測試時自己修改 #else //對子程序時行注入,輸入子程序的全路徑 CHAR * pProcess = "D:\\Desktop\\DbgView\\Dbgview.exe"; #endif //被注入的dll,,正常的dll都行 CHAR * pDll= "D:\\Desktop\\EnumDirFile.dll"; #if Debug_Attach //1.通過DebugActiveProcess將目標程序附加到偵錯程式上 fSuccess = DebugActiveProcess(dwProcessId); if(!fSuccess){printf("Debug Process [%d] Failed.",dwProcessId);return 0;} #else fSuccess = CreateProcessA(NULL, pProcess, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); if(!fSuccess){printf("CreateProcessA [%s] Failed.",pProcess);return 0;} #endif //2.本程式退出時,防止被除錯程序也一併退出 fSuccess = DebugSetProcessKillOnExit(FALSE); if(!fSuccess){printf("DebugSetProcessKillOnExit ProcessID [%d] Failed.",dwProcessId);return 0;} //3.建立除錯迴圈體,一旦接收到通知,除錯資訊便會被填充到DEBUG_EVENT結構中 while(WaitForDebugEvent(&dbgEvent,INFINITE)) { switch(dbgEvent.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT : hProcess = dbgEvent.u.CreateProcessInfo.hProcess; hThread = dbgEvent.u.CreateProcessInfo.hThread; //分配記憶體,填充注入指令 lpBaseAddress = VirtualAllocEx(hProcess, NULL, sizeof(INJECT_CODE), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(NULL == lpBaseAddress) { printf("Error:%d,Can not alloc enough memory",GetLastError()); return 0; } //將載入DLL指令寫入到目標程序中 fSuccess = InjectDebuggeeCode(hProcess,lpBaseAddress, pDll); if(!fSuccess) return 0; //獲取當前執行緒上下文 fSuccess = GetThreadContext(hThread,&ctxOld); if(!fSuccess){printf("GetThreadContext return false ProcessID [%d] Failed.",dwProcessId);return 0;} ctxNew = ctxOld; ctxNew.Eip = (DWORD)lpBaseAddress; printf("Old Eip = 0x%08X\n",ctxOld.Eip); printf("New Eip = 0x%08X\n",ctxNew.Eip); //4.設定新的執行緒上下文 fSuccess = SetThreadContext(hThread,&ctxNew); if(!fSuccess){printf("GetThreadContext return false ProcessID [%d] Failed.",dwProcessId);return 0;} break; case EXCEPTION_DEBUG_EVENT : if(dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { fSuccess = GetThreadContext(hThread,&ctxNew); if(!fSuccess){printf("GetThreadContext return false ProcessID [%d] Failed.",dwProcessId);return 0;} //第一次捕獲斷點則跳過不執行!查閱MSDN中DebugActiveProcess的最後一段話 //After all of this is done, the system resumes all threads in the process. //When the first thread in the process resumes, it executes a breakpoint instruction //that causes an EXCEPTION_DEBUG_EVENT debugging event to be sent to the debugger. //All future debugging events are sent to the debugger by using the normal mechanism and rules. if(ctxNew.Eip != (DWORD)lpBaseAddress + 0x0e) break; printf("Second Exception Eip = 0x%08X/n",ctxNew.Eip); //釋放記憶體 VirtualFreeEx(hProcess, lpBaseAddress, sizeof(INJECT_CODE), MEM_RELEASE); //5.設定原先的執行緒上下文 fSuccess = SetThreadContext(hThread,&ctxOld); if(!fSuccess){printf("SetThreadContext return false ProcessID [%d] Failed.",dwProcessId);return 0;} //執行原EIP指向的指令 fSuccess = ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_CONTINUE); if(!fSuccess){printf("ContinueDebugEvent return false ProcessID [%d] Failed.",dwProcessId);return 0;} return 0; //退出除錯程式! } break; } fSuccess = ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); if(!fSuccess){printf("ContinueDebugEvent return false ProcessID [%d] Failed.",dwProcessId);return 0;} } }