一般而言要注入DLL到一个目标进程最简单的方法 就是先获取DLL文件路径,然后在目标进程分配内存空间将路径写入到目标进程,写入到目标进程后再调用CreateRemoteThread()/NtCreateThread()/RtlCreateUserThread()函数来运行LoadLibraryA/W函数调用自己的DLL,这种方法的缺陷也很明显那就是容易被游戏检测到,很容易被游戏拦截,比如CSGO最新版就已经有这个限制了。" G& L, e0 l2 B3 T$ A$ {; P
想要突破CSGO的限制注入DLL进去,我们可以采用反射式注入的方法(也可以先恢复CSGOhook的api进行远程线程注入),那么什么是反射式注入呢?又有什么有点呢?- {/ C! K F) K7 w6 Y
反射式dll注入与常规dll注入类似,而不同的地方在于反射式dll注入技术自己实现了一个reflective loader()函数来代替LoadLibaryA()函数去加载dll,示意图如下图所示。蓝色的线表示与用常规dll注入相同的步骤,红框中的是reflective loader()函数行为,也是下面重点描述的地方。- N1 d- L2 A3 I ?- @/ M' k
Reflective loader实现思路如下: ' w$ _# j- l4 k7 P* o
- 获得被注入进程未解析的dll的基地址。
- 获得必要的dll句柄和函数为修复导入表做准备。
- 分配一块新内存去取解析dll,并把pe头复制到新内存中和将各节复制到新内存中。
- 修复导入表和重定向表。
- 执行DllMain()函数。
" V- G+ O$ q+ L& v6 {$ K' a
: ^- W$ {) l/ U0 i' m
. ]7 r. Z% a* y: [6 A- Z" j
A# g7 U4 s' ~. `核心代码如下:
3 i( \: l5 Q. d4 K' y3 oManualMapInject.h
+ J: W- g1 u; V. `4 S S$ u/ ]/ Y#pragma once
#include "Injector.h"
using f_LoadLibraryA = HINSTANCE(WINAPI*)(const char* lpLibFilename);
using f_GetProcAddress = FARPROC(WINAPI*)(HMODULE hModule, LPCSTR lpProcName);
using f_DLL_ENTRY_POINT = BOOL(WINAPI*)(void* hDll, DWORD dwReason, void* pReserved);
#ifdef _WIN64
using f_RtlAddFunctionTable = BOOL(WINAPIV*)(PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount, DWORD64 BaseAddress);
#endif
struct MANUAL_MAPPING_DATA
{
f_LoadLibraryA pLoadLibraryA;
f_GetProcAddress pGetProcAddress;
#ifdef _WIN64
f_RtlAddFunctionTable pRtlAddFunctionTable;
#endif
BYTE* pbase;
HINSTANCE hMod;
DWORD fdwReasonParam;
LPVOID reservedParam;
BOOL SEHSupport;
};
//Note: Exception support only x64 with build params /EHa or /EHc
bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader = true, bool ClearNonNeededSections = true, bool AdjustProtections = true, bool SEHExceptionSupport = true, DWORD fdwReason = DLL_PROCESS_ATTACH, LPVOID lpReserved = 0);
void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData);
class CManualMapInject :public CInjector
{
public:
CManualMapInject();
virtual ~CManualMapInject();
virtual bool InjectorDLL(TCHAR* szPath,DWORD dwPid);
}; ManualMapInject.cpp
* x( V7 d5 y7 |#include "pch.h"
#include "ManualMapInject.h"
#ifdef _WIN64
#define CURRENT_ARCH IMAGE_FILE_MACHINE_AMD64
#else
#define CURRENT_ARCH IMAGE_FILE_MACHINE_I386
#endif
#define RELOC_FLAG32(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_HIGHLOW)
#define RELOC_FLAG64(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_DIR64)
#ifdef _WIN64
#define RELOC_FLAG RELOC_FLAG64
#else
#define RELOC_FLAG RELOC_FLAG32
#endif
CManualMapInject::CManualMapInject()
{
}
CManualMapInject::~CManualMapInject()
{
}
bool CManualMapInject::InjectorDLL(TCHAR* szPath, DWORD dwPid)
{
HANDLE hProc = GetProcessHandle(dwPid);
if (!hProc || !IsCorrectTargetArchitecture(hProc) || GetFileAttributes(szPath) == INVALID_FILE_ATTRIBUTES)
{
return false;
}
// std::ifstream File(szPath, std::ios::binary | std::ios::ate);
//
// if (File.fail())
// {
// printf("Opening the file failed: %X\n", (DWORD)File.rdstate());
// File.close();
// CloseHandle(hProc);
// system("PAUSE");
// return -5;
// }
//
// auto FileSize = File.tellg();
// if (FileSize < 0x1000)
// {
// printf("Filesize invalid.\n");
// File.close();
// CloseHandle(hProc);
// system("PAUSE");
// return -6;
// }
//
// BYTE* pSrcData = new BYTE[(UINT_PTR)FileSize];
// if (!pSrcData)
// {
// printf("Can't allocate dll file.\n");
// File.close();
// CloseHandle(hProc);
// system("PAUSE");
// return -7;
// }
//
// File.seekg(0, std::ios::beg);
// File.read((char*)(pSrcData), FileSize);
// File.close();
CFile file;
file.Open(szPath, CFile::modeRead);
ULONGLONG nFileSize = file.GetLength();
BYTE* pSrcData = new BYTE[nFileSize];
ZeroMemory(pSrcData,nFileSize);
file.SeekToBegin();
file.Read(pSrcData,nFileSize);
file.Close();
if (!ManualMapDll(hProc, pSrcData, nFileSize))
{
delete[] pSrcData;
CloseHandle(hProc);
return false;
}
delete[] pSrcData;
CloseHandle(hProc);
return false;
}
bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader,
bool ClearNonNeededSections, bool AdjustProtections,
bool SEHExceptionSupport, DWORD fdwReason, LPVOID lpReserved)
{
IMAGE_NT_HEADERS* pOldNtHeader = nullptr;
IMAGE_OPTIONAL_HEADER* pOldOptHeader = nullptr;
IMAGE_FILE_HEADER* pOldFileHeader = nullptr;
BYTE* pTargetBase = nullptr;
if (reinterpret_cast<IMAGE_DOS_HEADER*>(pSrcData)->e_magic != 0x5A4D)//"MZ"
{
return false;
}
pOldNtHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(pSrcData + reinterpret_cast<IMAGE_DOS_HEADER*>(pSrcData)->e_lfanew);
pOldOptHeader = &pOldNtHeader->OptionalHeader;
pOldFileHeader = &pOldNtHeader->FileHeader;
if (pOldFileHeader->Machine != CURRENT_ARCH)
{
return false;
}
pTargetBase = reinterpret_cast<BYTE*>(VirtualAllocEx(hProc, nullptr, pOldOptHeader->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (!pTargetBase)
{
return false;
}
DWORD oldp = 0;
VirtualProtectEx(hProc, pTargetBase, pOldOptHeader->SizeOfImage, PAGE_EXECUTE_READWRITE, &oldp);
MANUAL_MAPPING_DATA data{ 0 };
data.pLoadLibraryA = LoadLibraryA;
data.pGetProcAddress = GetProcAddress;
#ifdef _WIN64
data.pRtlAddFunctionTable = (f_RtlAddFunctionTable)RtlAddFunctionTable;
#else
SEHExceptionSupport = false;
#endif
data.pbase = pTargetBase;
data.fdwReasonParam = fdwReason;
data.reservedParam = lpReserved;
data.SEHSupport = SEHExceptionSupport;
//PE header
if (!WriteProcessMemory(hProc, pTargetBase, pSrcData, 0x1000, nullptr)) //only first 0x1000 bytes for the header
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
return false;
}
IMAGE_SECTION_HEADER* pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader);
for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader)
{
if (pSectionHeader->SizeOfRawData)
{
if (!WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSrcData + pSectionHeader->PointerToRawData, pSectionHeader->SizeOfRawData, nullptr))
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
return false;
}
}
}
//Mapping params
BYTE* MappingDataAlloc = reinterpret_cast<BYTE*>(VirtualAllocEx(hProc, nullptr, sizeof(MANUAL_MAPPING_DATA), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (!MappingDataAlloc)
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
return false;
}
if (!WriteProcessMemory(hProc, MappingDataAlloc, &data, sizeof(MANUAL_MAPPING_DATA), nullptr))
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
return false;
}
//Shell code
void* pShellcode = VirtualAllocEx(hProc, nullptr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!pShellcode)
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
return false;
}
if (!WriteProcessMemory(hProc, pShellcode, Shellcode, 0x1000, nullptr))
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE);
return false;
}
HANDLE hThread = CreateRemoteThread(hProc, nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(pShellcode), MappingDataAlloc, 0, nullptr);
if (!hThread)
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE);
return false;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
HINSTANCE hCheck = NULL;
while (!hCheck)
{
DWORD exitcode = 0;
GetExitCodeProcess(hProc, &exitcode);
if (exitcode != STILL_ACTIVE)
{
return false;
}
MANUAL_MAPPING_DATA data_checked{ 0 };
ReadProcessMemory(hProc, MappingDataAlloc, &data_checked, sizeof(data_checked), nullptr);
hCheck = data_checked.hMod;
if (hCheck == (HINSTANCE)0x404040)
{
VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE);
return false;
}
else if (hCheck == (HINSTANCE)0x505050)
{
//Exception support failed!
}
Sleep(10);
}
BYTE* emptyBuffer = (BYTE*)malloc(1024 * 1024 * 20);
if (emptyBuffer == nullptr)
{
return false;
}
memset(emptyBuffer, 0, 1024 * 1024 * 20);
//CLEAR PE HEAD
if (ClearHeader)
{
WriteProcessMemory(hProc, pTargetBase, emptyBuffer, 0x1000, nullptr);
}
//END CLEAR PE HEAD
if (ClearNonNeededSections)
{
pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader);
for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader)
{
if (pSectionHeader->Misc.VirtualSize)
{
if ((SEHExceptionSupport ? 0 : strcmp((char*)pSectionHeader->Name, ".pdata") == 0) ||
strcmp((char*)pSectionHeader->Name, ".rsrc") == 0 ||
strcmp((char*)pSectionHeader->Name, ".reloc") == 0)
{
WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, emptyBuffer, pSectionHeader->Misc.VirtualSize, nullptr);
}
}
}
}
if (AdjustProtections)
{
pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader);
for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader)
{
if (pSectionHeader->Misc.VirtualSize)
{
DWORD old = 0;
DWORD newP = PAGE_READONLY;
if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) > 0)
{
newP = PAGE_READWRITE;
}
else if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) > 0)
{
newP = PAGE_EXECUTE_READ;
}
VirtualProtectEx(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSectionHeader->Misc.VirtualSize, newP, &old);
}
}
DWORD old = 0;
VirtualProtectEx(hProc, pTargetBase, IMAGE_FIRST_SECTION(pOldNtHeader)->VirtualAddress, PAGE_READONLY, &old);
}
WriteProcessMemory(hProc, pShellcode, emptyBuffer, 0x1000, nullptr);
VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE);
VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE);
return true;
}
//#pragma runtime_checks( "", off )
//#pragma optimize( "", off )
void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData)
{
if (!pData)
{
pData->hMod = (HINSTANCE)0x404040;
return;
}
BYTE* pBase = pData->pbase;
auto* pOpt = &reinterpret_cast<IMAGE_NT_HEADERS*>(pBase + reinterpret_cast<IMAGE_DOS_HEADER*>((uintptr_t)pBase)->e_lfanew)->OptionalHeader;
auto _LoadLibraryA = pData->pLoadLibraryA;
auto _GetProcAddress = pData->pGetProcAddress;
#ifdef _WIN64
auto _RtlAddFunctionTable = pData->pRtlAddFunctionTable;
#endif
auto _DllMain = reinterpret_cast<f_DLL_ENTRY_POINT>(pBase + pOpt->AddressOfEntryPoint);
BYTE* LocationDelta = pBase - pOpt->ImageBase;
if (LocationDelta) {
if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
{
auto* pRelocData = reinterpret_cast<IMAGE_BASE_RELOCATION*>(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
const auto* pRelocEnd = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<uintptr_t>(pRelocData) + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
while (pRelocData < pRelocEnd && pRelocData->SizeOfBlock)
{
UINT AmountOfEntries = (pRelocData->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
WORD* pRelativeInfo = reinterpret_cast<WORD*>(pRelocData + 1);
for (UINT i = 0; i != AmountOfEntries; ++i, ++pRelativeInfo)
{
if (RELOC_FLAG(*pRelativeInfo))
{
UINT_PTR* pPatch = reinterpret_cast<UINT_PTR*>(pBase + pRelocData->VirtualAddress + ((*pRelativeInfo) & 0xFFF));
*pPatch += reinterpret_cast<UINT_PTR>(LocationDelta);
}
}
pRelocData = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<BYTE*>(pRelocData) + pRelocData->SizeOfBlock);
}
}
}
if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
{
auto* pImportDescr = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (pImportDescr->Name)
{
char* szMod = reinterpret_cast<char*>(pBase + pImportDescr->Name);
HINSTANCE hDll = _LoadLibraryA(szMod);
ULONG_PTR* pThunkRef = reinterpret_cast<ULONG_PTR*>(pBase + pImportDescr->OriginalFirstThunk);
ULONG_PTR* pFuncRef = reinterpret_cast<ULONG_PTR*>(pBase + pImportDescr->FirstThunk);
if (!pThunkRef)
pThunkRef = pFuncRef;
for (; *pThunkRef; ++pThunkRef, ++pFuncRef)
{
if (IMAGE_SNAP_BY_ORDINAL(*pThunkRef))
{
*pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, reinterpret_cast<char*>(*pThunkRef & 0xFFFF));
}
else
{
auto* pImport = reinterpret_cast<IMAGE_IMPORT_BY_NAME*>(pBase + (*pThunkRef));
*pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, pImport->Name);
}
}
++pImportDescr;
}
}
if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
{
auto* pTLS = reinterpret_cast<IMAGE_TLS_DIRECTORY*>(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
auto* pCallback = reinterpret_cast<PIMAGE_TLS_CALLBACK*>(pTLS->AddressOfCallBacks);
for (; pCallback && *pCallback; ++pCallback)
(*pCallback)(pBase, DLL_PROCESS_ATTACH, nullptr);
}
bool ExceptionSupportFailed = false;
#ifdef _WIN64
if (pData->SEHSupport)
{
auto excep = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
if (excep.Size) {
if (!_RtlAddFunctionTable(
reinterpret_cast<IMAGE_RUNTIME_FUNCTION_ENTRY*>(pBase + excep.VirtualAddress),
excep.Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), (DWORD64)pBase))
{
ExceptionSupportFailed = true;
}
}
}
#endif
_DllMain(pBase, pData->fdwReasonParam, pData->reservedParam);
if (ExceptionSupportFailed)
pData->hMod = reinterpret_cast<HINSTANCE>(0x505050);
else
pData->hMod = reinterpret_cast<HINSTANCE>(pBase);
} 运行效果如下:
. m; C. v/ Z/ w9 k% B
' Z( b; ?! k9 `. |+ b, [
|