TOC

代码注入是一种向目标进程插入独立运行代码并使之运行的技术,一般调用CreateRemoteThread()API以远程线程形式运行插入的代码,所以也被称为线程注入。 首先向目标进程插入代码和数据,在此过程中,代码以线程过程形式插入,而代码中使用的数据则以线程参数的形式传入,也就是说代码与数据是分别注入的。

// CodeInjection.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "windows.h"
#include "stdio.h"
#include "windef.h"
typedef struct _THREAD_PARAM
{
	//FARPROC是一个(int FAR WINAPI*)()类型的指针
	FARPROC pFunc[2];  // LoadLibraryA(), GetProcAddress()
	char szBuf[4][128];  // "user32.dll", "MessageBoxA",
	                     // "www.reversecore.com", "ReverseCore"
} THREAD_PARAM, *PTHREAF_PARAM;

// LoadLibraryA() 函数指针PFLOADLIBRARYA
typedef HMODULE (WINAPI *PFLOADLIBRARYA)(LPCSTR lpLibFileName);

// GetProcAddress()
typedef FARPROC (WINAPI *PFGETPROCADDRESS)
(
	HMODULE hModule,
	LPCSTR lpProcName
);

// MessageBoxA()
typedef int (WINAPI *PFMESSAGEBOXA)
(
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType
);

// Thread Procedure
DWORD WINAPI ThreadProc(LPVOID lParam)
{
	PTHREAF_PARAM pParam = (PTHREAF_PARAM)lParam;
	HMODULE hMod = NULL;
	FARPROC pFunc = NULL;

	// LoadLibraryA("user32.dll")
	// pParam->pFunc[0] -> kernel32!LoadLibraryA()
	// pParam->szBuf[0] -> "user32.dll"
	hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]);

	// GetProcAddress("MessageBoxA")
	// pParam->pFunc[1] -> kernel32!GetProcAddress()
	// pParam->szBuf[1] -> "MessageBoxA"
	pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, 
		pParam->szBuf[1]);

	// MessageBoxA(NULL, "www...", "ReverseCore", MB_OK)
	// pParam->szBuf[2] = "www..."
	// pParam->szBuf[3] = "ReverseCore"
	((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);

	return 0;
}

BOOL InjectCode(DWORD dwPID)
{
	HMODULE hMod = NULL;
	THREAD_PARAM param = { 0, };
	HANDLE hProcess = NULL;
	HANDLE hThread = NULL;
	LPVOID pRemoteBuf[2] = { 0, };
	DWORD dwSize = 0;

	hMod = GetModuleHandleA("kernel32.dll");

	param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
	param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
	strcpy_s(param.szBuf[0], "user32.dll");
	strcpy_s(param.szBuf[1], "MessageBoxA");
	strcpy_s(param.szBuf[2], "www.reversecore.com");
	strcpy_s(param.szBuf[3], "ReverseCore");

	// OpenProcess
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,
		FALSE,
		dwPID);

	// Allocation for THREAD_PRARM
	dwSize = sizeof(THREAD_PARAM);
	pRemoteBuf[0] = VirtualAllocEx(hProcess, 
		NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	if (pRemoteBuf[0] == NULL)
	{
		printf("VirtualAllocEx failed\n");
		return FALSE;
	}
	if (!WriteProcessMemory(hProcess,
		pRemoteBuf[0], (LPVOID)&param, dwSize, NULL))
	{
		printf("WriteProcessMemory failed\n");
		return FALSE;
	}

	// Allocation for ThreadProc
	dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
	printf("dwSize: %d\n", dwSize);
	pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize,
		MEM_COMMIT, PAGE_EXECUTE_READWRITE);  // 这里注意要有可执行权限
	if (pRemoteBuf[1] == NULL)
	{
		printf("VirtualAllocEx failed\n");
		return FALSE;
	}
	if (!WriteProcessMemory(hProcess, pRemoteBuf[1],
		(LPVOID)ThreadProc, dwSize, NULL))
	{
		printf("WriteProcessMemory failed\n");
		return FALSE;
	}

	hThread = CreateRemoteThread(hProcess,
		NULL,
		0,
		(LPTHREAD_START_ROUTINE)pRemoteBuf[1],
		pRemoteBuf[0],
		0,
		NULL);
	if (hThread == NULL)
	{
		printf("CreateRemoteThread failed\n");
		return FALSE;
	}

	WaitForSingleObject(hThread, INFINITE);

	CloseHandle(hThread);
	CloseHandle(hProcess);

	return TRUE;
}

int main(int argc, char *argv[])
{
	DWORD dwPID = 0;

	if (argc != 2)
	{
		printf("\n usage: %s PID\n", argv[0]);
		return 1;
	}

	dwPID = (DWORD)atol(argv[1]);
	InjectCode(dwPID);

	return 0;
}

执行的时候注意要生成release版本,因为MS Virual C++中使用Release模式编译程序代码后,源代码中函数顺序与二进制代码中的顺序是一致的,所以代码中的InjectCode-ThreadProc才可以表示ThreadProc函数的大小。 将PID设置成notepad.exe的PID时,结果如下: