diff --git a/.gitignore b/.gitignore index 3a8542d..7b186d0 100644 --- a/.gitignore +++ b/.gitignore @@ -359,4 +359,6 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd +out/* +CMakeSettings.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b44c38d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.15) + +project(TheCruZMMap) + +set(SRC_ROOT "Manual Map Injector") + +include(CBuildKit) + +add_library_ns(thecruz manualmap STATIC ${SRC_ROOT}/injector.cpp) +target_include_dir_iface(thecruz-manualmap PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_ROOT} include) +install_target_and_headers(thecruz manualmap) +target_compile_features(thecruz-manualmap PUBLIC cxx_std_17) + +add_executable(injector ${SRC_ROOT}/main.cpp) +target_link_libraries(injector thecruz::manualmap) +target_compile_definitions(injector PRIVATE -DUNICODE -D_UNICODE) + +install(FILES + ${SRC_ROOT}/injector.h + DESTINATION include/TheCruZ) + +configure_file(TheCruZMMapConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/TheCruZMMapConfig.cmake + @ONLY) + +# Realize Installation of Configuration cmake file +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/TheCruZMMapConfig.cmake + DESTINATION lib/cmake/TheCruZ) \ No newline at end of file diff --git a/Manual Map Injector/injector.cpp b/Manual Map Injector/injector.cpp index 09a33e7..790b9fd 100644 --- a/Manual Map Injector/injector.cpp +++ b/Manual Map Injector/injector.cpp @@ -12,7 +12,35 @@ #define CURRENT_ARCH IMAGE_FILE_MACHINE_I386 #endif -bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader, bool ClearNonNeededSections, bool AdjustProtections, bool SEHExceptionSupport, DWORD fdwReason, LPVOID lpReserved) { +std::optional GetLdrpHandleTlsDataRVA() +{ + return 0x54590; +} + +std::optional GetModuleBaseAddress(DWORD processID, const char* moduleName) { + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processID); + if (hSnapshot == INVALID_HANDLE_VALUE) { + return std::nullopt; + } + + MODULEENTRY32 moduleEntry; + moduleEntry.dwSize = sizeof(MODULEENTRY32); + + if (Module32First(hSnapshot, &moduleEntry)) { + do { + if (strcmp(moduleEntry.szModule, moduleName) == 0) { + CloseHandle(hSnapshot); + return moduleEntry.hModule; // Return the base address + } + } while (Module32Next(hSnapshot, &moduleEntry)); + } + + CloseHandle(hSnapshot); + return std::nullopt; // Return nullopt if the module was not found +} + +std::optional ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader, bool ClearNonNeededSections, bool AdjustProtections, bool SEHExceptionSupport, DWORD fdwReason, LPVOID lpReserved) { + auto procNtdll = GetModuleBaseAddress(GetProcessId(hProc), "ntdll.dll"); IMAGE_NT_HEADERS* pOldNtHeader = nullptr; IMAGE_OPTIONAL_HEADER* pOldOptHeader = nullptr; IMAGE_FILE_HEADER* pOldFileHeader = nullptr; @@ -20,7 +48,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade if (reinterpret_cast(pSrcData)->e_magic != 0x5A4D) { //"MZ" ILog("Invalid file\n"); - return false; + return std::nullopt; } pOldNtHeader = reinterpret_cast(pSrcData + reinterpret_cast(pSrcData)->e_lfanew); @@ -29,7 +57,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade if (pOldFileHeader->Machine != CURRENT_ARCH) { ILog("Invalid platform\n"); - return false; + return std::nullopt; } ILog("File ok\n"); @@ -37,13 +65,47 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade pTargetBase = reinterpret_cast(VirtualAllocEx(hProc, nullptr, pOldOptHeader->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); if (!pTargetBase) { ILog("Target process memory allocation failed (ex) 0x%X\n", GetLastError()); - return false; + return std::nullopt; } + std::unique_ptr emptyBuffStrg = std::make_unique(1024 * 1024 * 20); + BYTE* emptyBuffer = emptyBuffStrg.get(); + if (emptyBuffer == nullptr) { + ILog("Unable to allocate memory\n"); + return std::nullopt; + } + memset(emptyBuffer, 0, 1024 * 1024 * 20); + DWORD oldp = 0; VirtualProtectEx(hProc, pTargetBase, pOldOptHeader->SizeOfImage, PAGE_EXECUTE_READWRITE, &oldp); - + MANUAL_MAPPING_DATA data{ 0 }; + data.pDummyLdr = (LDR_DATA_TABLE_ENTRY*)VirtualAllocEx(hProc, nullptr, sizeof(LDR_DATA_TABLE_ENTRY) * 4, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + WriteProcessMemory(hProc, data.pDummyLdr, emptyBuffer, sizeof(LDR_DATA_TABLE_ENTRY) * 4, nullptr); + data.pLdrpHandleTlsData = [&]() -> f_LdrpHandleTlsData { + if (!procNtdll) + return nullptr; + + auto rva = GetLdrpHandleTlsDataRVA(); + + if (!rva) + { + ILog("LdrpHandleTlsData Not found\n"); + return nullptr; + } + + auto r = (f_LdrpHandleTlsData)((uint64_t)(*procNtdll) + *rva); + + // Hash Like Integrity Check + if (*(uint16_t*)r != 0x8948 || + *(uint16_t*)((char*)r + 5) != 0x8948) + { + ILog("LdrpHandleTlsData Integrity Check Failed\n"); + return nullptr; + } + + return r; + }(); data.pLoadLibraryA = LoadLibraryA; data.pGetProcAddress = GetProcAddress; #ifdef _WIN64 @@ -61,7 +123,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade if (!WriteProcessMemory(hProc, pTargetBase, pSrcData, 0x1000, nullptr)) { //only first 0x1000 bytes for the header ILog("Can't write file header 0x%X\n", GetLastError()); VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); - return false; + return std::nullopt; } IMAGE_SECTION_HEADER* pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader); @@ -70,7 +132,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade if (!WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSrcData + pSectionHeader->PointerToRawData, pSectionHeader->SizeOfRawData, nullptr)) { ILog("Can't map sections: 0x%x\n", GetLastError()); VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); - return false; + return std::nullopt; } } } @@ -80,14 +142,14 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade if (!MappingDataAlloc) { ILog("Target process mapping allocation failed (ex) 0x%X\n", GetLastError()); VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); - return false; + return std::nullopt; } if (!WriteProcessMemory(hProc, MappingDataAlloc, &data, sizeof(MANUAL_MAPPING_DATA), nullptr)) { ILog("Can't write mapping 0x%X\n", GetLastError()); VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); - return false; + return std::nullopt; } //Shell code @@ -96,7 +158,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade ILog("Memory shellcode allocation failed (ex) 0x%X\n", GetLastError()); VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); - return false; + return std::nullopt; } if (!WriteProcessMemory(hProc, pShellcode, Shellcode, 0x1000, nullptr)) { @@ -104,7 +166,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); - return false; + return std::nullopt; } ILog("Mapped DLL at %p\n", pTargetBase); @@ -125,7 +187,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); - return false; + return std::nullopt; } CloseHandle(hThread); @@ -137,7 +199,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade GetExitCodeProcess(hProc, &exitcode); if (exitcode != STILL_ACTIVE) { ILog("Process crashed, exit code: %d\n", exitcode); - return false; + return std::nullopt; } MANUAL_MAPPING_DATA data_checked{ 0 }; @@ -149,7 +211,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); - return false; + return std::nullopt; } else if (hCheck == (HINSTANCE)0x505050) { ILog("WARNING: Exception support failed!\n"); @@ -158,13 +220,6 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade Sleep(10); } - BYTE* emptyBuffer = (BYTE*)malloc(1024 * 1024 * 20); - if (emptyBuffer == nullptr) { - ILog("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)) { @@ -225,7 +280,7 @@ bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeade ILog("WARNING: can't release mapping data memory\n"); } - return true; + return pTargetBase; } #define RELOC_FLAG32(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_HIGHLOW) @@ -300,6 +355,17 @@ void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData) { } } + if (pData->pLdrpHandleTlsData) + { + pData->pDummyLdr->DllBase = pBase; + pData->pLdrpHandleTlsData(pData->pDummyLdr); + } + + /*Todo + * Unlink from TLS list pData->pDummyLdr + * Finally release pData->pDummyLdr + */ + 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); diff --git a/Manual Map Injector/injector.h b/Manual Map Injector/injector.h index eb57755..4555cf5 100644 --- a/Manual Map Injector/injector.h +++ b/Manual Map Injector/injector.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include using f_LoadLibraryA = HINSTANCE(WINAPI*)(const char* lpLibFilename); using f_GetProcAddress = FARPROC(WINAPI*)(HMODULE hModule, LPCSTR lpProcName); @@ -15,10 +17,38 @@ using f_DLL_ENTRY_POINT = BOOL(WINAPI*)(void* hDll, DWORD dwReason, void* pReser using f_RtlAddFunctionTable = BOOL(WINAPIV*)(PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount, DWORD64 BaseAddress); #endif +struct UNICODE_STR +{ + USHORT Length; + USHORT MaximumLength; + PWSTR pBuffer; +}; + +struct LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STR FullDllName; + UNICODE_STR BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +}; + +using f_LdrpHandleTlsData = DWORD(*)(LDR_DATA_TABLE_ENTRY*); + struct MANUAL_MAPPING_DATA { f_LoadLibraryA pLoadLibraryA; f_GetProcAddress pGetProcAddress; + f_LdrpHandleTlsData pLdrpHandleTlsData; + LDR_DATA_TABLE_ENTRY* pDummyLdr; #ifdef _WIN64 f_RtlAddFunctionTable pRtlAddFunctionTable; #endif @@ -31,5 +61,5 @@ struct MANUAL_MAPPING_DATA //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); +std::optional 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); \ No newline at end of file diff --git a/TheCruZMMapConfig.cmake.in b/TheCruZMMapConfig.cmake.in new file mode 100644 index 0000000..08ab331 --- /dev/null +++ b/TheCruZMMapConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ # Init + +include(CMakeFindDependencyMacro) + +find_dependency(MSPDBX) + +include(${CMAKE_CURRENT_LIST_DIR}/thecruz-manualmap-targets.cmake) \ No newline at end of file