目前公開的DLL注入技巧共有如下幾種:編程
遠程線程注入的方式在於使用一個Windows API函數CreateRemoteThread,經過它能夠在另一個進程中注入一個線程並執行。api
操做系統:win10_64位 被注入程序:系統自帶notepad_32位
Procexp : 查看進程模塊是否被注入成功的工具
查找處理窗口的類名和窗口名稱匹配指定的字符串緩存
WINUSERAPI HWND WINAPI FindWindow( //參數指向類名 _In_opt_ LPCSTR lpClassName, //指向窗口名 _In_opt_ LPCSTR lpWindowName); WINUSERAPI
指向一個以NULL字符結尾的、用來指定類名的字符串或一個能夠肯定類名字符串的原子。若是這個參數是一個原子,那麼它必須是一個在調用此函數前已經經過GlobalAddAtom函數建立好的全局原子。這個原子(一個16bit的值),必須被放置在lpClassName的低位字節中,lpClassName的高位字節置零。
若是該參數爲null時,將會尋找任何與lpWindowName參數匹配的窗口。安全
指向一個以NULL字符結尾的、用來指定窗口名(即窗口標題)的字符串。若是此參數爲NULL,則匹配全部窗口名。函數
若是函數執行成功,則返回值是擁有指定窗口類名或窗口名的窗口的句柄。工具
若是函數執行失敗,則返回值爲 NULL。能夠經過調用GetLastError函數得到更加詳細的錯誤信息。操作系統
找出某個進程的PID值。線程
WINUSERAPI DWORD WINAPI GetWindowThreadProcessId( //窗口的句柄 _In_ HWND hWnd, //進程號的存放地址(變量地址) _Out_opt_ LPDWORD lpdwProcessId);
返回線程號,注意,lpdwProcessId 是存放進程號的變量。指針
DWORD dwPID, dwTID; dwTID = GetWindowThreadProcessId( hWnd, &dwPID );
能夠在其餘進程分配或者預約一塊虛擬內存code
WINBASEAPI _Ret_maybenull_ _Post_writable_byte_size_(dwSize) LPVOID WINAPI VirtualAllocEx( //申請內存所在的進程句柄。 _In_ HANDLE hProcess, //保留頁面的內存地址;通常用NULL自動分配 。 _In_opt_ LPVOID lpAddress, //欲分配的內存大小,字節單位; //注意實際分配的內存大小是頁內存大小的整數倍 _In_ SIZE_T dwSize, //指定內存分配的方式,預約仍是要提交 _In_ DWORD flAllocationType, //指定應用程序讀寫的權限,內存的保護屬性 _In_ DWORD flProtect );
MEM_COMMIT:爲特定的頁面區域分配內存中或磁盤的頁面文件中的物理存儲
MEM_PHYSICAL :分配物理內存(僅用於地址窗口擴展內存)
MEM_RESERVE:保留進程的虛擬地址空間,而不分配任何物理存儲。保留頁面可經過繼續調用VirtualAlloc()而被佔用
MEM_RESET :指明在內存中由參數lpAddress和dwSize指定的數據無效
MEM_TOP_DOWN:在儘量高的地址上分配內存(Windows 98忽略此標誌)
MEM_WRITE_WATCH:必須與MEM_RESERVE一塊兒指定,使系統跟蹤那些被寫入分配區域的頁面(僅針對Windows 98)
PAGE_READONLY: 該區域爲只讀。若是應用程序試圖訪問區域中的頁的時候,將會被拒絕訪
PAGE_READWRITE 區域可被應用程序讀寫
PAGE_EXECUTE: 區域包含可被系統執行的代碼。試圖讀寫該區域的操做將被拒絕。
PAGE_EXECUTE_READ :區域包含可執行代碼,應用程序能夠讀該區域。
PAGE_EXECUTE_READWRITE: 區域包含可執行代碼,應用程序能夠讀寫該區域。
PAGE_GUARD: 區域第一次被訪問時進入一個STATUS_GUARD_PAGE異常,這個標誌要和其餘保護標誌合併使用,代表區域被第一次訪問的權限
PAGE_NOACCESS: 任何訪問該區域的操做將被拒絕
PAGE_NOCACHE: RAM中的頁映射到該區域時將不會被微處理器緩存(cached)
注:PAGE_GUARD和PAGE_NOCHACHE標誌能夠和其餘標誌合併使用以進一步指定頁的特徵。PAGE_GUARD標誌指定了一個防禦頁(guard page),即當一個頁被提交時會因第一次被訪問而產生一個one-shot異常,接着取得指定的訪問權限。PAGE_NOCACHE防止當它映射到虛擬頁的時候被微處理器緩存。這個標誌方便設備驅動使用直接內存訪問方式(DMA)來共享內存塊。
執行成功就返回分配內存的首地址,不成功就是NULL。
此函數能寫入某一進程的內存區域。
WINBASEAPI _Success_(return != FALSE) BOOL WINAPI WriteProcessMemory( //由OpenProcess返回的進程句柄。 _In_ HANDLE hProcess, //要寫的內存首地址 _In_ LPVOID lpBaseAddress, //指向要寫的數據的指針。 _In_reads_bytes_(nSize) LPCVOID lpBuffer, //要寫入的字節數。 _In_ SIZE_T nSize, //可選參數,指向變量的指針接收的字節數轉移到指定的過程 _Out_opt_ SIZE_T * lpNumberOfBytesWritten );
非零值表明成功。
可用GetLastError獲取更多的錯誤詳細信息。
能夠建立一個在其它進程地址空間中運行的線程。
WINBASEAPI _Ret_maybenull_ HANDLE WINAPI CreateRemoteThread( //線程所屬進程的進程句柄. _In_ HANDLE hProcess, //一個指向 SECURITY_ATTRIBUTES 結構的指針, 該結指定了線程的安全屬性. _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //線程初始大小,以字節爲單位,若是該值設爲0,那麼使用系統默認大小. _In_ SIZE_T dwStackSize, //在遠程進程的地址空間中,該線程的線程函數的起始地址. _In_ LPTHREAD_START_ROUTINE lpStartAddress, //傳給線程函數的參數. _In_opt_ LPVOID lpParameter, 線程的建立標誌. _In_ DWORD dwCreationFlags, //指向所建立線程ID的指針,若是建立失敗,該參數爲NULL. _Out_opt_ LPDWORD lpThreadId );
若是調用成功,返回新線程句柄.
若是失敗,返回NULL.
Windows API函數。當等待仍在掛起狀態時,句柄被關閉。
WINBASEAPI DWORD WINAPI WaitForSingleObject( _In_ HANDLE hHandle, _In_ DWORD dwMilliseconds );
對象句柄。能夠指定一系列的對象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
定時時間間隔,單位爲milliseconds(毫秒).若是指定一個非零值,函數處於等待狀態直到hHandle標記的對象被觸發,或者時間到了。若是dwMilliseconds爲0,對象沒有被觸發信號,函數不會進入一個等待狀態,它老是當即返回。若是dwMilliseconds爲INFINITE,對象被觸發信號後,函數纔會返回。
執行成功,返回值指示出引起函數返回的事件.
VirtualFreeEx即爲目標進程的句柄,可在其它進程中釋放申請的虛擬內存空間。
WINBASEAPI BOOL WINAPI VirtualFreeEx( //目標進程的句柄。該句柄必須擁有 PROCESS_VM_OPERATION 權限。 _In_ HANDLE hProcess, //指向要釋放的虛擬內存空間首地址的指針。 _Pre_notnull_ _When_(dwFreeType == MEM_DECOMMIT, _Post_invalid_) _When_(dwFreeType == MEM_RELEASE, _Post_ptr_invalid_) LPVOID lpAddress, //虛擬內存空間的字節數。 _In_ SIZE_T dwSize, //釋放類型 _In_ DWORD dwFreeType );
釋放類型,取值見下表:
表示釋放後內存空間不可用,可是內存頁還存在
表示內存被釋放,內存頁徹底回收
#include "stdafx.h" #include <Windows.h> #define path _T("E:\\09核心編程\\_1304~1\\win原理下1\\Debug\\test.dll") bool Inject(DWORD dwId,WCHAR* szPath) { //1 在目標進程中申請一個空間 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwId); LPVOID pRemoteAddress = VirtualAllocEx( hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE ); //2 把dll的路徑寫入到對方的進程空間中 DWORD dwWriteSize = 0; //寫一段數據到指定進程所開闢的內存空間 WriteProcessMemory(hProcess, pRemoteAddress, szPath, wcslen(szPath) * 2 + 2, &dwWriteSize); //3 建立一個遠程線程,讓目標進程調用LoadLibrary HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, NULL, NULL ); WaitForSingleObject(hThread, -1); //4 釋放申請的虛擬內存空間 VirtualFreeEx(hProcess, pRemoteAddress, 1, MEM_DECOMMIT); return 0; } int _tmain(int argc, _TCHAR* argv[]) { DWORD dwId = 0; printf("請輸入一個ID:"); HWND hCalc = FindWindow(NULL, L"FileCleaner2.0"); DWORD dwPid = 0; DWORD dwRub = GetWindowThreadProcessId(hCalc, &dwPid); //選擇本身輸出PID或者自動獲取 // scanf_s("%d", &dwId); Inject(dwPid, path); return 0; }
#include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { MessageBox(NULL, L"呵呵", L"成功了,ye", NULL); } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
注入成果效果圖:
注入後的DLL查看: