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.
Custom GetProcAddress and GetModuleHandle parsing forwarded export
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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment