diff --git a/.travis.yml b/.travis.yml index f9cb7e7..d24a556 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,7 @@ install: - tar -xzvf libiosuhax.tar.gz - tar -xzvf fs_wrapper.tar.gz - tar -xzvf controller_patcher.tar.gz + - 7z x -y ./libs/portlibs.zip -o${DEVKITPRO} - 7z x -y ./dynamic_libs-lib/libs/portlibs.zip -o${DEVKITPRO} - 7z x -y ./libgui-master/libs/portlibs.zip -o${DEVKITPRO} - (cd libiosuhax-master && make -j8 && make install) diff --git a/README.MD b/README.MD index 019b682..cb8fa2d 100644 --- a/README.MD +++ b/README.MD @@ -47,11 +47,23 @@ For building the loader you need: - [libutils](https://github.com/Maschell/libutils) for common functions. - [libgui](https://github.com/Maschell/libgui) for the gui elements. +Install the according to their readmes. Don't forget to install their dependencies. + +**Dependencies** + +All needed dependencies are in the "libs" folder of this repository. Extract the "portlibs.zip" archive into your devkitPro directory. +The archive includes: + +- zlib + +**Compiling** + Then call the following command in the "loader" directory. ``` make ``` + This should create an "wiiupluginloader.elf" which can be loaded with the Homebrew Launcher. ### Plugins @@ -70,6 +82,12 @@ You can also check out the travis script for needed dependencies of the library, For logging (for example of the loader) you need to start the UdpDebugReader on a computer in the same network. This has been created by @dimok789 and can be found in the tools folder. +# Load plugin via network +While the loader is running, it's possible to load a single plugin via wiiload. +When using this feature, **only** this plugin will be loaded. The plugin will copied to the SDCard, this mean a SDCard is required. +A windows executable can be found in `tools/wiiload.exe` +More information about wiiload and alternatives can be found here: http://wiibrew.org/wiki/Wiiload + # Future Checkout the PLANS.MD for goals, issues and future plans. @@ -77,4 +95,6 @@ Checkout the PLANS.MD for goals, issues and future plans. Some files are based on brainslug by Chadderz: https://github.com/Chadderz121/brainslug-wii Much stuff also wouldn't be possible without dimok789. He made many great tools and homebrew this stuff in based on (Makefiles, Mocha, homebrew channel, udp logger, dynamic_libs etc.) -Also thanks to everyone who made actual exploits. \ No newline at end of file +Also thanks to everyone who made actual exploits. +Thanks to dhewg for wiiload: +http://wiibrew.org/wiki/Wiiload \ No newline at end of file diff --git a/loader/libs/portlibs.zip b/loader/libs/portlibs.zip new file mode 100644 index 0000000..d2a9905 Binary files /dev/null and b/loader/libs/portlibs.zip differ diff --git a/loader/src/Application.cpp b/loader/src/Application.cpp index d020912..a690e06 100644 --- a/loader/src/Application.cpp +++ b/loader/src/Application.cpp @@ -25,6 +25,7 @@ #include #include #include "settings/CSettings.h" +#include "myutils/TcpReceiver.h" Application *Application::applicationInstance = NULL; bool Application::exitApplication = false; @@ -169,6 +170,8 @@ void Application::executeThread(void) { DEBUG_FUNCTION_LINE("Entering main loop\n"); exitApplication = false; //! main GX2 loop (60 Hz cycle with max priority on core 1) + + TcpReceiver pluginReceiver(4299); while(!exitApplication && !reloadUIflag) { //! Read out inputs for(s32 i = 0; i < 5; i++) { diff --git a/loader/src/Application.h b/loader/src/Application.h index c024c89..cd3dc0b 100644 --- a/loader/src/Application.h +++ b/loader/src/Application.h @@ -23,8 +23,8 @@ #include #include -#define APPLICATION_CLOSE_APPLY 1 -#define APPLICATION_CLOSE_MIIMAKER 2 +#define APPLICATION_CLOSE_APPLY 1 +#define APPLICATION_CLOSE_MIIMAKER 2 class Application : public CThread { public: diff --git a/loader/src/common/common.h b/loader/src/common/common.h index 29ad151..e4cd4e3 100644 --- a/loader/src/common/common.h +++ b/loader/src/common/common.h @@ -29,6 +29,9 @@ extern "C" { #define DEFAULT_LANG_PATH DEFAULT_WUPSLOADER_PATH "/languages" #define LANGUAGE_FILE_EXT ".lang" +#define WUPS_TEMP_PLUGIN_PATH SD_PATH WIIU_PATH "/plugins/temp" +#define WUPS_TEMP_PLUGIN_FILE WUPS_TEMP_PLUGIN_PATH "/temp.mod" + #define WUPS_SDUSB_MOUNTED_NONE 0 #define WUPS_SDUSB_MOUNTED_FAKE (1<<0) #define WUPS_SDUSB_MOUNTED_OS_SD (1<<1) diff --git a/loader/src/main.cpp b/loader/src/main.cpp index 6f39840..4b998e5 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include #include #include @@ -10,7 +12,7 @@ #include #include -#include "dynamic_libs/os_functions.h" +#include #include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/ax_functions.h" #include "dynamic_libs/socket_functions.h" @@ -19,7 +21,7 @@ #include "dynamic_libs/nn_nim_functions.h" #include "dynamic_libs/vpad_functions.h" #include "dynamic_libs/padscore_functions.h" -#include "dynamic_libs/proc_ui_functions.h" +#include #include #include @@ -80,7 +82,7 @@ extern "C" int Menu_Main(int argc, char **argv) { DEBUG_FUNCTION_LINE("Wii U Plugin System Loader %s\n",APP_VERSION); - //setup_os_exceptions(); + setup_os_exceptions(); Init(); diff --git a/loader/src/myutils/TcpReceiver.cpp b/loader/src/myutils/TcpReceiver.cpp new file mode 100644 index 0000000..6cc7244 --- /dev/null +++ b/loader/src/myutils/TcpReceiver.cpp @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "TcpReceiver.h" +#include +#include +#include +#include +#include +#include +#include +#include "Application.h" +#include "plugin/PluginLoader.h" +#include "plugin/PluginInformation.h" + +TcpReceiver::TcpReceiver(int port) + : CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) + , exitRequested(false) + , serverPort(port) + , serverSocket(-1) { + + resumeThread(); +} + +TcpReceiver::~TcpReceiver() { + exitRequested = true; + + if(serverSocket > 0) { + shutdown(serverSocket, SHUT_RDWR); + } +} + +void TcpReceiver::executeThread() { + serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (serverSocket < 0) + return; + + u32 enable = 1; + setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + + struct sockaddr_in bindAddress; + memset(&bindAddress, 0, sizeof(bindAddress)); + bindAddress.sin_family = AF_INET; + bindAddress.sin_port = serverPort; + bindAddress.sin_addr.s_addr = INADDR_ANY; + + s32 ret; + if ((ret = bind(serverSocket, (struct sockaddr *)&bindAddress, sizeof(bindAddress))) < 0) { + socketclose(serverSocket); + return; + } + + if ((ret = listen(serverSocket, 3)) < 0) { + socketclose(serverSocket); + return; + } + + struct sockaddr_in clientAddr; + s32 addrlen = sizeof(struct sockaddr); + + while(!exitRequested) { + s32 clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrlen); + if(clientSocket >= 0) { + u32 ipAddress = clientAddr.sin_addr.s_addr; + //serverReceiveStart(this, ipAddress); + int result = loadToMemory(clientSocket, ipAddress); + //serverReceiveFinished(this, ipAddress, result); + socketclose(clientSocket); + + if(result > 0) + break; + } else { + os_usleep(100000); + } + } + + socketclose(serverSocket); +} + +int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) { + DEBUG_FUNCTION_LINE("Loading file from ip %08X\n", ipAddress); + + u32 fileSize = 0; + u32 fileSizeUnc = 0; + unsigned char haxx[8]; + memset(haxx, 0, sizeof(haxx)); + //skip haxx + recvwait(clientSocket, haxx, sizeof(haxx)); + recvwait(clientSocket, (unsigned char*)&fileSize, sizeof(fileSize)); + + if (haxx[4] > 0 || haxx[5] > 4) { + recvwait(clientSocket, (unsigned char*)&fileSizeUnc, sizeof(fileSizeUnc)); // Compressed protocol, read another 4 bytes + } + + u32 bytesRead = 0; + struct in_addr in; + in.s_addr = ipAddress; + + DEBUG_FUNCTION_LINE("transfer start\n"); + + unsigned char* loadAddress = (unsigned char*)memalign(0x40, fileSize); + if(!loadAddress) { + os_sleep(1); + return NOT_ENOUGH_MEMORY; + } + + // Copy rpl in memory + while(bytesRead < fileSize) { + + u32 blockSize = 0x1000; + if(blockSize > (fileSize - bytesRead)) + blockSize = fileSize - bytesRead; + + int ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0); + if(ret <= 0) { + DEBUG_FUNCTION_LINE("Failure on reading file\n"); + break; + } + + bytesRead += ret; + } + + if(bytesRead != fileSize) { + free(loadAddress); + DEBUG_FUNCTION_LINE("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize); + os_sleep(1); + return FILE_READ_ERROR; + } + + bool res = false; + + // Do we need to unzip this thing? + if (haxx[4] > 0 || haxx[5] > 4) { + unsigned char* inflatedData = NULL; + + // We need to unzip... + if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04) { + //! TODO: + //! mhmm this is incorrect, it has to parse the zip + + // Section is compressed, inflate + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) { + free(loadAddress); + os_sleep(1); + return NOT_ENOUGH_MEMORY; + } + + int ret = 0; + z_stream s; + memset(&s, 0, sizeof(s)); + + s.zalloc = Z_NULL; + s.zfree = Z_NULL; + s.opaque = Z_NULL; + + ret = inflateInit(&s); + if (ret != Z_OK) { + free(loadAddress); + free(inflatedData); + os_sleep(1); + return FILE_READ_ERROR; + } + + s.avail_in = fileSize; + s.next_in = (Bytef *)(&loadAddress[0]); + + s.avail_out = fileSizeUnc; + s.next_out = (Bytef *)&inflatedData[0]; + + ret = inflate(&s, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) { + free(loadAddress); + free(inflatedData); + os_sleep(1); + return FILE_READ_ERROR; + } + + inflateEnd(&s); + fileSize = fileSizeUnc; + } else { + // Section is compressed, inflate + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) { + free(loadAddress); + os_sleep(1); + return NOT_ENOUGH_MEMORY; + } + + uLongf f = fileSizeUnc; + int result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize); + if(result != Z_OK) { + DEBUG_FUNCTION_LINE("uncompress failed %i\n", result); + os_sleep(1); + return FILE_READ_ERROR; + } + + fileSizeUnc = f; + fileSize = fileSizeUnc; + } + + FSUtils::CreateSubfolder(WUPS_TEMP_PLUGIN_PATH); + res = FSUtils::saveBufferToFile(WUPS_TEMP_PLUGIN_FILE,inflatedData, fileSize); + free(inflatedData); + } else { + + FSUtils::CreateSubfolder(WUPS_TEMP_PLUGIN_PATH); + res = FSUtils::saveBufferToFile(WUPS_TEMP_PLUGIN_FILE,loadAddress, fileSize); + free(loadAddress); + } + + if(!res) { + os_sleep(1); + return NOT_ENOUGH_MEMORY; + } + + PluginInformation * plugin = PluginInformation::loadPluginInformation(WUPS_TEMP_PLUGIN_FILE); + if(plugin == NULL) { + return NOT_A_VALID_PLUGIN; + } + PluginLoader * pluginLoader = PluginLoader::getInstance(); + pluginLoader->resetPluginLoader(); + std::vector pluginList = pluginLoader->getPluginInformation(WUPS_TEMP_PLUGIN_PATH); + if(pluginList.size() == 0) { + return NOT_A_VALID_PLUGIN; + } + pluginLoader->loadAndLinkPlugins(pluginList); + Application::instance()->quit(APPLICATION_CLOSE_APPLY); + + return fileSize; +} diff --git a/loader/src/myutils/TcpReceiver.h b/loader/src/myutils/TcpReceiver.h new file mode 100644 index 0000000..05cc79a --- /dev/null +++ b/loader/src/myutils/TcpReceiver.h @@ -0,0 +1,43 @@ +#ifndef TCP_RECEIVER_H_ +#define TCP_RECEIVER_H_ + +#include +#include +#include + +#include +#include +#include + +class TcpReceiver : public CThread +{ +public: + enum eLoadResults + { + SUCCESS = 0, + INVALID_INPUT = -1, + FILE_OPEN_FAILURE = -2, + FILE_READ_ERROR = -3, + NOT_ENOUGH_MEMORY = -4, + NOT_A_VALID_PLUGIN = -5, + }; + + TcpReceiver(int port); + ~TcpReceiver(); + + sigslot::signal2 serverReceiveStart; + sigslot::signal3 serverReceiveFinished; + +private: + + void executeThread(); + int loadToMemory(s32 clientSocket, u32 ipAddress); + bool saveFileToSDCard(const char * path, void * buffer,u32 size); + + bool exitRequested; + s32 serverPort; + s32 serverSocket; +}; + + +#endif diff --git a/loader/src/patcher/function_patcher.h b/loader/src/patcher/function_patcher.h index 64e02a1..2d4a8b0 100644 --- a/loader/src/patcher/function_patcher.h +++ b/loader/src/patcher/function_patcher.h @@ -37,7 +37,7 @@ struct rpl_handling { #define FUNCTION_PATCHER_METHOD_STORE_SIZE 7 #define MAXIMUM_PLUGIN_PATH_NAME_LENGTH 256 #define MAXIMUM_PLUGIN_NAME_LENGTH 51 -#define MAXIMUM_FUNCTION_NAME_LENGTH 51 +#define MAXIMUM_FUNCTION_NAME_LENGTH 61 struct replacement_data_function_t { u32 replaceAddr; /* [needs to be filled] Address of our replacement function */ diff --git a/loader/src/plugin/PluginLoader.cpp b/loader/src/plugin/PluginLoader.cpp index 40c0ea2..c3a34e9 100644 --- a/loader/src/plugin/PluginLoader.cpp +++ b/loader/src/plugin/PluginLoader.cpp @@ -105,6 +105,9 @@ void PluginLoader::loadAndLinkPlugins(std::vector pluginInf copyPluginDataIntoGlobalStruct(loadedPlugins); clearPluginData(loadedPlugins); + + DCFlushRange((void*)this->startAddress,(u32)this->endAddress - (u32)this->startAddress); + ICInvalidateRange((void*)this->startAddress,(u32)this->endAddress - (u32)this->startAddress); } void PluginLoader::clearPluginData(std::vector pluginData) { @@ -392,11 +395,17 @@ void PluginLoader::copyPluginDataIntoGlobalStruct(std::vector plug for(size_t j = 0; j < function_data_list.size(); j++) { replacement_data_function_t * function_data = &plugin_data->functions[j]; - FunctionData * cur_function = function_data_list[j]; + + if(strlen(cur_function->getName().c_str()) > MAXIMUM_FUNCTION_NAME_LENGTH-1){ + DEBUG_FUNCTION_LINE("Couldn not add function \"%s\" for plugin \"%s\" function name is too long.\n",cur_function->getName().c_str(),plugin_data->plugin_name); + continue; + } + DEBUG_FUNCTION_LINE("Adding function \"%s\" for plugin \"%s\"\n",cur_function->getName().c_str(),plugin_data->plugin_name); //TODO: Warning/Error if string is too long. + strncpy(function_data->function_name,cur_function->getName().c_str(),MAXIMUM_FUNCTION_NAME_LENGTH-1); function_data->library = cur_function->getLibrary(); @@ -424,4 +433,6 @@ void PluginLoader::copyPluginDataIntoGlobalStruct(std::vector plug plugin_index++; gbl_replacement_data.number_used_plugins++; } + DCFlushRange((void*)&gbl_replacement_data,sizeof(gbl_replacement_data)); + ICInvalidateRange((void*)&gbl_replacement_data,sizeof(gbl_replacement_data)); } diff --git a/loader/src/plugin/PluginLoader.h b/loader/src/plugin/PluginLoader.h index 5cea729..7bf7687 100644 --- a/loader/src/plugin/PluginLoader.h +++ b/loader/src/plugin/PluginLoader.h @@ -107,6 +107,10 @@ public: return getTotalSpace() - getAvailableSpace(); } + void resetPluginLoader() { + this->currentStoreAddress = endAddress; + } + private: PluginLoader(void * startAddress, void * endAddress) { // TODO: Check if endAddress > startAddress. diff --git a/loader/src/utils.cpp b/loader/src/utils.cpp index 67b598a..ffccd4f 100644 --- a/loader/src/utils.cpp +++ b/loader/src/utils.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,40 +10,11 @@ #include #include "utils.h" +#include #include "common/common.h" #include "common/retain_vars.h" #include "myutils/overlay_helper.h" -// https://gist.github.com/ccbrown/9722406 -void dumpHex(const void* data, size_t size) { - char ascii[17]; - size_t i, j; - ascii[16] = '\0'; - for (i = 0; i < size; ++i) { - log_printf("%02X ", ((unsigned char*)data)[i]); - if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { - ascii[i % 16] = ((unsigned char*)data)[i]; - } else { - ascii[i % 16] = '.'; - } - if ((i+1) % 8 == 0 || i+1 == size) { - log_printf(" "); - if ((i+1) % 16 == 0) { - log_printf("| %s \n", ascii); - } else if (i+1 == size) { - ascii[(i+1) % 16] = '\0'; - if ((i+1) % 16 <= 8) { - log_printf(" "); - } - for (j = (i+1) % 16; j < 16; ++j) { - log_printf(" "); - } - log_printf("| %s \n", ascii); - } - } - } -} - void CallHook(wups_loader_hook_type_t hook_type) { CallHookEx(hook_type,-1); } diff --git a/loader/src/utils.h b/loader/src/utils.h index c058c83..991c968 100644 --- a/loader/src/utils.h +++ b/loader/src/utils.h @@ -7,8 +7,8 @@ extern "C" { #endif #include +#include -void dumpHex(const void* data, size_t size); void CallHook(wups_loader_hook_type_t hook_type); void CallHookEx(wups_loader_hook_type_t hook_type, s32 plugin_index_needed); diff --git a/tools/wiiload.exe b/tools/wiiload.exe new file mode 100644 index 0000000..601014f Binary files /dev/null and b/tools/wiiload.exe differ