線程注入有很多種方法,有最簡單也最方便安全的SetWindowsHookEx的鉤子注入,也有代碼簡潔的遠程線程建立注入。
這種方法構思巧妙,但是個人覺得直接硬寫目標進程記憶體空間有一定風險,可謂差之毫釐,謬以千里。本菜鳥這個程式調試了很長時間才成功的,大牛請勿發笑。
CreatRemoteThread從字面意思上不難理解,建立一個遠程線程,所以我們可以用他在目標進程中建立一個線程,立即執行。並且將線程的入口地址設定為LoadLibrary函數的入口地址,LoadLibrary只有一個參數,就是動態連結程式庫的絕對位址,我們將這個參數傳入就可以調用任意一個我們想要注入的動態連結程式庫,在DllMain函數中放入我們的目標代碼就可以實現寄生執行。
這裡需要注意的是,我們都知道,進程是一個封閉的空間,裡面的所有資料都是私人的,那麼這個動態連結程式庫的絕對位址要被這個進程的線程所使用就應該成為這個進程空間中的資料,這也就是關鍵所在,我們需要先使用VirtualAllocEx進程中的記憶體空間,然後用WriteProcessMemory將這個參數內容寫進進程,這裡需要注意任何細節,一點小小錯誤都會使得目標進程崩潰。
下面我們看看代碼:
#include "windows.h"#include "stdlib.h"#include "stdio.h"#include "tlhelp32.h"DWORD ProcessNameToPID(char Name[20]);//將進程名轉化成PIDint main(){ DWORD pdwProcessId; WCHAR pszLibFileName[MAX_PATH]={0}; char lpDllFullPathName[MAX_PATH],ProcessName[20]; HANDLE hRemoteThread,hRemoteProcess; PWSTR pszLibFileRemote=NULL; printf("請輸入進程名稱:\n"); scanf("%s",ProcessName); printf("請輸入dll地址:\n"); scanf("%s",lpDllFullPathName); MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,lpDllFullPathName,strlen(lpDllFullPathName),pszLibFileName,MAX_PATH); if((pdwProcessId=ProcessNameToPID(ProcessName))==-1) return 0; hRemoteProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pdwProcessId);//開啟被注入進程 if (hRemoteProcess==NULL) { printf("OpenProcess Error\n"); return 0; } int cb=(1+lstrlenW(pszLibFileName))*sizeof(WCHAR); pszLibFileRemote=(PWSTR)VirtualAllocEx(hRemoteProcess,NULL,cb,MEM_COMMIT,PAGE_EXECUTE_READWRITE);//開闢記憶體 if (pszLibFileRemote==NULL) { printf("VirtualAllocEx Error\n"); return 0; } if(!WriteProcessMemory(hRemoteProcess,(PVOID)pszLibFileRemote,(PVOID)pszLibFileName,cb,NULL))//將dll模組名稱寫入被注入進程作為私人變數可供目標進程使用 { printf("WriteProcessMemory Error %d\n",GetLastError()); return 0; } PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("kernel32")),"LoadLibraryW");//獲得LoadLibraryW地址 if(pfnStartAddr==NULL) { printf("pfnStartAddr Error\n"); } //建立遠程線程,線程回呼函數就是LoadLibraryW,pszLibFileRemote中的dll路徑作為LoadLibraryW的唯一參數傳入 hRemoteThread=CreateRemoteThread(hRemoteProcess,NULL,0,pfnStartAddr,pszLibFileRemote,0,NULL); if (hRemoteThread==NULL) { printf("CreatRemoteThread Error\n"); return 0; } return 1;}DWORD ProcessNameToPID(char Name[20]) //進程遍曆就不用多說了把,方法多的是{PROCESSENTRY32 pe32;pe32.dwSize=sizeof(pe32);HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);if(hProcessSnap==INVALID_HANDLE_VALUE){printf("CreateToolhelp32Snapshot fuild!\n");return -1;}BOOL bMore=Process32First(hProcessSnap,&pe32);while(bMore){if (!strcmp(Name,pe32.szExeFile)){printf("find it %d\n",pe32.th32ProcessID);return pe32.th32ProcessID;}bMore=Process32Next(hProcessSnap,&pe32);}CloseHandle(hProcessSnap);return -1;}
下面是被注入進程的動態連結程式庫代碼,只輸出一個MessageBox,“這是個測試程式!”:
#include "windows.h"BOOL APIENTRY DllMain(HANDLE hMoudle,DWORD reason,LPVOID lpReserved){switch(reason){case DLL_PROCESS_ATTACH:MessageBox(NULL,"this is a test!","Success",MB_OK);break;default:return TRUE;}}
下面是運行效果,我寫了個介面: