internal static void* MemoryGetProcAddress(MEMORYMODULE mod, byte* name) { MEMORYMODULE module = mod; byte* codeBase = module.codeBase; uint idx = 0; IMAGE_EXPORT_DIRECTORY* exports; IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) // no export table found return null; exports = (IMAGE_EXPORT_DIRECTORY*)(codeBase + directory->VirtualAddress); if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) // DLL doesn't export anything return null; if (HIWORD(name) == 0) { // load function by ordinal value if (LOWORD(name) < exports->Base) return null; idx = LOWORD(name) - exports->Base; } else if (exports->NumberOfNames == 0) return null; else { ExportNameEntry found; // Lazily build name table and sort it by names if (module.nameExportsTable == null) { uint i; uint* nameRef = (uint*)(codeBase + exports->AddressOfNames); ushort* ordinal = (ushort*)(codeBase + exports->AddressOfNameOrdinals); ExportNameEntry[] entry = new ExportNameEntry[exports->NumberOfNames]; module.nameExportsTable = entry; for (i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++) entry[i] = new ExportNameEntry { name = codeBase + (*nameRef), idx = *ordinal }; Array.Sort(module.nameExportsTable, _compare); } // search function name in list of exported names with binary search ExportNameEntry tmp = new ExportNameEntry { name = name }; int foundIndex = Array.BinarySearch(module.nameExportsTable, tmp, tmp); found = foundIndex < 0 ? null : module.nameExportsTable[foundIndex]; if (found == null) // exported symbol not found return null; idx = found.idx; } if (idx > exports->NumberOfFunctions) // name <. ordinal number don't match return null; // AddressOfFunctions contains the RVAs to the "real" functions return (void*)(codeBase + (*(uint*)(codeBase + exports->AddressOfFunctions + (idx * 4)))); }
private static int _compare(ExportNameEntry a, ExportNameEntry b) { return strcmp(a.name, b.name); }