Skip to content

Instantly share code, notes, and snippets.

@OtterHacker
Created November 27, 2023 22:51
Show Gist options
  • Save OtterHacker/8abaf54694ef27b9e3d38dfe57f13bd3 to your computer and use it in GitHub Desktop.
Save OtterHacker/8abaf54694ef27b9e3d38dfe57f13bd3 to your computer and use it in GitHub Desktop.

Revisions

  1. OtterHacker created this gist Nov 27, 2023.
    98 changes: 98 additions & 0 deletions get_proc_address.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    unsigned long hash_string(void* buffer, unsigned long size, char* extension){
    unsigned char current = 0;
    unsigned long hash = 0;
    unsigned char* currentChar = NULL;
    hash = 1337;
    currentChar = (void*)buffer;
    hash++;

    while(1){
    current = *currentChar;
    if (!size) {
    if (!*currentChar) {break;}
    }
    else {
    if ((ULONG)(currentChar - (PUCHAR)buffer) >= size) { break; }
    if (!*currentChar) { ++currentChar; continue; }
    }
    if (current >= 'a'){current -= 0x20;}
    hash = ((hash << 5) + hash) + current;
    ++currentChar;
    };

    if(extension) {
    currentChar = (void *)extension;
    while (1) {
    current = *currentChar;
    if (!*currentChar) { break; }

    if (current >= 'a') { current -= 0x20; }
    hash = ((hash << 5) + hash) + current;
    ++currentChar;
    };
    }
    return hash;
    };

    HMODULE get_module_handle(unsigned long module_hash, unsigned long* image_size) {
    PPEB peb = (PPEB)__readgsqword(0x60);
    PLIST_ENTRY hdr = NULL;
    PLIST_ENTRY ent = NULL;
    PLDR_DATA_TABLE_ENTRY ldr = NULL;
    hdr = &(peb->Ldr->InLoadOrderModuleList);
    ent = hdr->Flink;
    for (; hdr != ent; ent = ent->Flink){
    ldr = (void*)ent;
    if (hash_string(ldr->BaseDllName.Buffer, ldr->BaseDllName.Length, NULL) == module_hash){
    if (image_size != NULL) { *image_size = ldr->SizeOfImage; }
    return ldr->DllBase;
    }
    }
    return NULL;
    }

    PVOID get_proc_address(HMODULE moduleHandle, unsigned long hash) {
    PIMAGE_DOS_HEADER dosHeaders = (PVOID)moduleHandle;
    PIMAGE_NT_HEADERS ntHeaders = (PVOID)((ULONG_PTR)dosHeaders + dosHeaders->e_lfanew);
    PIMAGE_DATA_DIRECTORY dataDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    ULONG Idx = 0;
    if (dataDirectory->VirtualAddress){
    PIMAGE_EXPORT_DIRECTORY exportsDirectory = (PVOID)((ULONG_PTR)dosHeaders + dataDirectory->VirtualAddress);
    PUINT32 addressOfNames = (PVOID)((ULONG_PTR)dosHeaders + exportsDirectory->AddressOfNames);
    PUINT32 addressOfFunctions = (PVOID)((ULONG_PTR)dosHeaders + exportsDirectory->AddressOfFunctions);
    PUINT16 addressOfOrdinals = (PVOID)((ULONG_PTR)dosHeaders + exportsDirectory->AddressOfNameOrdinals);

    for (Idx = 0; Idx < exportsDirectory->NumberOfNames; ++Idx){
    if (hash_string((PVOID)((ULONG_PTR)dosHeaders + addressOfNames[Idx]), 0, NULL) == hash){
    // Forwarded export
    if((addressOfFunctions[addressOfOrdinals[Idx]] >=dataDirectory->VirtualAddress) && (addressOfFunctions[addressOfOrdinals[Idx]] < dataDirectory->VirtualAddress + dataDirectory->Size)){
    // Get the name of the forwarder : DLL.FUNCTION
    char* forwarded_dll = (char*)((ULONG_PTR)dosHeaders + addressOfFunctions[addressOfOrdinals[Idx]]);
    // Retrieve the function name with a simple split on '.'
    char* export_name = forwarded_dll;
    while(*export_name != '.'){
    if(*export_name == '\0'){
    return NULL;
    }
    export_name++;
    }
    size_t dll_name_length = export_name - forwarded_dll;
    export_name++;
    // Compute the hashed name of the DLL
    ULONG dll_hash = hash_string(forwarded_dll, dll_name_length, (char[]){'.','d','l','l','\0'});
    ULONG export_hash = hash_string(export_name, 0, NULL);

    // Get the module handle
    HMODULE export_dll_module = get_module_handle(dll_hash, NULL);

    // Resolve the forwarder and return the value
    return get_proc_address(export_dll_module, export_hash);

    }
    return (PVOID)((ULONG_PTR)dosHeaders + addressOfFunctions[addressOfOrdinals[Idx]]);
    }
    }
    }

    return NULL;
    }