Skip to content

Instantly share code, notes, and snippets.

@SolomonSklash
Forked from rad9800/apihash.c
Created June 21, 2022 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SolomonSklash/ae53e0c04c822c57780618eb9d38a4e3 to your computer and use it in GitHub Desktop.
Save SolomonSklash/ae53e0c04c822c57780618eb9d38a4e3 to your computer and use it in GitHub Desktop.
Using macros and constexpr to make API hashing a bit more friendly
#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