| 一般而言要注入DLL到一个目标进程最简单的方法 就是先获取DLL文件路径,然后在目标进程分配内存空间将路径写入到目标进程,写入到目标进程后再调用CreateRemoteThread()/NtCreateThread()/RtlCreateUserThread()函数来运行LoadLibraryA/W函数调用自己的DLL,这种方法的缺陷也很明显那就是容易被游戏检测到,很容易被游戏拦截,比如CSGO最新版就已经有这个限制了。 
 想要突破CSGO的限制注入DLL进去,我们可以采用反射式注入的方法(也可以先恢复CSGOhook的api进行远程线程注入),那么什么是反射式注入呢?又有什么有点呢?反射式dll注入与常规dll注入类似,而不同的地方在于反射式dll注入技术自己实现了一个reflective loader()函数来代替LoadLibaryA()函数去加载dll,示意图如下图所示。蓝色的线表示与用常规dll注入相同的步骤,红框中的是reflective loader()函数行为,也是下面重点描述的地方。
 
 Reflective loader实现思路如下: 
 1.获得被注入进程未解析的dll的基地址。 
2.获得必要的dll句柄和函数为修复导入表做准备。 
3.分配一块新内存去取解析dll,并把pe头复制到新内存中和将各节复制到新内存中。 
4.修复导入表和重定向表。 
5.执行DllMain()函数。
 反射式DLL注入实现(ManualMap,手动解析PE并映射到目标进程...  
 核心代码如下:ManualMapInject.h
 | #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 | 
 #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", (DWORD)File.rdstate());
 //         File.close();
 //         CloseHandle(hProc);
 //         system("PAUSE");
 //         return -5;
 //     }
 //
 //     auto FileSize = File.tellg();
 //     if (FileSize < 0x1000)
 //     {
 //         printf("Filesize invalid.");
 //         File.close();
 //         CloseHandle(hProc);
 //         system("PAUSE");
 //         return -6;
 //     }
 //
 //     BYTE* pSrcData = new BYTE[(UINT_PTR)FileSize];
 //     if (!pSrcData)
 //     {
 //         printf("Can't allocate dll file.");
 //         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(pSrcData)->e_magic != 0x5A4D)//"MZ"
 {
 return false;
 }
 
 pOldNtHeader = reinterpret_cast(pSrcData + reinterpret_cast(pSrcData)->e_lfanew);
 pOldOptHeader = &pOldNtHeader->OptionalHeader;
 pOldFileHeader = &pOldNtHeader->FileHeader;
 
 if (pOldFileHeader->Machine != CURRENT_ARCH)
 {
 return false;
 }
 
 pTargetBase = reinterpret_cast(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(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(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(pBase + reinterpret_cast((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(pBase + pOpt->AddressOfEntryPoint);
 
 BYTE* LocationDelta = pBase - pOpt->ImageBase;
 if (LocationDelta) {
 if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
 {
 auto* pRelocData = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
 const auto* pRelocEnd = reinterpret_cast(reinterpret_cast(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(pRelocData + 1);
 
 for (UINT i = 0; i != AmountOfEntries; ++i, ++pRelativeInfo)
 {
 if (RELOC_FLAG(*pRelativeInfo))
 {
 UINT_PTR* pPatch = reinterpret_cast(pBase + pRelocData->VirtualAddress + ((*pRelativeInfo) & 0xFFF));
 *pPatch += reinterpret_cast(LocationDelta);
 }
 }
 pRelocData = reinterpret_cast(reinterpret_cast(pRelocData) + pRelocData->SizeOfBlock);
 }
 }
 }
 
 if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
 {
 auto* pImportDescr = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
 while (pImportDescr->Name)
 {
 char* szMod = reinterpret_cast(pBase + pImportDescr->Name);
 HINSTANCE hDll = _LoadLibraryA(szMod);
 
 ULONG_PTR* pThunkRef = reinterpret_cast(pBase + pImportDescr->OriginalFirstThunk);
 ULONG_PTR* pFuncRef = reinterpret_cast(pBase + pImportDescr->FirstThunk);
 
 if (!pThunkRef)
 pThunkRef = pFuncRef;
 
 for (; *pThunkRef; ++pThunkRef, ++pFuncRef)
 {
 if (IMAGE_SNAP_BY_ORDINAL(*pThunkRef))
 {
 *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, reinterpret_cast(*pThunkRef & 0xFFFF));
 }
 else
 {
 auto* pImport = reinterpret_cast(pBase + (*pThunkRef));
 *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, pImport->Name);
 }
 }
 ++pImportDescr;
 }
 }
 
 if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
 {
 auto* pTLS = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
 auto* pCallback = reinterpret_cast(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(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(0x505050);
 else
 pData->hMod = reinterpret_cast(pBase);
 }
 
 
 | 
 运行效果如下: 反射式DLL注入实现(ManualMap,手动解析PE并映射到目标进程...   反射式DLL注入实现(ManualMap,手动解析PE并映射到目标进程...  
 |