查看原文
其他

反射式DLL注入实现

_DriverEntry 看雪学苑 2022-07-01


本文为看雪论坛优秀文章
看雪论坛作者ID:_DriverEntry


一般而言要注入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()函数。
核心代码如下:
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 _WIN64using 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 /EHcbool 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\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);}
运行效果如下:






看雪ID:_DriverEntry

https://bbs.pediy.com/user-home-944747.htm

*本文由看雪论坛 _DriverEntry 原创,转载请注明来自看雪社区



# 往期推荐

1.angr符号变量转LLVM IR

2.记录一次对某CMS漏洞挖掘

3.Android APP漏洞之战—验证码漏洞挖掘详解

4.CTF 中 glibc堆利用及 IO_FILE 总结

5.记一次新型变种QakBot木马分析

6.[VNCTF2022]gocalc0复现






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存