Windows C++ / API Obfuscation
Author | Unprotect |
Platform | Windows |
Language | C++ |
Technique | API Obfuscation |
Description:
Original source code: https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
Code
#include <iostream>
#include <Windows.h>
DWORD getHashFromString(char *string)
{
size_t stringLength = strnlen_s(string, 50);
DWORD hash = 0x35;
for (size_t i = 0; i < stringLength; i++)
{
hash += (hash * 0xab10f29f + string[i]) & 0xffffff;
}
// printf("%s: 0x00%x\n", string, hash);
return hash;
}
PDWORD getFunctionAddressByHash(char *library, DWORD hash)
{
PDWORD functionAddress = (PDWORD)0;
// Get base address of the module in which our exported function of interest resides (kernel32 in the case of CreateThread)
HMODULE libraryBase = LoadLibraryA(library);
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)libraryBase;
PIMAGE_NT_HEADERS imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)libraryBase + dosHeader->e_lfanew);
DWORD_PTR exportDirectoryRVA = imageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY imageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)libraryBase + exportDirectoryRVA);
// Get RVAs to exported function related information
PDWORD addresOfFunctionsRVA = (PDWORD)((DWORD_PTR)libraryBase + imageExportDirectory->AddressOfFunctions);
PDWORD addressOfNamesRVA = (PDWORD)((DWORD_PTR)libraryBase + imageExportDirectory->AddressOfNames);
PWORD addressOfNameOrdinalsRVA = (PWORD)((DWORD_PTR)libraryBase + imageExportDirectory->AddressOfNameOrdinals);
// Iterate through exported functions, calculate their hashes and check if any of them match our hash of 0x00544e304 (CreateThread)
// If yes, get its virtual memory address (this is where CreateThread function resides in memory of our process)
for (DWORD i = 0; i < imageExportDirectory->NumberOfFunctions; i++)
{
DWORD functionNameRVA = addressOfNamesRVA[i];
DWORD_PTR functionNameVA = (DWORD_PTR)libraryBase + functionNameRVA;
char* functionName = (char*)functionNameVA;
DWORD_PTR functionAddressRVA = 0;
// Calculate hash for this exported function
DWORD functionNameHash = getHashFromString(functionName);
// If hash for CreateThread is found, resolve the function address
if (functionNameHash == hash)
{
functionAddressRVA = addresOfFunctionsRVA[addressOfNameOrdinalsRVA[i]];
functionAddress = (PDWORD)((DWORD_PTR)libraryBase + functionAddressRVA);
printf("%s : 0x%x : %p\n", functionName, functionNameHash, functionAddress);
return functionAddress;
}
}
}
// Define CreateThread function prototype
using customCreateThread = HANDLE(NTAPI*)(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
__drv_aliasesMem LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
int main()
{
// Resolve CreateThread address by hash
PDWORD functionAddress = getFunctionAddressByHash((char *)"kernel32", 0x00544e304);
// Point CreateThread function pointer to the CreateThread virtual address resolved by its hash
customCreateThread CreateThread = (customCreateThread)functionAddress;
DWORD tid = 0;
// Call CreateThread
HANDLE th = CreateThread(NULL, NULL, NULL, NULL, NULL, &tid);
return 1;
}
Created
June 19, 2022
Last Revised
April 22, 2024