-
-
Save SolomonSklash/ae53e0c04c822c57780618eb9d38a4e3 to your computer and use it in GitHub Desktop.
Using macros and constexpr to make API hashing a bit more friendly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <winternl.h> | |
#include <stdio.h> | |
/* Define the overloaded hashing function you want to use */ | |
#define HASHALGO HashStringDjb2 | |
// https://github.com/vxunderground/VX-API/blob/main/VX-API/MalwareStrings.h | |
#pragma region HashStringDjb2 | |
constexpr DWORD HashStringDjb2(const char* String) | |
{ | |
ULONG Hash = 5381; | |
INT c = 0; | |
while ((c = *String++)) { | |
Hash = ((Hash << 5) + Hash) + c; | |
} | |
return Hash; | |
} | |
constexpr DWORD HashStringDjb2(const wchar_t* String) | |
{ | |
ULONG Hash = 5381; | |
INT c = 0; | |
while ((c = *String++)) { | |
Hash = ((Hash << 5) + Hash) + c; | |
} | |
return Hash; | |
} | |
#pragma endregion | |
#pragma region HashStringFowlerNollVoVariant1a | |
constexpr ULONG HashStringFowlerNollVoVariant1a(const char* String) | |
{ | |
ULONG Hash = 0x811c9dc5; | |
while (*String) | |
{ | |
Hash ^= (UCHAR)*String++; | |
Hash *= 0x01000193; | |
} | |
return Hash; | |
} | |
constexpr ULONG HashStringFowlerNollVoVariant1a(const wchar_t* String) | |
{ | |
ULONG Hash = 0x811c9dc5; | |
while (*String) | |
{ | |
Hash ^= (UCHAR)*String++; | |
Hash *= 0x01000193; | |
} | |
return Hash; | |
} | |
#pragma endregion | |
void* GetProcAddrH(UINT moduleHash, UINT funcHash); | |
void InitModules(); | |
#define TOKENIZE( x ) #x | |
#define TOKENIZEW( x ) L#x | |
#define CONCAT( x , y) x##y | |
#define hash( VAL ) constexpr auto CONCAT( hash, VAL ) = HASHALGO( TOKENIZE( VAL ) ); | |
#define dllhash(DLL, VAL ) constexpr auto CONCAT( hash, DLL ) = HASHALGO( VAL ); | |
#define hashFunc( FUNCNAME , RETTYPE, ...) \ | |
hash( FUNCNAME ) typedef RETTYPE( WINAPI* CONCAT( type, FUNCNAME ) )( __VA_ARGS__ ); | |
#define API( DLL, FUNCNAME ) ( ( CONCAT( type, FUNCNAME ))GetProcAddrH( CONCAT( hash, DLL ) , \ | |
CONCAT( hash,FUNCNAME ) ) ) | |
dllhash(KERNEL32, L"KERNEL32.DLL") | |
dllhash(NTDLL, L"ntdll.dll") | |
dllhash(KERNELBASE, L"KERNELBASE.dll") | |
dllhash(UCRTBASE, L"ucrtbase.dll") | |
/* funcName , rettype , parameters */ | |
hashFunc(NtWriteVirtualMemory, NTSTATUS, HANDLE, PVOID, PVOID, ULONG, PULONG) | |
hashFunc(VirtualProtect, BOOL, LPVOID, SIZE_T, DWORD, PDWORD) | |
hashFunc(CloseHandle, BOOL, HANDLE); | |
hashFunc(CreateProcessA, BOOL, LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); | |
struct ModuleHash | |
{ | |
UINT moduleHash; | |
PVOID module; | |
}; | |
ModuleHash ModuleHashes[] = | |
{ | |
{ hashNTDLL , nullptr }, | |
{ hashKERNEL32 , nullptr }, | |
{ hashKERNEL32 , nullptr }, | |
{ hashKERNELBASE , nullptr }, | |
{ hashUCRTBASE , nullptr }, | |
}; | |
int main() | |
{ | |
InitModules(); | |
do | |
{ | |
STARTUPINFOA si = { sizeof(si) }; | |
PROCESS_INFORMATION pi; | |
if (API(KERNEL32, CreateProcessA)(nullptr, (LPSTR)R"(c:\windows\system32\calc.exe)", nullptr, nullptr, 0, 0, nullptr, nullptr, &si, &pi) == 0) { | |
break; | |
} | |
API(KERNEL32, CloseHandle)(pi.hProcess); | |
API(KERNEL32, CloseHandle)(pi.hThread); | |
} while (FALSE); | |
} | |
void* GetProcAddrH(UINT moduleHash, UINT funcHash) | |
{ | |
void* base = nullptr; | |
for (auto i : ModuleHashes) { | |
if (i.moduleHash == moduleHash) { | |
base = i.module; | |
} | |
} | |
if (base == nullptr) { | |
return nullptr; | |
} | |
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base; | |
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)base + dos->e_lfanew); | |
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); | |
if (exports->AddressOfNames != 0) | |
{ | |
auto ordinals = (PWORD)((PBYTE)base + exports->AddressOfNameOrdinals); | |
auto names = (PDWORD)((PBYTE)base + exports->AddressOfNames); | |
auto functions = (PDWORD)((PBYTE)base + exports->AddressOfFunctions); | |
for (auto i = 0; i < exports->NumberOfNames; i++) { | |
auto name = (LPSTR)((PBYTE)base + names[i]); | |
if (HASHALGO(name) == funcHash) { | |
auto function = ((PBYTE)base + functions[ordinals[i]]); | |
return function; | |
} | |
} | |
} | |
return nullptr; | |
} | |
void InitModules() | |
{ | |
PEB* peb = NtCurrentTeb()->ProcessEnvironmentBlock; | |
LIST_ENTRY* head = &peb->Ldr->InMemoryOrderModuleList; | |
LIST_ENTRY* next = head->Flink; | |
while (next != head) | |
{ | |
LDR_DATA_TABLE_ENTRY* entry = (LDR_DATA_TABLE_ENTRY*)((PBYTE)next - offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)); | |
UNICODE_STRING* fullname = &entry->FullDllName; | |
UNICODE_STRING* basename = (UNICODE_STRING*)((PBYTE)fullname + sizeof(UNICODE_STRING)); | |
UINT hash = HASHALGO(basename->Buffer); | |
for (auto& i : ModuleHashes) { | |
if (i.moduleHash == hash) { | |
i.module = entry->DllBase; | |
} | |
} | |
next = next->Flink; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment