1 int main() 2 { 3 BOOL bFlag = FALSE; 4 5 char *szDllName = "MSGDLL.dll"; 6 //bFlag = EnablePrivilege(SE_DEBUG_NAME); //返回值為1時代表成功 7 8 9 //得到目標進程句柄 10 HANDLE hDestProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 7084); 11 12 LPTHREAD_START_ROUTINE dwAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA"); 13 14 //在目標進程的地址空間內分配一個內存塊 15 LPVOID pRemoteSpace = VirtualAllocEx(hDestProcess, NULL, strlen(szDllName) + 1, MEM_COMMIT, 16 PAGE_READWRITE); 17 18 //向上一步的內存塊中寫入數據,就是要加載的DLL名字 19 bFlag = WriteProcessMemory(hDestProcess, pRemoteSpace, szDllName, strlen(szDllName) + 1, 0); 20 21 //在目標進程內創建線程,線程的入口函數就是LoadLibraryA, 參數就是Dll名字 22 HANDLE hThread = CreateRemoteThread(hDestProcess, NULL, 0, dwAddr, pRemoteSpace, 23 NULL, 0 24 ); //前面都是成功的,就到了這一步,返回的錯誤是5,Access denied,權限不夠 25 //本來以為我的VS是以管理員權限啟動的,那么我這個進程應該權限就都夠了, 26 //看來不行,必須程序提權 27 //我提權了之后,發現還是不行,之后上網查了 28 //發現是32位注入到64位中會有問題,所以我換了個x64,然后顯然線程運行成功了, 29 //但是現在遠程進程卻崩潰了,估計是DLL是32的,我換個DLL編譯方式再試試 30 //我編譯了64位的DLL,然后還是崩潰的,之后我發現了應該是我函數地址傳的有問題 31 //因為32位的LoadLibraryA地址是DWORD,但64位卻是ULONGLONG,所以僅僅改變編譯方式還不夠 32 //必須用一個足夠容納8個字節地址的類型來保存,這樣就夠了 33 34 //另外一個需要注意的問題就是,為什么我在我這個進程中得到的LoadLibrary在遠程進程中也可以用 35 //答案就是,系統DLL在各個進程中的映射地址都是一樣的,不過具體情況具體分析,至少這個函數看來是一樣的。 36 37 //在我完成了之后,我把EnablePrivileges這行注釋掉了,但仍然注入成功,看來我用管理員權限運行VS2015之后就夠了 38 39 //然后我又發現了一個問題,就是對同一個進程,加載dll只能一次,第二次就不會彈了 40 //原因,我目測是,DLL已經被加載了,所以第二次就不加載了,也就不執行DllMain那個函數了 41 //除非我創建一個線程再UnLoad那個LIB,之后再LOAD,這樣應該就可以了 42 //也可以換個Dll名字,再LOAD, 反正方法很多。 43 44 DWORD dwErr = GetLastError(); 45 46 return 0; 47 }
//DLL的代碼,用DLL方式生成一下,拉到前面EXE目錄,或者系統目錄都行,跟前面代碼中DLL名字有沒有加絕對路徑有關 //這代碼是書上的代碼,直接復制了 /* ************************************ *《精通Windows API》 * 示例代碼 * msg.c * 6.5 動態鏈接庫 **************************************/ /* 頭文件 */ #include <Windows.h> #include <Psapi.h> /* 鏈接 */ #pragma comment (lib, "Psapi.lib") /* 函數聲明 */ // 使用__declspec(dllexport)聲明導出函數 __declspec(dllexport) DWORD ExportExample(LPSTR szMsg, DWORD dwCode); /************************************* * DllMain **************************************/ BOOL WINAPI DllMain( HINSTANCE hinstDLL, // DLL模塊的句柄 DWORD fdwReason, // 調用的情況 LPVOID lpReserved) // reserved { // 在不同的情況下都會調用DllMain函數,分別處理 switch (fdwReason) { // 加載Dll case DLL_PROCESS_ATTACH: { CHAR lpMainMoudleName[MAX_PATH]; CHAR lpMessage[MAX_PATH + 64]; // 獲取PID 和主模塊名,將彈出消息框 DWORD dwPID = GetCurrentProcessId(); GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH); wsprintf(lpMessage, "Process name: %s, PID: %u ", lpMainMoudleName, dwPID); MessageBox(NULL, lpMessage, "msg.dll", MB_OK); break; } // 新建線程 case DLL_THREAD_ATTACH: break; // 線程退出 case DLL_THREAD_DETACH: break; // 釋放Dll case DLL_PROCESS_DETACH: break; } return TRUE; } /************************************* * DWORD ExportExample(LPSTR szMsg, DWORD dwCode) * 功能 導出函數,顯示消息 * * 參數 LPSTR szMsg 字符串; DWORD dwCode 整形 **************************************/ DWORD ExportExample(LPSTR szMsg, DWORD dwCode) { LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), 0, lstrlen(szMsg) + 100); wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode); MessageBox(NULL, (LPSTR)lpShowOut, "由導出函數彈出的消息!", MB_OK); HeapFree(GetProcessHeap(), 0, lpShowOut); return 0; }
需要注意的點都在那一大串注釋中
64位進程,就得用64位的EXE來CreateRemoteThread, 另外DLL也應該是64位
32位進程,就得用32位的EXE來CreateRemoteThread, 另外DLL也應該是32位
把CreateRemoteThread的入口點函數設為LoadLibraryA(W),線程的那個參數設為DLL路徑指針(在目標進程中,所以得把DLL路徑拷到目標進程 中, 用VirtualAllocEx在目標進程中分配塊空間,然后WriteProcessMemory).
這樣可行的原因:
線程的函數原型DWORD ThreadProc(LPVOID lpParam)
LoadLibrary的函數原型HMODULE LoadLibrary(LPCTSTR lpFileName);
其實是一樣的,指針都是同樣大小,都只有一個參數,返回值無所謂..
另外在目標進程和本進程中LoadLibraryA(W)的虛擬地址是一樣的..