From b5b403f5dc4480f5e70af77af6bc353979b319af Mon Sep 17 00:00:00 2001 From: Joaquin <67109235+Taiga74164@users.noreply.github.com> Date: Sat, 11 May 2024 08:45:56 -0600 Subject: [PATCH] fix: #90 --- .gitignore | 5 - injector/src/manual-map.cpp | 438 ++++++++++++++++++++++++++++++++++++ injector/src/manual-map.h | 7 + 3 files changed, 445 insertions(+), 5 deletions(-) create mode 100644 injector/src/manual-map.cpp create mode 100644 injector/src/manual-map.h diff --git a/.gitignore b/.gitignore index 628b310..c9778c3 100644 --- a/.gitignore +++ b/.gitignore @@ -365,8 +365,3 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd - -PostBuildEvent.cmd - -manual-map.h -manual-map.cpp \ No newline at end of file diff --git a/injector/src/manual-map.cpp b/injector/src/manual-map.cpp new file mode 100644 index 0000000..03031b6 --- /dev/null +++ b/injector/src/manual-map.cpp @@ -0,0 +1,438 @@ +#include "manual-map.h" + +#include +#include +#include "util.h" + +#if defined(DISABLE_OUTPUT) +#define ILog(data, ...) +#define IPrintError(text, ...) +#else +#define ILog(text, ...) printf(text, __VA_ARGS__) +#define ILogError(text, ...) ILog(text, __VA_ARGS__); std::cout << "Error: " << util::GetLastErrorAsString() << std::endl +#endif + +#ifdef _WIN64 +#define CURRENT_ARCH IMAGE_FILE_MACHINE_AMD64 +#else +#define CURRENT_ARCH IMAGE_FILE_MACHINE_I386 +#endif + +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; +}; + + +bool ManualMapDLL(HANDLE hProc, const std::string& filepath) +{ + std::ifstream file(filepath, std::ios::in | std::ios::binary | std::ios::ate); + if (!file.is_open()) + { + std::cout << "Error while reading DLL file!" << std::endl; + return false; + } + + std::streampos size = file.tellg(); + auto memblock = new char[size]; + file.seekg(0, std::ios::beg); + file.read(memblock, size); + file.close(); + + BYTE* fileContent = (BYTE*)memblock; + + // Manual map injection will help us to be like a assassin + bool result = ManualMapDLL(hProc, fileContent, size, true, true, false, false, DLL_PROCESS_ATTACH); + + delete[] memblock; + + return result; +} + +void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData); + +bool ManualMapDLL(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader, bool ClearNonNeededSections, bool AdjustProtections, bool SEHExceptionSupport, DWORD fdwReason) +{ + 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" + ILog("[DLL injection] Invalid file\n"); + return false; + } + + pOldNtHeader = reinterpret_cast(pSrcData + reinterpret_cast(pSrcData)->e_lfanew); + pOldOptHeader = &pOldNtHeader->OptionalHeader; + pOldFileHeader = &pOldNtHeader->FileHeader; + + if (pOldFileHeader->Machine != CURRENT_ARCH) + { + ILog("[DLL injection] Invalid platform.\n"); + return false; + } + + ILog("[DLL injection] File ok\n"); + + pTargetBase = reinterpret_cast(VirtualAllocEx(hProc, nullptr, pOldOptHeader->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + if (!pTargetBase) + { + ILogError("[DLL injection] Target process memory allocation failed (ex)\n"); + 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.SEHSupport = SEHExceptionSupport; + + //File header + if (!WriteProcessMemory(hProc, pTargetBase, pSrcData, 0x1000, nullptr)) + { //only first 0x1000 bytes for the header + ILogError("[DLL injection] Can't write file header.\n"); + + 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)) + { + ILogError("[DLL injection] Can't map sections.\n"); + 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) + { + ILogError("[DLL injection] Target process mapping allocation failed (ex).\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + return false; + } + + if (!WriteProcessMemory(hProc, MappingDataAlloc, &data, sizeof(MANUAL_MAPPING_DATA), nullptr)) + { + ILogError("[DLL injection] Can't write mapping.\n"); + 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) + { + ILogError("[DLL injection] Memory shellcode allocation failed (ex).\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + return false; + } + + if (!WriteProcessMemory(hProc, pShellcode, Shellcode, 0x1000, nullptr)) + { + ILogError("[DLL injection] Can't write shellcode.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); + return false; + } + + ILog("[DLL injection] Mapped DLL at %p\n", pTargetBase); + ILog("[DLL injection] Mapping info at %p\n", MappingDataAlloc); + ILog("[DLL injection] Shell code at %p\n", pShellcode); + + ILog("[DLL injection] Data allocated\n"); + +#ifdef _DEBUG + ILog("[DLL injection] My shellcode pointer %p\n", Shellcode); + ILog("[DLL injection] Target point %p\n", pShellcode); +#endif + + HANDLE hThread = CreateRemoteThread(hProc, nullptr, 0, reinterpret_cast(pShellcode), MappingDataAlloc, 0, nullptr); + if (!hThread) + { + ILogError("[DLL injection] Thread creation failed.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); + return false; + } + CloseHandle(hThread); + + ILog("[DLL injection] Thread created at: %p, waiting for return...\n", pShellcode); + + HINSTANCE hCheck = NULL; + while (!hCheck) + { + DWORD exitcode = 0; + GetExitCodeProcess(hProc, &exitcode); + if (exitcode != STILL_ACTIVE) + { + ILog("[DLL injection] Process crashed, exit code: 0x%x\n", exitcode); + 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) + { + ILog("[DLL injection] Wrong mapping ptr.\n"); + 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) + { + ILog("[DLL injection] WARNING: Exception support failed!\n"); + } + + Sleep(10); + } + + BYTE* emptyBuffer = (BYTE*)malloc(1024 * 1024 * 20); + if (emptyBuffer == nullptr) + { + ILog("[DLL injection] Unable to allocate memory\n"); + return false; + } + memset(emptyBuffer, 0, 1024 * 1024 * 20); + + //CLEAR PE HEAD + if (ClearHeader) + { + if (!WriteProcessMemory(hProc, pTargetBase, emptyBuffer, 0x1000, nullptr)) + { + ILogError("[DLL injection] WARNING!: Can't clear HEADER\n"); + } + } + //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) + { + ILog("[DLL injection] Processing %s removal\n", pSectionHeader->Name); + if (!WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, emptyBuffer, pSectionHeader->Misc.VirtualSize, nullptr)) + { + ILogError("[DLL injection] Can't clear section %s.\n", pSectionHeader->Name); + } + } + } + } + } + + 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_READONLY; + } + else if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) > 0) + { + newP = PAGE_READONLY; + } + if (VirtualProtectEx(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSectionHeader->Misc.VirtualSize, newP, &old)) + { + ILog("[DLL injection] Section %s set as %lX\n", (char*)pSectionHeader->Name, newP); + } + else + { + ILog("[DLL injection] FAIL: section %s not set as %lX\n", (char*)pSectionHeader->Name, newP); + } + } + } + DWORD old = 0; + VirtualProtectEx(hProc, pTargetBase, IMAGE_FIRST_SECTION(pOldNtHeader)->VirtualAddress, PAGE_READONLY, &old); + } + + if (!WriteProcessMemory(hProc, pShellcode, emptyBuffer, 0x1000, nullptr)) + { + ILog("[DLL injection] WARNING: Can't clear shellcode\n"); + } + if (!VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE)) + { + ILog("[DLL injection] WARNING: can't release shell code memory\n"); + } + if (!VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE)) + { + ILog("[DLL injection] WARNING: can't release mapping data memory\n"); + } + + return true; +} + +#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 + +#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, nullptr); + + if (ExceptionSupportFailed) + pData->hMod = reinterpret_cast(0x505050); + else + pData->hMod = reinterpret_cast(pBase); +} diff --git a/injector/src/manual-map.h b/injector/src/manual-map.h new file mode 100644 index 0000000..599f546 --- /dev/null +++ b/injector/src/manual-map.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +bool ManualMapDLL(HANDLE hProc, const std::string& filepath); +bool ManualMapDLL(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader = false, bool ClearNonNeededSections = false, bool AdjustProtections = true, bool SEHExceptionSupport = false, DWORD fdwReason = DLL_PROCESS_ATTACH); \ No newline at end of file