1. 程式人生 > >偵錯程式開啟子程序和附加子程序注入DLL

偵錯程式開啟子程序和附加子程序注入DLL

//網上找的一段程式碼改了改,調了調,只能當測試用哦...
#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;}	
	}

}