mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2024-11-08 03:45:09 +01:00
[Loader] A single plugin can be loaded via wiiload.
Now more sd swapping for ftpiiu while developing plugins! Simply use the normal wiiload to send a plugin (.mod) file to the Wii U while the plugin loader in running. This requires zlib, don't forget to add it to your portlib. It can be found in the "libs" folder.
This commit is contained in:
parent
0b6d578e27
commit
36f4b1f350
@ -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)
|
||||
|
22
README.MD
22
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.
|
||||
Also thanks to everyone who made actual exploits.
|
||||
Thanks to dhewg for wiiload:
|
||||
http://wiibrew.org/wiki/Wiiload
|
BIN
loader/libs/portlibs.zip
Normal file
BIN
loader/libs/portlibs.zip
Normal file
Binary file not shown.
@ -25,6 +25,7 @@
|
||||
#include <sounds/SoundHandler.hpp>
|
||||
#include <utils/logger.h>
|
||||
#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++) {
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include <system/CThread.h>
|
||||
#include <language/gettext.h>
|
||||
|
||||
#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:
|
||||
|
@ -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)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
@ -10,7 +12,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dynamic_libs/os_functions.h"
|
||||
#include <dynamic_libs/os_functions.h>
|
||||
#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 <dynamic_libs/proc_ui_functions.h>
|
||||
|
||||
#include <utils/logger.h>
|
||||
#include <fs/FSUtils.h>
|
||||
@ -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();
|
||||
|
||||
|
236
loader/src/myutils/TcpReceiver.cpp
Normal file
236
loader/src/myutils/TcpReceiver.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "TcpReceiver.h"
|
||||
#include <dynamic_libs/os_functions.h>
|
||||
#include <dynamic_libs/socket_functions.h>
|
||||
#include <fs/CFile.hpp>
|
||||
#include <fs/FSUtils.h>
|
||||
#include <utils/logger.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <utils/net.h>
|
||||
#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<PluginInformation* > 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;
|
||||
}
|
43
loader/src/myutils/TcpReceiver.h
Normal file
43
loader/src/myutils/TcpReceiver.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef TCP_RECEIVER_H_
|
||||
#define TCP_RECEIVER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <dynamic_libs/os_types.h>
|
||||
|
||||
#include <system/CThread.h>
|
||||
#include <gui/sigslot.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
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<GuiElement *, u32> serverReceiveStart;
|
||||
sigslot::signal3<GuiElement *, u32, int> 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
|
@ -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 */
|
||||
|
@ -105,6 +105,9 @@ void PluginLoader::loadAndLinkPlugins(std::vector<PluginInformation *> 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 *> pluginData) {
|
||||
@ -392,11 +395,17 @@ void PluginLoader::copyPluginDataIntoGlobalStruct(std::vector<PluginData *> 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<PluginData *> 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));
|
||||
}
|
||||
|
@ -107,6 +107,10 @@ public:
|
||||
return getTotalSpace() - getAvailableSpace();
|
||||
}
|
||||
|
||||
void resetPluginLoader() {
|
||||
this->currentStoreAddress = endAddress;
|
||||
}
|
||||
|
||||
private:
|
||||
PluginLoader(void * startAddress, void * endAddress) {
|
||||
// TODO: Check if endAddress > startAddress.
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
@ -9,40 +10,11 @@
|
||||
#include <wups.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include <utils/logger.h>
|
||||
#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);
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <wups.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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);
|
||||
|
BIN
tools/wiiload.exe
Normal file
BIN
tools/wiiload.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user