VC++實現DLL注入
阿新 • • 發佈:2019-02-19
所謂DLL注入就是將一個DLL放進某個程序的地址空間裡,讓它成為那個程序的一部分。要實現DLL注入,首先需要開啟目標程序。 hRemoteProcess = OpenProcess( PROCESS_CREATE_THREAD | //允許遠端建立執行緒 PROCESS_VM_OPERATION | //允許遠端VM操作 PROCESS_VM_WRITE, //允許遠端VM寫 FALSE, dwRemoteProcessId ) 由於我們後面需要寫入遠端程序的記憶體地址空間並建立遠端執行緒,所以需要申請足夠的許可權(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。 如果程序打不開,以後的操作就別想了。程序開啟後,就可以建立遠執行緒了,不過別急,先想想這個遠執行緒的執行緒函式是什麼?我們的目的是注入一個DLL。而且我們知道用LoadLibrary可以載入一個DLL到本程序的地址空間。於是,自然會想到如果可以在目標程序中呼叫LoadLibrary,不就可以把DLL載入到目標程序的地址空間了嗎?對!就是這樣。遠執行緒就在這兒用了一次,建立的遠執行緒的執行緒函式就是LoadLibrary,而引數就是要注入的DLL的檔名。(這裡需要自己想一想,注意到了嗎,執行緒函式ThreadProc和LoadLibrary函式非常相似,返回值,引數個數都一樣) 還有一個問題,LoadLibrary這個函式的地址在哪兒?也許你會說,這個簡單,GetProcAddress就可以得出。於是程式碼就出來了。 char *pszLibFileRemote="my.dll"; PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA"); CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL); 但是不對!不要忘了,這是遠執行緒,不是在你的程序裡,而pszLibFileRemote指向的是你的程序裡的資料,到了目標程序,這個指標都不知道指向哪兒去了,同樣pfnStartAddr這個地址上的程式碼到了目標程序裡也不知道是什麼了,不知道是不是你想要的LoadLibraryA了。但是,問題總是可以解決的,Windows有些很強大的API函式,他們可以在目標程序裡分配記憶體,可以將你的程序中的資料拷貝到目標程序中。因此pszLibFileRemote的問題可以解決了。 char *pszLibFileName="my.dll";//注意,這個一定要是全路徑檔名,除非它在系統目錄裡;原因大家自己想想。 //計算DLL路徑名需要的記憶體空間 int cb = (1 + lstrlenA(pszLibFileName)) * sizeof(char); //使用VirtualAllocEx函式在遠端程序的記憶體地址空間分配DLL檔名緩衝區 pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE); //使用WriteProcessMemory函式將DLL的路徑名複製到遠端程序的記憶體空間 iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL);
OK,現在目標程序也認識pszLibFileRemote了,但是pfnStartAddr好像不好辦,我怎麼可能知道LoadLibraryA在目標程序中的地址呢?其實Windows為我們解決了這個問題,LoadLibraryA這個函式是在Kernel32.dll這個核心DLL裡的,而這個DLL很特殊,不管對於哪個程序,Windows總是把它載入到相同的地址上去。因此你的程序中LoadLibraryA的地址和目標程序中LoadLibraryA的地址是相同的(其實,這個DLL裡的所有函式都是如此)。至此,DLL注入結束了。
/* 遠端注入explorer.exe,不停Beep,注入完就退出。 */ #include <windows.h> #include <stdio.h> #include <tlhelp32.h> #include <Shlwapi.h> #include <tchar.h> #pragma comment(lib,"Shlwapi.lib") #pragma comment(linker, "/BASE:0x14000000") //#define NoWindow #ifdef NoWindow #pragma comment(linker,"/subsystem:windows /FILEALIGN:0x200 /ENTRY:main") #pragma comment(linker,"/INCREMENTAL:NO /IGNORE:4078") #pragma comment(linker,"/MERGE:.idata=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.text=Anskya /SECTION:Anskya,EWR") #endif typedef int (__stdcall *fnMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT); typedef int (__stdcall *fnBeep)(int,int); #define ProcessName "services.exe"//"rundll32.exe"//"svchost.exe"//"explorer.exe"//"avp.exe"//"lsass.exe"// //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //根據程序名,獲得程序ID DWORD GetProcessID(char *FileName) { HANDLE hProcess; PROCESSENTRY32 pe; BOOL bRet; //進行程序快照 hProcess=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); //開始程序查詢 bRet=::Process32First(hProcess,&pe); //迴圈比較,得出ProcessID while(bRet) { if(strcmp(FileName,pe.szExeFile)==0) return pe.th32ProcessID; else bRet=::Process32Next(hProcess,&pe); } //返回得到的ProcessID // printf("Process not found!\n"); return 9999; } //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //遠端注入函式 void __stdcall RmoteThread() { HMODULE hMod,hMod2; fnMessageBoxA myMessageBoxA; fnBeep myBeep; char* path[MAX_PATH]; hMod = GetModuleHandle("user32.dll"); hMod2 = GetModuleHandle("kernel32.dll"); myMessageBoxA = (fnMessageBoxA)GetProcAddress(hMod, (LPCSTR)"MessageBoxA"); myBeep = (fnBeep)GetProcAddress(hMod2, (LPCSTR)"Beep"); /*for(int i=0;i<30;i++) { myBeep(800,400); } */ // while(1) for(int i=0;i<6;i++) { Beep(600,100); Sleep(200); } GetModuleFileName(NULL,(char*)path,MAX_PATH); // myMessageBoxA(NULL, (char*)path, NULL, 64); } //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ // 提升應用級除錯許可權 BOOL EnablePrivilege(HANDLE hToken,LPCTSTR szPrivName,BOOL fEnable) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL,szPrivName,&tp.Privileges[0].Luid); tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED:0; AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL); return((GetLastError() == ERROR_SUCCESS)); } //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ///說明: 插入程式碼,遠端執行緒為RmoteThread() ///引數: Pid = 程序PID ///返回: 成功True,否則False bool InjectExe(DWORD Pid) { bool status = false; LPVOID pBaseAddr = NULL; HMODULE hMod = GetModuleHandle(NULL); LONG hNHOffset = PIMAGE_DOS_HEADER(hMod)->e_lfanew; HANDLE hThread, hProcess, hToken; DWORD cbImage; //cbImage=記憶體中整個PE映像體的尺寸 cbImage= PIMAGE_NT_HEADERS((DWORD)hMod + (DWORD)hNHOffset)->OptionalHeader.SizeOfImage; //重要,否則不能注入lsass OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken); EnablePrivilege(hToken,SE_DEBUG_NAME,TRUE); hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, Pid); if (hProcess == NULL) { #ifdef debug MessageBoxA(NULL, "錯誤OpenProcess", NULL, 64); #endif goto Err; } //釋放遠端記憶體 VirtualFreeEx(hProcess, LPVOID(hMod), 0, MEM_RELEASE); //分配遠端記憶體 pBaseAddr = VirtualAllocEx(hProcess, LPVOID(hMod), cbImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pBaseAddr == NULL) { #ifdef debug MessageBoxA(NULL, "VirtualAllocEx failed", NULL, 64); #endif goto Err; } //寫進去,將本程序的整個PE體 全寫進目標程序,夠狠~ if (!WriteProcessMemory(hProcess, pBaseAddr, LPVOID(hMod), cbImage, NULL)) { #ifdef debug MessageBoxA(NULL, "WriteProcessMemory failed", NULL, 64); #endif goto Err; } hThread = CreateRemoteThread(hProcess, NULL, NULL, \ (LPTHREAD_START_ROUTINE)&RmoteThread, NULL, NULL, NULL); if (hThread == NULL) { #ifdef debug MessageBoxA(NULL, "CreateRemoteThread failed", NULL, 64); #endif goto Err; } // WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); status = TRUE; return status; //自己返回就行,不要VirtualFreeEx;,否則宿主就掛了! Err: if (pBaseAddr != NULL) VirtualFreeEx(hProcess, pBaseAddr, 0, MEM_RELEASE); if (hProcess != NULL) CloseHandle(hProcess); return status; } //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ int main() { char aa[]="aBcDdddFFFF asfd"; strupr((char*)aa); printf(aa); if (!InjectExe(GetProcessID(ProcessName))) Beep(1800,500); return 0; }