遠程線程DLL注入

老手請飄過,寫給新手看的低級東西

一、步驟

1、CreateThread
    要搞懂遠程線程注入技術,首先應該用過CreateThread創建多線程。
    如果對這個函數怎麼使用沒搞懂下面的內容就不用看了,如果對這個函數理解了那麼繼續走

2、如何加載一個DLL
    要在目標進程注入一個DLL,也就是要將DLL加載到目標進程,我們平時在使用DLL時,是怎麼加載的?
    通過LoadLibrary加載。那麼我們要將一個DLL注入目標進程,可以理解爲我們要在目標進程執行LoadLibrary("xxxdll")
    
3、如何在目標進程執行LoadLibrary
    如果是在自己的進程,我們直接調用LoadLibrary就可以加載一個DLL,現在的問題是我們要在其它進程
    執行LoadLibrary,這就要藉助創建遠程線程
    
4、如何創建遠程線程
    調用下面這個函數,就可以創建遠程線程,我們看下msdn對這個函數的描述:
    The CreateRemoteThread function creates a thread that runs in the virtual address space of another process. 

    HANDLE CreateRemoteThread(
        HANDLE hProcess,                          // handle to process
        LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
        SIZE_T dwStackSize,                       // initial stack size
        LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
        LPVOID lpParameter,                       // thread argument
        DWORD dwCreationFlags,                    // creation option
        LPDWORD lpThreadId                        // thread identifier
    );
    其它參數不多說了,如果不懂可以百度這個函數用法,說說第四個參數
    LPTHREAD_START_ROUTINE lpStartAddress,其實這個參數和CreateThread的第三個參數一樣,LPTHREAD_START_ROUTINE原型如下:
    DWORD WINAPI ThreadProc(
        LPVOID lpParameter   // thread data
    );

    說白了第四個參數就是要指定,線程跑起來時,要執行的代碼在哪裏,這就給我們注入dll帶來了機會啊,我們可以把目標進程中LoadLibrary
    函數在內存中的地址作爲CreateRemoteThread的第四個參數,那麼線程運行時,就去執行LoadLibrary這個函數了。
    
    補充下爲什麼可以把LoadLibrary這個函數的地址,作爲第四個參數,我們來看下LoadLibrary的原型:
    HMODULE LoadLibrary(
        LPCTSTR lpFileName   // file name of module
    );
    
    發現沒,LoadLibrary在MSDN中給出的原型只少了個WINAPI,但是Windows所有的API默認都是WINAPI啊,(WINAPI表示調用約定)
    返回值:DWORD 和 HMODULE 本質就是個整數
    參數:LPVOID 和 LPCTSTR 都是個指針
    這就是爲什麼可以把LoadLibrary作爲CreateRemoteThread函數的第三個參數,這樣我們就完美利用CreateRemoteThread創建一個
    遠程線程,並執行LoadLibrary,去加載我們要注入的DLL了。
    
    那要如何獲取目標進程中的LoadLibrary函數地址了,很簡單我們獲取自己進程中的LoadLibrary的地址即可,LoadLibrary屬於kernel32模塊
    這個模塊在每個進程中加載的基地址都一樣,所以LoadLibrary在自己進程中的地址和在目標進程中的地址是一致的。
    
5 解決LoadLibrary的參數問題
    在第四步中我們解決了如何跨進程調用LoadLibrary這個問題,現在的問題是,執行LoadLibrary,我們要給它一個參數,
    這個參數用來指明DLL的路徑。我們可以利用CreateRemoteThread的第五個參數LPVOID lpParameter,來解決。
    lpParameter這個參數在遠程線程執行時,會傳遞給LoadLibrary (LoadLibrary就是遠程線程),作爲LoadLibrary的第一參數。
    
    但是這裏有一個問題,我們調用CreateRemoteThread時,是在自己的進程調用,那麼傳遞lpParameter這個參數時,不能使用自己進程
    虛擬地址空間的地址,那要怎麼解決這個問題
    
6 VirtualAllocEx
    在Step5中,碰到了新的問題,如何傳遞LoadLibrary的參數,因爲這個參數必須是目標進程中的一個虛擬地址。
    我們需要用到VirtualAllocEx這個函數,這個函數可以在目標進程申請內存,我們通過調用這個函數,在目標
    進程中申請一段內存,然後把DLL的路徑,寫到這段內存中,比如d:\xxx\xxoo.dll
    這個函數的返回值,就是申請到的內存的起始地址。所以我們可以把返回值作爲CreateRemoteThread的第5個參數,這樣解決了給
    LoadLibrary傳遞參數的問題。
    
7 其它一些細節問題看代碼註釋
    

二、注意事項
    如果你要注入的目標進程是64位程序,那麼你的注入進程必須是64位的,而且要注入的DLL也必須是64位的,否則           CreateRemoteThread會 失敗,GetLastError返回錯誤代碼:5。寫一個完善的注入代碼要考慮的問題很多

三、部分關鍵代碼如下,代碼有參考這個博客:

https://www.cnblogs.com/BoyXiao/archive/2011/08/11/2134367.html

代碼網上一大把,關鍵是搞清楚思路,如果需要完整代碼可以聯繫QQ 844255657, 這裏沒有把所有代碼貼上來了,

因爲網上太多了。

int _tmain(int argc, _TCHAR* argv[])
{
	

	if (!AdjustProcessTokenPrivilege()){
		MyOutputDebugString("提權失敗\n");
	}

	DWORD dwPid = GetPidByName("explorer.exe");
	if (dwPid == 0){
		MyOutputDebugString("GetPidByName failed\n");
		return -1;
	}

	MyOutputDebugString("explorer.exe pid=%d\n", dwPid);

	HANDLE hProcess;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);

	if (hProcess == NULL)
	{
		MyOutputDebugString("打開進程失敗!!!!");
		return -1;
	}


	//1.在遠程進程中分配內存
	LPVOID pszRemoteBuffer = (char *)VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);

	if (pszRemoteBuffer == NULL)
	{
		MyOutputDebugString("申請遠程空間失敗");
		return -1;
	}
	//2.在遠程申請的內存空間中寫入DLL的路徑,後面這塊數據當做遠程線程的參數
	SIZE_T dwWriten = 0;
	const char * dllPath = "D:\\VS\\DllToInject\\x64\\Debug\\UtilDll.dll";
	if (!WriteProcessMemory(hProcess, pszRemoteBuffer, (LPVOID)dllPath, strlen(dllPath) + 1, &dwWriten))
	{
		MyOutputDebugString("寫入內存失敗");
		return -1;
	}

	//3.獲取遠程進程中LoadLibry的地址, 這裏使用當前進程Kernel32模塊的基地址當做遠程進程中的kernel32的基地址,這不是巧合
	//kernel32在每個進程中的基地址都一樣,可能是操作系統爲進程加載kernel32時,直接將已經加載了的kernel32映射到需要這個模塊的進程中
	//pfnLoadLibrary 就是遠程線程, 所以遠程線程執行就是在對方進程調用LoadLibrary, 
	//如果是Unicode程序,GetProcAddress需要使用LoadLibraryW
	HMODULE hMouDle = GetModuleHandle("Kernel32");
	PTHREAD_START_ROUTINE pfnLoadLibrary = (PTHREAD_START_ROUTINE)GetProcAddress(hMouDle, "LoadLibraryA");

	if (pfnLoadLibrary == NULL)
	{
		MyOutputDebugString("獲取LoadLibrary地址失敗!!!");
		return -1;
	}

	//4.創建遠程線程
	DWORD dwThreadId = 0;
	HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnLoadLibrary, pszRemoteBuffer, 0, &dwThreadId);

	if (hThread == NULL)
	{
		MyOutputDebugString("創建遠程線程失敗 %d\n", GetLastError());
		return -1;
	}

	//5 等待遠程線程退出
	DWORD exitCode = 0;
	DWORD dwRet = 0;
	WaitForSingleObject(hThread, INFINITE);
	dwRet = GetExitCodeThread(hThread, &exitCode);

	//6 檢查退出碼,如果退出碼等於0,說明LoadLibrary失敗了
	if (dwRet == 0){
		MyOutputDebugString("GetExitCodeThread failed\n");
		return -1;
	}

	if (exitCode == 0){
		MyOutputDebugString("LoadLibrary %s failed\n", dllPath);
	}

	VirtualFreeEx(hProcess, pszRemoteBuffer, MAX_PATH, MEM_DECOMMIT);
	::CloseHandle(hThread);
	::CloseHandle(hProcess);

	getchar();

	//6 釋放注入的DLL, 需要再次創建遠程線程執行FreeLibrary
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章