#pragma once
class CInjectCode
{
public:
	CInjectCode(DWORD (*fn)(HINSTANCE));
	~CInjectCode();
	void SetRemoteThread_Main(DWORD(*fn)(HINSTANCE));
	//注入
	BOOL Inject(DWORD dwProcessID);
	BOOL Inject(const wchar_t* wszProcessName);
private:
	//完成重定位
	void RelocCode(LPBYTE lpImage, LPBYTE lpInjectBase);
	//用于完成API函数的导入,参数为要插入代码处地址
	BOOL LoadAPI(LPBYTE lpInjectBase);
	//CreateRemoteThread的线程运行入口
	DWORD ThreadEntry(LPBYTE  lpImageBase);
	//通过进程名获取进程ID
	BOOL GetProcessIDByName(const wchar_t* wszProcessName, DWORD& dwProcID);
	//提升se_debug权限
	BOOL AdjustProcessTokenPrivilege();
private:
	//远程执行的函数指针
	DWORD(*fnRemoteThread_Main)(HINSTANCE);
};
 
#include "stdafx.h"
#include "InjectCode.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <memory.h>
#include <TlHelp32.h>
CInjectCode::CInjectCode(DWORD(*fn)(HINSTANCE))
{
	SetRemoteThread_Main(fn);
}
CInjectCode::~CInjectCode()
{
}
void CInjectCode::SetRemoteThread_Main(DWORD(*fn)(HINSTANCE))
{
	fnRemoteThread_Main = fn;
}
//提升se_debug权限
BOOL CInjectCode::AdjustProcessTokenPrivilege()
{
	LUID luidTmp;
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN\_ADJUST\_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		OutputDebugString(_T("AdjustProcessTokenPrivilege OpenProcessToken Failed ! n"));
		return FALSE;
	}
	if (!LookupPrivilegeValue(NULL, SE\_DEBUG\_NAME, &luidTmp))
	{
		OutputDebugString(_T("AdjustProcessTokenPrivilege LookupPrivilegeValue Failed ! n"));
		CloseHandle(hToken);
		return FALSE;
	}
	tkp.PrivilegeCount = 1;
	tkp.Privileges\[0\].Luid = luidTmp;
	tkp.Privileges\[0\].Attributes = SE\_PRIVILEGE\_ENABLED;
	if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
	{
		OutputDebugString(_T("AdjustProcessTokenPrivilege AdjustTokenPrivileges Failed ! n"));
		CloseHandle(hToken);
		return FALSE;
	}
	return TRUE;
}
//完成重定位
void CInjectCode::RelocCode(LPBYTE lpImage, LPBYTE lpInjectBase)
{
	DWORD  dwRva = 0, dwRvaCount = 0, dwRelocOffset = 0;
	LPWORD  lpwOffset = NULL;
	PIMAGE\_NT\_HEADERS pNtHeader = NULL;
	LPBYTE lpRelocTable;
	PIMAGE\_BASE\_RELOCATION  pBaseReloc;
	//获取ntheader
	pNtHeader = (PIMAGE\_NT\_HEADERS)(lpImage + ((PIMAGE\_DOS\_HEADER)lpImage)->e_lfanew);
	//获取重定位表位置
	lpRelocTable = lpImage + pNtHeader->OptionalHeader.DataDirectory\[5\].VirtualAddress;
	pBaseReloc = (PIMAGE\_BASE\_RELOCATION)lpRelocTable;
	//获取重定位表偏移
	dwRelocOffset = (DWORD)lpInjectBase - pNtHeader->OptionalHeader.ImageBase;
	//遍历重定位表,修正需要重定位的代码
	while (pBaseReloc->VirtualAddress != NULL)
	{
		lpwOffset = (WORD*)(lpRelocTable + sizeof(IMAGE\_BASE\_RELOCATION));
		dwRvaCount = (pBaseReloc->SizeOfBlock - sizeof(IMAGE\_BASE\_RELOCATION)) / 2;
		//循环修正
		for (DWORD i = 0; i < dwRvaCount; i++)
		{
			//获取要修正的RVA
			dwRva = (DWORD)lpImage + (pBaseReloc->VirtualAddress) + (DWORD)(*lpwOffset & 0x0fff);
			//RVA加上修正量进行修正
			*(DWORD*)dwRva += dwRelocOffset;
			lpwOffset++;
		}
		//指向下一页重定位信息处
		lpRelocTable += pBaseReloc->SizeOfBlock;
		pBaseReloc = (PIMAGE\_BASE\_RELOCATION)lpRelocTable;
	}
}
//用于完成API函数的导入,参数为要插入代码处地址
BOOL CInjectCode::LoadAPI(LPBYTE lpInjectBase)
{
	PIMAGE\_DOS\_HEADER pDosHeader = (PIMAGE\_DOS\_HEADER)lpInjectBase;
	PIMAGE\_NT\_HEADERS pNtHeader = (PIMAGE\_NT\_HEADERS)(lpInjectBase + pDosHeader->e_lfanew);
	PIMAGE\_IMPORT\_DESCRIPTOR pImportDescriptor = (PIMAGE\_IMPORT\_DESCRIPTOR)
		(lpInjectBase + pNtHeader->OptionalHeader.DataDirectory\[1\].VirtualAddress);
	for (; pImportDescriptor->OriginalFirstThunk != 0; pImportDescriptor++)//遍历导入表
	{
		HMODULE hDll = LoadLibraryA((LPCSTR)(lpInjectBase + pImportDescriptor->Name));
		//上面能直接引用LoadLibrary是由于本地和远程进程中该函数地址都是相同的
		if (hDll == NULL)
			return FALSE;
		PIMAGE\_THUNK\_DATA Origin = (PIMAGE\_THUNK\_DATA)(lpInjectBase + pImportDescriptor->OriginalFirstThunk);
		PIMAGE\_THUNK\_DATA First = (PIMAGE\_THUNK\_DATA)(lpInjectBase + pImportDescriptor->FirstThunk);
		LPCSTR Name = NULL;
		PIMAGE\_IMPORT\_BY\_NAME Import\_name = NULL;
		for (; Origin->u1.Ordinal != 0; Origin++, First++)
		{
			if (Origin->u1.Ordinal & IMAGE\_ORDINAL\_FLAG)
				Name = (LPCSTR)IMAGE_ORDINAL(Origin->u1.Ordinal);
			else
			{
				Import\_name = (PIMAGE\_IMPORT\_BY\_NAME)(lpInjectBase + (DWORD)(Origin->u1.AddressOfData));
				Name = (LPCSTR)Import_name->Name;
			}
			First->u1.Function = (DWORD)GetProcAddress(hDll, Name);
			//上面能直接引用GetProcAddress是由于本地和远程进程中该函数地址都是相同的
			if (First->u1.Function == NULL)
				return FALSE;
		}
	}
	return TRUE;
}
//CreateRemoteThread的线程运行入口
DWORD CInjectCode::ThreadEntry(LPBYTE  lpImageBase)
{
	if (LoadAPI(lpImageBase))//先完成API函数的导入工作
		fnRemoteThread\_Main((HINSTANCE)lpImageBase);  //执行函数RemoteThread\_Main中的代码
	return 0;
}
//通过进程名获取进程ID
BOOL CInjectCode::GetProcessIDByName(const wchar_t* wszProcessName, DWORD& dwProcID)
{
	HANDLE hSnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, dwProcID);
	PROCESSENTRY32 pe = { sizeof(pe) };
	BOOL bOk = ::Process32First(hSnapShot, &pe);
	while (bOk)
	{
		if (wcsstr(pe.szExeFile, wszProcessName) != NULL)
		{
			dwProcID = pe.th32ProcessID;
			return TRUE;
		}
		bOk = ::Process32Next(hSnapShot, &pe);
	}
	::CloseHandle(hSnapShot);
	return FALSE;
}
//远程注入
BOOL CInjectCode::Inject(DWORD dwProcessID)
{
	LPBYTE lpNewMoudle = NULL;
	HANDLE hRemoteProcess = NULL;
	HANDLE hRemoteThread = NULL;
	BOOL bRet = TRUE;
	__try
	{
		//获取自身句柄
		LPBYTE lpMoudle = NULL;
		lpMoudle = (LPBYTE)GetModuleHandle(NULL);
		if (lpMoudle == NULL)
		{
			OutputDebugString(_T("GetModuleHandle failedn"));
			bRet = FALSE;
			__leave;
		}
		//获取NT_HEADER
		PIMAGE\_NT\_HEADERS pNtHeader = NULL;
		pNtHeader = (PIMAGE\_NT\_HEADERS)(lpMoudle + ((PIMAGE\_DOS\_HEADER)lpMoudle)->e_lfanew);
		//得到自身映像大小
		DWORD dwImageSize;
		dwImageSize = pNtHeader->OptionalHeader.SizeOfImage;
		//在当前空间申请空间存放自身代码
		lpNewMoudle = (LPBYTE)VirtualAlloc(NULL, dwImageSize, MEM\_COMMIT | MEM\_RESERVE,
			PAGE\_EXECUTE\_READWRITE);
		if (lpNewMoudle == NULL)
		{
			OutputDebugString(_T("VirtualAlloc failedn"));
			bRet = FALSE;
			__leave;
		}
		//拷贝自身到buffer
		PIMAGE\_NT\_HEADERS pNewNtHeader = NULL;
		memcpy_s(lpNewMoudle, dwImageSize, lpMoudle, dwImageSize);
		//获取Buffer中NtHeader
		pNewNtHeader = (PIMAGE\_NT\_HEADERS)(lpNewMoudle + ((PIMAGE\_DOS\_HEADER)lpMoudle)->e_lfanew);	
		//提升权限
		if (!AdjustProcessTokenPrivilege())
		{
			OutputDebugString(_T("OpenProcess failedn"));
		}
		//打开远程进程
		hRemoteProcess = OpenProcess(PROCESS\_ALL\_ACCESS, FALSE, dwProcessID);
		if (hRemoteProcess == NULL)
		{
			OutputDebugString(_T("OpenProcess failedn"));
			bRet = FALSE;
			__leave;
		}
		//在远程进程申请空间
		LPBYTE lpInjectPoint;
		lpInjectPoint = (LPBYTE)VirtualAllocEx(hRemoteProcess, 0, dwImageSize, MEM\_COMMIT, PAGE\_EXECUTE_READWRITE);
		if (lpInjectPoint == NULL)
		{
			OutputDebugString(_T("VirtualAllocEx failedn"));
			bRet = FALSE;
			__leave;
		}
		//重定位NewMoudle代码
		RelocCode(lpNewMoudle, lpInjectPoint);
		//得到ThreadEntry在远程进程中的地址
		LPTHREAD\_START\_ROUTINE lpRemoteEntryPoint;
		LPBYTE lpParam;
		lpRemoteEntryPoint = (LPTHREAD\_START\_ROUTINE)(lpInjectPoint + (DWORD)fnRemoteThread_Main - lpMoudle);
		//将插入点地址作为参数传递给线程函数
		lpParam = lpInjectPoint;
		//将重定位好的代码通过WriteProcessMemory写入远程进程的内存空间中
		if (!WriteProcessMemory(hRemoteProcess, lpInjectPoint, lpNewMoudle, dwImageSize, NULL))
		{
			OutputDebugString(_T("WriteProcessMemory failedn"));
			bRet = FALSE;
			__leave;
		}
		//通过CreateRemoteThread启动刚写入的代码,参数为Param
		hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, lpRemoteEntryPoint, lpParam, 0, NULL);
		if (hRemoteThread == NULL)
		{
			OutputDebugString(_T("CreateRemoteThread failedn"));
			bRet = FALSE;
			__leave;
		}
		// 		//等待线程执行完成
		// 		WaitForSingleObject(hRemoteThread, INFINITE);
		// 
		// 		//获取完成
		// 		DWORD dwExitCode;
		// 		if (!GetExitCodeThread(hRemoteThread, &dwExitCode))
		// 		{
		// 			OutputDebugString(_T("GetExitCodeThread failedn"));
		// 			bRet = FALSE;
		// 			__leave;
		//		}
	}
	__finally
	{
		if (lpNewMoudle != NULL)
		{
			VirtualFree(lpNewMoudle, 0, MEM_RELEASE);
		}
		if (hRemoteProcess != NULL)
		{
			CloseHandle(hRemoteProcess);
		}
	}
	return bRet;
}
//重载使用进程名
BOOL CInjectCode::Inject(const wchar_t* wszProcessName)
{
	DWORD dwProcID;
	if (GetProcessIDByName(wszProcessName, dwProcID))
	{
		return Inject(dwProcID);
	}
	else
	{
		OutputDebugString(_T("GetProcessIDByName failedn"));
		return FALSE;
	}
}
附上使用demo
#include "InjectCode.h"
//远程要执行的代码,在这里只演示MessageBox
DWORD RemoteThread_Main1(HINSTANCE hInstance)
{
	::MessageBox(0, \_T("远程线程插入成功!"), \_T("远程线程"), 0);
	return 0;
}
DWORD RemoteThread_Main2(HINSTANCE hInstance)
{
	::MessageBox(0, \_T("远程线程插入成功!"), \_T("远程线程"), 0);
	return 0;
}
int \_tmain(int argc, \_TCHAR* argv\[\])
{
	CInjectCode injectcode(RemoteThread_Main1);
	if injectcode.Inject(L"notepad++.exe");
	injectcode.SetRemoteThread\_Main(RemoteThread\_Main2);
	injectcode.Inject(164);
	return 0;
}