#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;
}