diff --git a/plugins/mumble_plugin_linux.h b/plugins/mumble_plugin_linux.h index ad499c96c..461d58bb4 100644 --- a/plugins/mumble_plugin_linux.h +++ b/plugins/mumble_plugin_linux.h @@ -11,6 +11,7 @@ #endif #include +#include #include #include #include @@ -212,6 +213,107 @@ static inline bool peekProc(const procptr_t &addr, void *dest, const size_t &len return (nread != -1 && static_cast< size_t >(nread) == in.iov_len); } +static inline procptr_t getExportedSymbol(const std::string &symbol, const procptr_t module) { + if (isWin32) { + return getWin32ExportedSymbol(symbol, module); + } + + procptr_t hashTable = 0; + procptr_t strTable = 0; + procptr_t symTable = 0; + + if (is64Bit) { + const auto ehdr = peekProc< Elf64_Ehdr >(module); + const auto phdr = peekProcVector< Elf64_Phdr >(module + ehdr.e_phoff, ehdr.e_phnum); + + for (size_t i = 0; i < phdr.size(); ++i) { + if (phdr[i].p_type == PT_DYNAMIC) { + const auto dyn = + peekProcVector< Elf64_Dyn >(module + phdr[i].p_vaddr, phdr[i].p_memsz / sizeof(Elf64_Dyn)); + + for (size_t j = 0; j < dyn.size(); ++j) { + switch (dyn[j].d_tag) { + case DT_HASH: + hashTable = dyn[j].d_un.d_ptr; + break; + case DT_STRTAB: + strTable = dyn[j].d_un.d_ptr; + break; + case DT_SYMTAB: + symTable = dyn[j].d_un.d_ptr; + break; + } + + if (hashTable && strTable && symTable) { + break; + } + } + + break; + } + } + } else { + const auto ehdr = peekProc< Elf32_Ehdr >(module); + const auto phdr = peekProcVector< Elf32_Phdr >(module + ehdr.e_phoff, ehdr.e_phnum); + + for (size_t i = 0; i < phdr.size(); ++i) { + if (phdr[i].p_type == PT_DYNAMIC) { + const auto dyn = + peekProcVector< Elf32_Dyn >(module + phdr[i].p_vaddr, phdr[i].p_memsz / sizeof(Elf32_Dyn)); + + for (size_t j = 0; j < dyn.size(); ++j) { + switch (dyn[j].d_tag) { + case DT_HASH: + hashTable = dyn[j].d_un.d_ptr; + break; + case DT_STRTAB: + strTable = dyn[j].d_un.d_ptr; + break; + case DT_SYMTAB: + symTable = dyn[j].d_un.d_ptr; + break; + } + + if (hashTable && strTable && symTable) { + break; + } + } + + break; + } + } + } + + // Hash table pseudo-struct: + // uint32_t nBucket; + // uint32_t nChain; + // uint32_t bucket[nBucket]; + // uint32_t chain[nChain]; + const auto nChain = peekProc< uint32_t >(hashTable + sizeof(uint32_t)); + + if (is64Bit) { + for (uint32_t i = 0; i < nChain; ++i) { + const auto sym = peekProc< Elf64_Sym >(symTable + sizeof(Elf64_Sym) * i); + const auto name = peekProcString(strTable + sym.st_name, symbol.size()); + + if (name == symbol) { + return module + sym.st_value; + } + } + } else { + for (uint32_t i = 0; i < nChain; ++i) { + const auto sym = peekProc< Elf32_Sym >(symTable + sizeof(Elf32_Sym) * i); + const auto name = peekProcString(strTable + sym.st_name, symbol.size()); + + if (name == symbol) { + return module + sym.st_value; + } + } + } + + return 0; +} + static void generic_unlock() { pModule = 0; pPid = 0; diff --git a/plugins/mumble_plugin_main.h b/plugins/mumble_plugin_main.h index f4b5be5b1..6adcd5d1f 100644 --- a/plugins/mumble_plugin_main.h +++ b/plugins/mumble_plugin_main.h @@ -151,6 +151,52 @@ static inline procptr_t getVirtualFunction(const procptr_t classObject, const si return peekProcPtr(vTable + (index * GET_POINTER_SIZE)); } +#ifdef OS_WINDOWS +static inline procptr_t getExportedSymbol(const std::string &symbol, const procptr_t module) { +#else +/// We use a different name because the function is called by the Linux version +/// of getExportedSymbol() in case the process is running through Wine. +static inline procptr_t getWin32ExportedSymbol(const std::string &symbol, const procptr_t module) { +#endif + const auto dos = peekProc< ImageDosHeader >(module); + if (!(dos.magic[0] == 'M' && dos.magic[1] == 'Z')) { + // Invalid DOS signature + return -1; + } + + procptr_t dataAddress; + + if (is64Bit) { + const auto nt = peekProc< ImageNtHeaders64 >(module + dos.addressOfNtHeader); + dataAddress = nt.optionalHeader.dataDirectory[0].virtualAddress; + } else { + const auto nt = peekProc< ImageNtHeaders32 >(module + dos.addressOfNtHeader); + dataAddress = nt.optionalHeader.dataDirectory[0].virtualAddress; + } + + if (!dataAddress) { + return 0; + } + + const auto exportDir = peekProc< ImageExportDirectory >(module + dataAddress); + + const auto funcs = peekProcVector< uint32_t >(module + exportDir.addressOfFunctions, exportDir.numberOfFunctions); + const auto names = peekProcVector< uint32_t >(module + exportDir.addressOfNames, exportDir.numberOfNames); + const auto ords = peekProcVector< uint16_t >(module + exportDir.addressOfNameOrdinals, exportDir.numberOfNames); + + for (uint32_t i = 0; i < exportDir.numberOfNames; ++i) { + if (names[i]) { + const auto name = peekProcString(module + names[i], symbol.size()); + + if (name == symbol) { + return module + funcs[ords[i]]; + } + } + } + + return 0; +} + // This function returns: // -1 in case of failure. // 0 if the process is 32-bit.