Description
Original source code: https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
#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;
}
Author: Unprotect / Target Platform: Windows
Description
In this code, the hash function is used to obfuscate the names of the APIs that are imported from the kernel32.dll library. The hashed names are then used to call the APIs using the GetProcAddress and LoadLibrary functions. When the code is disassembled, the actual names of the APIs will be hidden and replaced with the hashed values.
import ctypes
# Hash function to obfuscate the API names
def hash(str):
hash = 5381
for c in str:
hash = (hash * 33 + ord(c)) % 2**32
return hash
# Load the kernel32.dll library
hKernel32 = ctypes.windll.kernel32
# Use the hash function to obfuscate the names of the APIs
# we want to call from the library
lpLoadLibraryA = hKernel32.GetProcAddress(hKernel32, hash("LoadLibraryA"))
lpMessageBoxA = hKernel32.GetProcAddress(hKernel32, hash("MessageBoxA"))
# Call the APIs using the hashed names
hUser32 = ctypes.CFUNCTYPE(ctypes.c_void_p)(lpLoadLibraryA)("user32.dll")
ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint)(lpMessageBoxA)(None, "Hello World!", "API Hashing", 0)
# Clean up
hKernel32.FreeLibrary(hUser32)
Author: Unprotect / Target Platform: Windows