Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2020-09-27 21:12:02 +0300
committerDavide Beatrici <git@davidebeatrici.dev>2020-09-27 21:12:02 +0300
commit5df2bb2c0bdf91ed078e3cd3fafb04bdec5333c8 (patch)
treef60ded92d9759a254c7418b684b6c671cfbe3e23 /plugins/mumble_plugin_main.h
parentd8c4b82efee8f2e0785f04ed8d9e7c8b24cdca4d (diff)
FEAT(client): add getExportedSymbol() function for positional audio plugins
This function is of critical importance for the Source Engine plugin, let me elaborate on why. Most games consist in an executable and maybe one or more libraries, but they don't have particular exported symbols we can use to easily access (existing) resources inside the process, which means we have to rely on hardcoded offsets and hex pattern scanning. Source Engine games are special: the executable is nothing more than a manager that takes care of loading the core libraries, which are engine(.dll|.so) and client(.dll|.so) (or server(.dll|.so) in the case of a dedicated server). Those libraries have a common exported symbol, which is CreateInterface(). The function takes the interface's name as argument (char *), creates the interface object if it doesn't exist yet and returns a pointer (void *) to it. The interfaces objects are stored in a list called s_pInterfaceList, which is usually an exported symbol on Linux. getExportedSymbol() allows us to get the address to CreateInterface() (different for each loaded library) inside the process and read the function's assembly code in order to reach s_pInterfaceList. If s_pInterfaceList is exported we can get its address with getExportedSymbol(), without the need of CreateInterface().
Diffstat (limited to 'plugins/mumble_plugin_main.h')
-rw-r--r--plugins/mumble_plugin_main.h46
1 files changed, 46 insertions, 0 deletions
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.