Skip to content

Instantly share code, notes, and snippets.

@tautologicc
Forked from rad9800/apihash.c
Created October 4, 2023 00:47
Show Gist options
  • Save tautologicc/4792b48402e1e1994dfadc3b8d7b71d1 to your computer and use it in GitHub Desktop.
Save tautologicc/4792b48402e1e1994dfadc3b8d7b71d1 to your computer and use it in GitHub Desktop.

Revisions

  1. @rad9800 rad9800 revised this gist Jun 21, 2022. 1 changed file with 107 additions and 36 deletions.
    143 changes: 107 additions & 36 deletions apihash.c
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,15 @@
    #include <Windows.h>
    #include <winternl.h>
    #include <stdio.h>

    /* Define the overloaded hashing function you want to use */
    #pragma comment(linker, "/ENTRY:entry")

    // Define hashing algorithm to use
    #define HASHALGO HashStringDjb2
    // Define how large you'd like cache to be
    #define CACHE 50


    #pragma region hashes
    // https://github.com/vxunderground/VX-API/blob/main/VX-API/MalwareStrings.h
    #pragma region HashStringDjb2
    constexpr DWORD HashStringDjb2(const char* String)
    @@ -61,43 +66,57 @@ constexpr ULONG HashStringFowlerNollVoVariant1a(const wchar_t* String)
    }
    #pragma endregion

    #pragma endregion

    void* GetProcAddrH(UINT moduleHash, UINT funcHash);

    void InitModules();
    #pragma region macros

    #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, ...) \
    #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 ) , \
    #define API( DLL, FUNCNAME ) ( ( CONCAT( type, FUNCNAME ))GetProcAddrH( CONCAT( hash, DLL ) ,\
    CONCAT( hash,FUNCNAME ) ) )


    #pragma region dlls
    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)
    #pragma endregion

    hashFunc(CloseHandle, BOOL, HANDLE);
    #pragma region functions
    // Example functions funcName , rettype , parameters
    //hashFunc(NtWriteVirtualMemory, NTSTATUS, HANDLE, PVOID, PVOID, ULONG, PULONG)


    hashFunc(VirtualProtect, BOOL, LPVOID, SIZE_T, DWORD, PDWORD)
    hashFunc(VirtualAlloc, LPVOID, LPVOID, SIZE_T, DWORD, DWORD);
    hashFunc(CreateProcessA, BOOL, LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
    hashFunc(LoadLibraryA, HMODULE, LPCSTR);
    hashFunc(LoadLibraryW, HMODULE, LPCWSTR);
    hashFunc(CloseHandle, BOOL, HANDLE);
    #pragma endregion

    #pragma endregion


    struct ModuleHash
    #pragma function(memset)
    void* memset(void* dest, int c, size_t count);
    __forceinline char Upper(char c);
    void* GetProcAddrH(UINT moduleHash, UINT funcHash);
    void InitModules();


    struct HashStruct
    {
    UINT moduleHash;
    PVOID module;
    UINT Hash;
    PVOID addr;
    };

    ModuleHash ModuleHashes[] =
    HashStruct ModuleHashes[] =
    {
    { hashNTDLL , nullptr },
    { hashKERNEL32 , nullptr },
    @@ -106,34 +125,44 @@ ModuleHash ModuleHashes[] =
    { hashUCRTBASE , nullptr },
    };

    int main()
    #ifdef CACHE
    HashStruct HashCache[CACHE];
    DWORD hashPointer;
    #endif

    int entry()
    {
    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);

    STARTUPINFOA si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    API(KERNEL32, CreateProcessA)(nullptr, (LPSTR)R"(c:\windows\system32\calc.exe)", nullptr, nullptr, 0, 0, nullptr, nullptr, &si, &pi);
    API(KERNEL32, CloseHandle)(pi.hProcess);
    API(KERNEL32, CloseHandle)(pi.hThread);
    return 0;
    }

    void* GetProcAddrH(UINT moduleHash, UINT funcHash)
    {
    void* base = nullptr;
    for (auto i : ModuleHashes) {
    if (i.moduleHash == moduleHash) {
    base = i.module;
    if (i.Hash == moduleHash) {
    base = i.addr;
    }
    }
    if (base == nullptr) {
    return nullptr;
    }


    #ifdef CACHE
    for (auto i = 0; i < CACHE; i++)
    {
    if (funcHash == HashCache[i].Hash) {
    return HashCache[i].addr;
    }
    }
    #endif

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)base + dos->e_lfanew);

    @@ -149,6 +178,12 @@ void* GetProcAddrH(UINT moduleHash, UINT funcHash)
    auto name = (LPSTR)((PBYTE)base + names[i]);
    if (HASHALGO(name) == funcHash) {
    auto function = ((PBYTE)base + functions[ordinals[i]]);
    #ifdef CACHE
    // Cache result
    HashCache[hashPointer % CACHE].addr = function;
    HashCache[hashPointer % CACHE].Hash = funcHash;
    hashPointer = (hashPointer + 1) % CACHE;
    #endif
    return function;
    }
    }
    @@ -172,12 +207,48 @@ void InitModules()
    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;
    char name[64];
    if (basename->Length < sizeof(name) - 1)
    {
    int i = 0;
    while (basename->Buffer[i] && i < sizeof(name) - 1)
    {
    name[i] = Upper((char)basename->Buffer[i]); // can never be sure so uppercase
    i++;
    }
    name[i] = 0;
    UINT hash = HASHALGO(name);

    for (auto& i : ModuleHashes) {
    if (i.Hash == hash) {
    i.addr = entry->DllBase;
    }
    }
    }
    next = next->Flink;
    }
    #ifdef CACHE
    RtlSecureZeroMemory(HashCache, sizeof(HashCache));
    hashPointer = 0;
    #endif

    }

    char Upper(char c)
    {
    if (c >= 'a' && c <= 'z') {
    return c - 'a' + 'A';
    }

    return c;
    }

    void* memset(void* dest, int c, size_t count)
    {
    char* bytes = (char*)dest;
    while (count--)
    {
    *bytes++ = (char)c;
    }
    return dest;
    }
  2. @rad9800 rad9800 revised this gist Jun 16, 2022. 1 changed file with 13 additions and 5 deletions.
    18 changes: 13 additions & 5 deletions apihash.c
    Original file line number Diff line number Diff line change
    @@ -87,6 +87,9 @@ dllhash(UCRTBASE, L"ucrtbase.dll")
    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
    {
    @@ -106,11 +109,16 @@ ModuleHash ModuleHashes[] =
    int main()
    {
    InitModules();

    printf("Hashed NtWriteVirtualMemory: 0x%p\n", API(NTDLL, NtWriteVirtualMemory));
    printf("Manual NtWriteVirtualMemory: 0x%p\n", GetProcAddress(GetModuleHandle(L"ntdll"), "NtWriteVirtualMemory"));
    printf("Hashed VirtualProtect: 0x%p\n", API(KERNEL32, VirtualProtect));
    printf("Manual VirtualProtect: 0x%p\n", GetProcAddress(GetModuleHandle(L"kernel32"), "VirtualProtect"));
    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);

    }

  3. @rad9800 rad9800 created this gist Jun 16, 2022.
    175 changes: 175 additions & 0 deletions apihash.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,175 @@
    #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)


    struct ModuleHash
    {
    UINT moduleHash;
    PVOID module;
    };

    ModuleHash ModuleHashes[] =
    {
    { hashNTDLL , nullptr },
    { hashKERNEL32 , nullptr },
    { hashKERNEL32 , nullptr },
    { hashKERNELBASE , nullptr },
    { hashUCRTBASE , nullptr },
    };

    int main()
    {
    InitModules();

    printf("Hashed NtWriteVirtualMemory: 0x%p\n", API(NTDLL, NtWriteVirtualMemory));
    printf("Manual NtWriteVirtualMemory: 0x%p\n", GetProcAddress(GetModuleHandle(L"ntdll"), "NtWriteVirtualMemory"));
    printf("Hashed VirtualProtect: 0x%p\n", API(KERNEL32, VirtualProtect));
    printf("Manual VirtualProtect: 0x%p\n", GetProcAddress(GetModuleHandle(L"kernel32"), "VirtualProtect"));

    }

    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;
    }
    }