diff --git a/source/common/plugin_defines.h b/source/common/plugin_defines.h index 46966d5..2114fdf 100644 --- a/source/common/plugin_defines.h +++ b/source/common/plugin_defines.h @@ -65,6 +65,12 @@ struct replacement_data_hook_t { wups_loader_hook_type_t type{}; /* [will be filled] */ }; +struct plugin_function_symbol_data_t { + char* name; + void* address; + uint32_t size; +}; + struct plugin_info_t { dyn_linking_relocation_entry_t linking_entries[PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH]{}; plugin_section_info_t sectionInfos[MAXIMUM_PLUGIN_SECTION_LENGTH]; @@ -73,8 +79,11 @@ struct plugin_info_t { uint32_t number_used_hooks{}; // Number of used hooks. Maximum is MAXIMUM_HOOKS_PER_PLUGIN replacement_data_hook_t hooks[MAXIMUM_HOOKS_PER_PLUGIN]; // Replacement information for each function. uint8_t trampolinId{}; + plugin_function_symbol_data_t * function_symbol_data = nullptr; + uint32_t number_function_symbol_data = 0; void * allocatedTextMemoryAddress = nullptr; void * allocatedDataMemoryAddress = nullptr; + void * allocatedFuncSymStringTableAddress = nullptr; }; struct plugin_data_t { diff --git a/source/main.cpp b/source/main.cpp index b228f6e..5c47eb1 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -129,7 +129,7 @@ WUMS_APPLICATION_STARTS() { for (const auto &kv: pluginContainer.getPluginInformation().getSectionInfoList()) { DEBUG_FUNCTION_LINE_VERBOSE("%s = %s %08X %d", kv.first.c_str(), kv.second.getName().c_str(), kv.second.getAddress(), kv.second.getSize()); } - if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer)) { + if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer, gPluginDataHeap)) { DEBUG_FUNCTION_LINE("Failed to save plugin"); } } @@ -181,7 +181,7 @@ WUMS_APPLICATION_STARTS() { for (auto &pluginContainer: plugins) { DEBUG_FUNCTION_LINE("Stored information for plugin %s ; %s", pluginContainer.getMetaInformation().getName().c_str(), pluginContainer.getMetaInformation().getAuthor().c_str()); - if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer)) { + if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer, gPluginDataHeap)) { DEBUG_FUNCTION_LINE("Failed to save plugin"); } } @@ -221,7 +221,7 @@ void *allocOnCustomHeap(int alignment, int size) { } uint32_t *custom_memalign; dyn_res = OSDynLoad_FindExport(module, true, "MEMAllocFromMappedMemoryEx", reinterpret_cast(&custom_memalign)); - auto * customMEMAllocFromDefaultHeapEx = (void *(*)(uint32_t, int)) *custom_memalign; + auto *customMEMAllocFromDefaultHeapEx = (void *(*)(uint32_t, int)) *custom_memalign; if (dyn_res != OS_DYNLOAD_OK) { return nullptr; diff --git a/source/patcher/hooks_patcher_static.cpp b/source/patcher/hooks_patcher_static.cpp index 4eff359..856d0cb 100644 --- a/source/patcher/hooks_patcher_static.cpp +++ b/source/patcher/hooks_patcher_static.cpp @@ -102,6 +102,116 @@ DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) { } } + +#define KiReport ((void (*)( const char*, ... ))0xfff0ad0c) + + +#pragma GCC push_options +#pragma GCC optimize ("O0") + +DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol, + uint32_t addr, + uint32_t *outDistance, + char *symbolNameBuffer, + uint32_t symbolNameBufferLength, + char *moduleNameBuffer, + uint32_t moduleNameBufferLength) { + for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) { + plugin_information_single_t *plugin = &(gPluginInformation->plugin_data[plugin_index]); + plugin_section_info_t *section = nullptr; + + for (auto §ionInfo: plugin->info.sectionInfos) { + if (sectionInfo.addr == 0 && sectionInfo.size == 0) { + break; + } + if (strncmp(sectionInfo.name, ".text", sizeof(sectionInfo.name)) == 0) { + section = §ionInfo; + break; + } + } + if (section == nullptr) { + continue; + } + if (addr < section->addr || addr >= (section->addr + section->size)) { + continue; + } + + strncpy(moduleNameBuffer, plugin->meta.name, moduleNameBufferLength); + if (plugin->info.function_symbol_data != nullptr && plugin->info.number_function_symbol_data > 1) { + for (uint32_t i = 0; i < plugin->info.number_function_symbol_data - 1; i++) { + auto symbolData = &plugin->info.function_symbol_data[i]; + auto symbolDataNext = &plugin->info.function_symbol_data[i + 1]; + if (i == plugin->info.number_function_symbol_data - 2 || (addr >= (uint32_t) symbolData->address && addr < (uint32_t) symbolDataNext->address)) { + strncpy(symbolNameBuffer, symbolData->name, moduleNameBufferLength); + if (outDistance) { + *outDistance = addr - (uint32_t) symbolData->address; + } + return 0; + } + } + } + + strncpy(symbolNameBuffer, ".text", symbolNameBufferLength); + + if (outDistance) { + *outDistance = addr - (uint32_t) section->addr; + } + + return 0; + } + + return real_SC17_FindClosestSymbol(addr, outDistance, symbolNameBuffer, symbolNameBufferLength, moduleNameBuffer, moduleNameBufferLength); +} + +DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t bufSize) { + for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) { + plugin_information_single_t *plugin = &(gPluginInformation->plugin_data[plugin_index]); + plugin_section_info_t *section = nullptr; + + for (auto §ionInfo: plugin->info.sectionInfos) { + if (sectionInfo.addr == 0 && sectionInfo.size == 0) { + break; + } + if (strncmp(sectionInfo.name, ".text", sizeof(sectionInfo.name)) == 0) { + section = §ionInfo; + break; + } + } + if (section == nullptr) { + continue; + } + if (addr < section->addr || addr >= (section->addr + section->size)) { + continue; + } + + auto pluginNameLen = strlen(plugin->meta.name); + int32_t spaceLeftInBuffer = (int32_t) bufSize - (int32_t) pluginNameLen - 1; + if (spaceLeftInBuffer < 0) { + spaceLeftInBuffer = 0; + } + strncpy(buffer, plugin->meta.name, bufSize); + + if (plugin->info.function_symbol_data != nullptr && plugin->info.number_function_symbol_data > 1) { + for (uint32_t i = 0; i < plugin->info.number_function_symbol_data - 1; i++) { + auto symbolData = &plugin->info.function_symbol_data[i]; + auto symbolDataNext = &plugin->info.function_symbol_data[i + 1]; + if (i == plugin->info.number_function_symbol_data - 2 || (addr >= (uint32_t) symbolData->address && addr < (uint32_t) symbolDataNext->address)) { + if(spaceLeftInBuffer > 2){ + buffer[pluginNameLen] = '|'; + buffer[pluginNameLen + 1] = '\0'; + strncpy(buffer + pluginNameLen + 1, symbolData->name, spaceLeftInBuffer - 1); + } + return (uint32_t) symbolData->address; + } + } + } + return addr; + } + + return real_KiGetAppSymbolName(addr, buffer, bufSize); +} +#pragma GCC pop_options + function_replacement_data_t method_hooks_hooks_static[] __attribute__((section(".data"))) = { REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers), REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer), @@ -110,6 +220,9 @@ function_replacement_data_t method_hooks_hooks_static[] __attribute__((section(" REPLACE_FUNCTION(OSReleaseForeground, LIBRARY_COREINIT, OSReleaseForeground), REPLACE_FUNCTION(VPADRead, LIBRARY_VPAD, VPADRead), REPLACE_FUNCTION(WPADRead, LIBRARY_PADSCORE, WPADRead), + REPLACE_FUNCTION_VIA_ADDRESS(SC17_FindClosestSymbol, 0xfff10218, 0xfff10218), + REPLACE_FUNCTION_VIA_ADDRESS(KiGetAppSymbolName, 0xfff0e3a0, 0xfff0e3a0), + }; uint32_t method_hooks_size_hooks_static __attribute__((section(".data"))) = sizeof(method_hooks_hooks_static) / sizeof(function_replacement_data_t); \ No newline at end of file diff --git a/source/plugin/FunctionSymbolData.h b/source/plugin/FunctionSymbolData.h new file mode 100644 index 0000000..676a341 --- /dev/null +++ b/source/plugin/FunctionSymbolData.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (C) 2021 Maschell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#pragma once + +#include + +class FunctionSymbolData { + +public: + FunctionSymbolData(const FunctionSymbolData &o2) = default; + + FunctionSymbolData(std::string &name, void *address, uint32_t size) : + name(name), + address(address), + size(size) { + } + + bool operator<(const FunctionSymbolData &rhs) const { + return (uint32_t) address < (uint32_t) rhs.address; //assume that you compare the record based on a + } + + virtual ~FunctionSymbolData() = default; + + [[nodiscard]] const std::string &getName() const { + return name; + } + + [[nodiscard]] void *getAddress() const { + return address; + } + + [[nodiscard]] uint32_t getSize() const { + return size; + } + +private: + std::string name; + void *address; + uint32_t size; +}; \ No newline at end of file diff --git a/source/plugin/PluginContainerPersistence.cpp b/source/plugin/PluginContainerPersistence.cpp index febcf60..631d5fa 100644 --- a/source/plugin/PluginContainerPersistence.cpp +++ b/source/plugin/PluginContainerPersistence.cpp @@ -7,7 +7,7 @@ #include "PluginDataPersistence.h" #include "DynamicLinkingHelper.h" -bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformation, PluginContainer &plugin) { +bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformation, PluginContainer &plugin, MEMHeapHandle heapHandle) { int32_t plugin_count = pluginInformation->number_used_plugins; auto pluginName = plugin.getMetaInformation().getName(); @@ -160,6 +160,48 @@ bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformat plugin_data->info.allocatedDataMemoryAddress = pluginInfo.allocatedDataMemoryAddress; + uint32_t entryCount = pluginInfo.getFunctionSymbolDataList().size(); + if (entryCount > 0) { + /* Saving SectionInfos */ + uint32_t funcSymStringLen = 1; + for (auto &curFuncSym: pluginInfo.getFunctionSymbolDataList()) { + funcSymStringLen += curFuncSym.getName().length() + 1; + } + + char *stringTable = (char *) MEMAllocFromExpHeapEx(heapHandle, funcSymStringLen, 0x4); + if (stringTable == nullptr) { + DEBUG_FUNCTION_LINE("Failed alloc memory to store string table for function symbol data"); + return false; + } + memset(stringTable, 0, funcSymStringLen); + DEBUG_FUNCTION_LINE("Allocated %d for the function symbol string table", funcSymStringLen); + auto *entryTable = (plugin_function_symbol_data_t *) MEMAllocFromExpHeapEx(heapHandle, entryCount * sizeof(plugin_function_symbol_data_t), 0x4); + if (entryTable == nullptr) { + MEMFreeToExpHeap((MEMHeapHandle) heapHandle, stringTable); + free(stringTable); + DEBUG_FUNCTION_LINE("Failed alloc memory to store function symbol data"); + return false; + } + DEBUG_FUNCTION_LINE("Allocated %d for the function symbol data", entryCount * sizeof(plugin_function_symbol_data_t)); + + uint32_t curStringOffset = 0; + uint32_t curEntryIndex = 0; + for (auto &curFuncSym: pluginInfo.getFunctionSymbolDataList()) { + entryTable[curEntryIndex].address = curFuncSym.getAddress(); + entryTable[curEntryIndex].name = &stringTable[curStringOffset]; + entryTable[curEntryIndex].size = curFuncSym.getSize(); + auto len = curFuncSym.getName().length() + 1; + memcpy(stringTable + curStringOffset, curFuncSym.getName().c_str(), len); + curStringOffset += len; + curEntryIndex++; + } + + plugin_data->info.allocatedFuncSymStringTableAddress = stringTable; + plugin_data->info.function_symbol_data = entryTable; + } + + plugin_data->info.number_function_symbol_data = entryCount; + /* Copy plugin data */ auto pluginData = plugin.getPluginData(); auto plugin_data_data = &plugin_data->data; @@ -239,13 +281,13 @@ std::vector PluginContainerPersistence::loadPlugins(plugin_info } bool storageHasId = true; - for(auto const &value : curPluginInformation.getHookDataList()){ - if(value.getType() == WUPS_LOADER_HOOK_INIT_STORAGE && - metaInformation.getStorageId().empty()){ + for (auto const &value: curPluginInformation.getHookDataList()) { + if (value.getType() == WUPS_LOADER_HOOK_INIT_STORAGE && + metaInformation.getStorageId().empty()) { storageHasId = false; } } - if(!storageHasId){ + if (!storageHasId) { DEBUG_FUNCTION_LINE("Plugin is using the storage API but has not set an ID"); continue; } @@ -287,6 +329,14 @@ std::vector PluginContainerPersistence::loadPlugins(plugin_info curPluginInformation.addRelocationData(reloc); } + /* load function symbol data */ + for (uint32_t j = 0; j < plugin_data->info.number_function_symbol_data; j++) { + auto symbol_data = &plugin_data->info.function_symbol_data[j]; + std::string symbol_name = symbol_data->name; + FunctionSymbolData funSymbolData(symbol_name, (void *) symbol_data->address, symbol_data->size); + curPluginInformation.addFunctionSymbolData(funSymbolData); + } + PluginContainer container; container.setMetaInformation(metaInformation); container.setPluginData(pluginData); diff --git a/source/plugin/PluginContainerPersistence.h b/source/plugin/PluginContainerPersistence.h index 1cccf5f..8b775a8 100644 --- a/source/plugin/PluginContainerPersistence.h +++ b/source/plugin/PluginContainerPersistence.h @@ -5,7 +5,7 @@ class PluginContainerPersistence { public: - static bool savePlugin(plugin_information_t *pluginInformation, PluginContainer &plugin); + static bool savePlugin(plugin_information_t *pluginInformation, PluginContainer &plugin, MEMHeapHandle heapHandle); static std::vector loadPlugins(plugin_information_t *pluginInformation); }; diff --git a/source/plugin/PluginInformation.cpp b/source/plugin/PluginInformation.cpp index fd76757..3302be7 100644 --- a/source/plugin/PluginInformation.cpp +++ b/source/plugin/PluginInformation.cpp @@ -10,6 +10,9 @@ PluginInformation::PluginInformation(const PluginInformation &other) { for (const auto &i: other.relocation_data_list) { relocation_data_list.push_back(i); } + for (const auto &i: other.symbol_data_list) { + symbol_data_list.insert(i); + } section_info_list = other.section_info_list; trampolinId = other.trampolinId; allocatedTextMemoryAddress = other.allocatedTextMemoryAddress; diff --git a/source/plugin/PluginInformation.h b/source/plugin/PluginInformation.h index 9ef1d54..c93faf7 100644 --- a/source/plugin/PluginInformation.h +++ b/source/plugin/PluginInformation.h @@ -18,6 +18,7 @@ #pragma once #include +#include #include #include #include @@ -26,6 +27,7 @@ #include "HookData.h" #include "FunctionData.h" #include "SectionInfo.h" +#include "FunctionSymbolData.h" class PluginInformation { public: @@ -59,6 +61,14 @@ public: return relocation_data_list; } + void addFunctionSymbolData(const FunctionSymbolData &symbol_data) { + symbol_data_list.insert(symbol_data); + } + + [[nodiscard]] const std::set &getFunctionSymbolDataList() const { + return symbol_data_list; + } + void addSectionInfo(const SectionInfo §ionInfo) { section_info_list[sectionInfo.getName()] = sectionInfo; } @@ -86,6 +96,7 @@ private: std::vector hook_data_list; std::vector function_data_list; std::vector relocation_data_list; + std::set symbol_data_list; std::map section_info_list; uint8_t trampolinId = 0; diff --git a/source/plugin/PluginInformationFactory.cpp b/source/plugin/PluginInformationFactory.cpp index d166f05..f4ad527 100644 --- a/source/plugin/PluginInformationFactory.cpp +++ b/source/plugin/PluginInformationFactory.cpp @@ -200,7 +200,44 @@ PluginInformationFactory::load(const PluginData &pluginData, MEMHeapHandle heapH } } - // Save the addresses for the allocated. This way we can free it again :) + // Get the symbol for functions. + Elf_Half n = reader.sections.size(); + for (Elf_Half i = 0; i < n; ++i) { + section *sec = reader.sections[i]; + if (SHT_SYMTAB == sec->get_type()) { + symbol_section_accessor symbols(reader, sec); + auto sym_no = (uint32_t) symbols.get_symbols_num(); + if (sym_no > 0) { + for (Elf_Half j = 0; j < sym_no; ++j) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + if (symbols.get_symbol(j, name, value, size, bind, type, section, other)) { + + if (type == STT_FUNC) { // We only care about functions. + auto sectionVal = reader.sections[section]; + auto offsetVal = value - sectionVal->get_address(); + auto sectionOpt = pluginInfo.getSectionInfo(sectionVal->get_name()); + if (!sectionOpt.has_value()) { + continue; + } + + auto finalAddress = offsetVal + sectionOpt->getAddress(); + + pluginInfo.addFunctionSymbolData(FunctionSymbolData(name, (void *) finalAddress, (uint32_t) size)); + } + } + } + break; + } + } + } + + // Save the addresses for the allocated memory. This way we can free it again :) pluginInfo.allocatedDataMemoryAddress = data_data; pluginInfo.allocatedTextMemoryAddress = text_data; @@ -332,7 +369,7 @@ bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X", sym_section_index); return false; } - DEBUG_FUNCTION_LINE_VERBOSE("sym_value %08X adjusted_sym_value %08X offset %08X adjusted_offset %08X", (uint32_t) sym_value, adjusted_sym_value, (uint32_t) offset, adjusted_offset); + // DEBUG_FUNCTION_LINE_VERBOSE("sym_value %08X adjusted_sym_value %08X offset %08X adjusted_offset %08X", (uint32_t) sym_value, adjusted_sym_value, (uint32_t) offset, adjusted_offset); if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampolin_data, trampolin_data_length, RELOC_TYPE_FIXED, trampolinId)) { DEBUG_FUNCTION_LINE("Link failed"); diff --git a/source/utils/logger.h b/source/utils/logger.h index 5915956..4e0263c 100644 --- a/source/utils/logger.h +++ b/source/utils/logger.h @@ -13,7 +13,9 @@ extern "C" { OSFatal_printf("[%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0) -#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) do { \ + WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0) #define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0)