后衛大師教你進程注入 首先提一下,由於文章完全是我手寫,所以打不了太多,請包含,由於我已經提供了源代碼,所以我在這里詳細講一下理論,至於想看代碼的下載代碼就可以了。代碼中關於注入的部分做了詳細的注釋。MFC界面部分的注釋沒有寫,(畢竟太膚淺了。) 好,言歸正傳。 所謂DLL注入,既把一個DLL文件放到目標進程中。 下面介紹2種注入方式: 1.遠程線程注入。 2.利用hook注入。(可以過卡巴斯基) 由於本文篇幅限制,不寫如何編寫DLL。 一.首先講一下遠程線程注入的方法: 1.假設我們已經寫好了一個DLL文件。 2.設置本進程權限為debug權限,既調試權限,可以打開其他進程。代碼如下: BOOL SetToken(void) { HANDLE hToken; TOKEN_PRIVILEGES Privileges; LUID luid; OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,&hToken); Privileges.PrivilegeCount=1; LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid); Privileges.Privileges[0].Luid=luid; Privileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(hToken,FALSE,&Privileges,NULL,NULL,NULL)!=0) return FALSE; CloseHandle(hToken); return (GetLastError() == ERROR_SUCCESS); } 3.獲得目標進程的句柄。 OpenProcess(權限類型,是否可被繼承,進程ID)功能:返回目標進程句柄. 4.在遠程進程中分配內存,用來存儲,我們要注入的dll的路徑 VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE); //VirtualAllocEx()函數功能:為制定的進程分配虛擬地址 //參1:要分配的進程句柄 //參2:要分配的虛擬地址的位置,0表示,自動分配位置 //參3:分配的大小 //參4:MEM_COMMIT表示,分配物理內存或者頁面內存,並且初始化內存為0 //參5:存儲選項:PAGE_READWRITE表示可以在頁面內存中 “讀寫” //返回值:如果分配內存成功,則返回分配內存的地址,如果分配失敗則返回NULL,調用GetLastError()查看錯誤原因 5.在遠程進程中剛才分配的內存處,寫入目標DLL路徑: WriteProcessMemory(hProcess, pszLibFileRemote,PVOID) pszLibFile, cb, NULL) //WriteProcessMemory()函數功能:在制定進程中寫入內存 //參1:寫入進程的句柄 //參2:寫入內存的起始地址,必須是已經創建的地址,比如上面用VirtualAllocEx()在進程中創建的內存地址 //參3:寫入內存中的數據內容的緩存 //參4:寫入數據大小 //參5:一個選項,0表示忽視 //返回值: 非0值表示成功, 返回0則表示寫入錯誤。調用GetLastError()查看錯誤原因 6.獲取LoadLibrary()函數地址,因為要用他來動態加載DLL,該函數在kernel32.dll文件中 PROC AdrMyDllDir=(PROC)::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),"LoadLibraryW");//W代表UNICODE版本,說實話,A代表多字節字符集,本人喜歡UNICODE版本 GetProcAddress() FARPROC GetProcAddress(HMODULE hModule,LPCWSTR lpProcName); //功能:返回指定的DLL輸出函數的函數地址 //參數1:DLL模塊句柄 //參數2:DLL輸出函數的函數名 這個函數的返回值,就是LoadLibraryW的地址了 7.創建遠程線程,既在目標進程中創建一個線程,這里的線程跟普通的線程不同,普通線程有線程處理函數ProcThread() CreateRemoteThread() HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); //函數功能:在制定進程中的虛擬地址中創建一個線程 //參數1:進程句柄,線程被創建在這個進程中 //參數2:安全等級,0表示默認安全等級 //參數3:創建線程的大小,0表示系統自動分配線程實際需要的大小 //參數4:線程起始地址,使用LPTHREAD_START_ROUTINE 定義的線程,並且線程是在遠程進程中已經存在。 //參數5: 給線程函數傳遞的參數 //參數6:創建標志,如果參數是0,則線程創建后立即運行 //參數7:線程ID,如果 ID給0 ,則不返回創建線程的ID ::CreateRemoteThread(hProcess,0,0,(LPTHREAD_START_ROUTINE)AdrMyDllDir,bufRemote,0,0); 這里的AdrMyDllDir存放LoadLibraryW ,也就是說把LoadLibraryW當做線程處理函數,傳入的參數bufRemote存放的是目標DLL文件的地址。 二。下面講解一下如何用hook既鈎子注入DLL文件。 首先給不懂鈎子的人簡單介紹一下原理:所謂hook,既鈎子。hook會在應用程序接到消息之前,攔截應用程序的信息,比如鼠標鍵盤鈎子會攔截一個應用程序的鼠標鍵盤信息。要做盜號木馬?用WH_KEYBOARD類型的hook 1.我們要跨進程使用鈎子,要把hook函數寫在DLL文件中,這是微軟明確規定的。也有其他方法,這里不多敘述 2.在DLL文件中 設置鈎子. 這里需要調用線程ID,threadId,我們會在下面調用DLL的調用端中寫入 hhookGetMsg=::SetWindowsHookEx(WH_GETMESSAGE,GetMessageHookProc,::GetModuleHandle(TEXT("dll.dll")),threadId); //參數1:鈎子類型 //參數2:鈎子處理函數 //參數3:鈎子所在的模塊 //參數4:鈎子要攔截的線程ID,如果要設置全局鈎子,這里給0。 把這個SetWindowsHookEx()函數寫在一個導出函數中,允許調用dll文件的程序調用 _declspec(dllexport) void SetHook(DWORD threadId) { hhookGetMsg=::SetWindowsHookEx(WH_GETMESSAGE,GetMessageHookProc,::GetModuleHandle(TEXT("dll.dll")),threadId); } SetHook()就是本dll的導出函數 3.在鈎子處理函數中寫入功能,當鈎子截取到WM_NULL消息的時候,注入DLL文件。由於WM_NULL消息,是個沒用的消息,應用程序一般不會收到這個消息,除非我們自己發送一個這個消息,所以我們在注入DLL的時候,只要給要注入的應用程序發一個WM_NULL消息,當鈎子截取到WM_NULL的時候就注入鈎子,就可以了。 LRESULT CALLBACK GetMessageHookProc(int nCode,WPARAM wParam,LPARAM lParam) { MSG* pMsg=(MSG*)lParam; if(WM_NULL==pMsg->message) ::LoadLibraryW(TEXT("D://MyDLL.dll")); } 好了,編譯DLL項目,產生DLL文件。 4.編寫調用端,調用鈎子 首先獲取窗口句柄 HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 返回窗體句柄。hWnd. hWnd=FindWindow(0,要注入dll的窗體的名稱(例如:千千靜聽)) 利用hWnd,查找窗體線程ID threadId=GetWindowThreadProcessId(hWnd,0); 好了,我們有了線程ID了,可以調用鈎子了。 SetHook(threadId); 這時鈎子已經加載到目標線程中了。 向目標窗體發送WM_NULL消息 SendMessage(hWnd,WM_NULL,0,0); 鈎子會在目標窗體受到消息前受到WM_NULL消息。由於鈎子處理函數中做了判斷,當受到WM_NULL消息時,加載DLL文件。所以DLL文件就注入到目標線程中了。 你可以把你的DLL文件中寫入許多功能,而且DLL已經被目標程序加載了,也就是說,你的DLL程序已經打入到目標程序內部了,所以現在你可以為所欲為了