From 86ae3eba7ccf046fdc7ae769cb93266a362958a6 Mon Sep 17 00:00:00 2001 From: Florian Bach Date: Sat, 15 Dec 2018 17:11:17 +0100 Subject: [PATCH] Support for new Wiimmfi update --- .../wiiflow_game_booter/source/apploader.c | 10 + .../wiiflow_game_booter/source/patchcode.c | 238 ++++++++++++++++++ .../wiiflow_game_booter/source/patchcode.h | 1 + source/menu/menu_config_game.cpp | 2 +- wii/wiiflow/Languages/english.ini | 2 +- wii/wiiflow/Languages/german.ini | 2 +- wii/wiiflow/Languages/italian.ini | 2 +- wii/wiiflow/Languages/korean.ini | 2 +- wii/wiiflow/Languages/spanish.ini | 4 +- 9 files changed, 256 insertions(+), 7 deletions(-) diff --git a/resources/wiiflow_game_booter/source/apploader.c b/resources/wiiflow_game_booter/source/apploader.c index 8affc320..bfb84e30 100644 --- a/resources/wiiflow_game_booter/source/apploader.c +++ b/resources/wiiflow_game_booter/source/apploader.c @@ -35,6 +35,7 @@ static void Anti_002_fix(void *Address, int Size); static bool Remove_001_Protection(void *Address, int Size); static void PrinceOfPersiaPatch(); static void NewSuperMarioBrosPatch(); +static void MarioKartWiiWiimmfiPatch( bool server); bool hookpatched = false; /* Thanks Tinyload */ @@ -102,6 +103,8 @@ u32 Apploader_Run(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryStrin free_wip(); if(hooktype != 0 && hookpatched) ocarina_do_code(); + + MarioKartWiiWiimmfiPatch(private_server); /* Set entry point from apploader */ return (u32)appldr_final(); @@ -168,6 +171,13 @@ static void Anti_002_fix(void *Address, int Size) } } +static void MarioKartWiiWiimmfiPatch( bool server) { + if(memcmp("RMC", GameID, 3) != 0) return; // This isn't MKWii + if(server == 0) return; // no Wiimmfi patch wanted + + do_new_wiimmfi(); +} + static void PrinceOfPersiaPatch() { if(memcmp("SPX", GameID, 3) != 0 && memcmp("RPW", GameID, 3) != 0) diff --git a/resources/wiiflow_game_booter/source/patchcode.c b/resources/wiiflow_game_booter/source/patchcode.c index 88c8396a..e8c2f4b5 100644 --- a/resources/wiiflow_game_booter/source/patchcode.c +++ b/resources/wiiflow_game_booter/source/patchcode.c @@ -28,6 +28,7 @@ #include "patchcode.h" #include "memory.h" #include "gecko.h" +#include "../../../source/defines.h" u32 hooktype; u8 configbytes[2]; @@ -684,3 +685,240 @@ void domainpatcher(void *addr, u32 len, const char* domain) } while (++cur < end); } + +u32 do_new_wiimmfi() { + + // As of November 2018, Wiimmfi requires a special Wiimmfi patcher + // update which does a bit more than just patch the server adresses. + // This function is being called by apploader.c, right before + // jumping to the entry point (only for Mario Kart Wii & Wiimmfi), + // and applies all the necessary new patches to the game. + // This includes support for the new patcher update plus + // support for StaticR.rel patching. + + // This function has been implemented by Leseratte. Please don't + // try to modify it without speaking to the Wiimmfi team because + // doing so could have unintended side effects. + + // check region: + char region = *((char *)(0x80000003)); + char * patched; + void * patch1_offset, *patch2_offset, *patch3_offset; + + // define some offsets and variables depending on the region: + switch (region) { + case 'P': + patched = (char*)0x80276054; + patch1_offset = (void*)0x800ee3a0; + patch2_offset = (void*)0x801d4efc; + patch3_offset = (void*)0x801A72E0; + break; + case 'E': + patched = (char*)0x80271d14; + patch1_offset = (void*)0x800ee300; + patch2_offset = (void*)0x801d4e5c; + patch3_offset = (void*)0x801A7240; + break; + case 'J': + patched = (char*)0x802759f4; + patch1_offset = (void*)0x800ee2c0; + patch2_offset = (void*)0x801d4e1c; + patch3_offset = (void*)0x801A7200; + break; + case 'K': + patched = (char*)0x80263E34; + patch1_offset = (void*)0x800ee418; + patch2_offset = (void*)0x801d5258; + patch3_offset = (void*)0x801A763c; + break; + default: + return -1; + } + + if (*patched != '*') return -2; // ISO already patched + + // This RAM address is set (no asterisk) by all officially + // updated patchers, so if it is modified, the image is already + // patched with a new patcher and we don't need to patch anything. + + // For statistics and easier debugging in case of problems, Wiimmfi + // wants to know what patcher a game has been patched with, thus, + // let the game know the exact USB-Loader version. Max length 42 + // chars, padded with whitespace, without null terminator + char * fmt = "%s v%-50s"; + char patcher[100] = {0}; + snprintf((char *)&patcher, 99, fmt, APP_NAME, APP_VERSION); + strncpy(patched, (char *)&patcher, 42); + + // Do the plain old patching with the string search + PrivateServerPatcher((void*)0x80004000, 0x385200); + + // Replace some URLs for Wiimmfi's new update system + char newURL1[] = "http://ca.nas.wiimmfi.de/ca"; + char newURL2[] = "http://naswii.wiimmfi.de/ac"; + char newURL3P[] = "https://main.nas.wiimmfi.de/pp"; + char newURL3E[] = "https://main.nas.wiimmfi.de/pe"; + char newURL3J[] = "https://main.nas.wiimmfi.de/pj"; + char newURL3K[] = "https://main.nas.wiimmfi.de/pk"; + + + // Write the URLs to the proper place and do some other patching. + switch (region) { + case 'P': + memcpy((void*)0x8027A400, newURL1, sizeof(newURL1)); + memcpy((void*)0x8027A400 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x8027A400 + 0x4C, newURL3P, sizeof(newURL3P)); + *(u32*)0x802a146c = 0x733a2f2f; + *(u32*)0x800ecaac = 0x3bc00000; + break; + case 'E': + memcpy((void*)0x802760C0, newURL1, sizeof(newURL1)); + memcpy((void*)0x802760C0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x802760C0 + 0x4C, newURL3E, sizeof(newURL3E)); + *(u32*)0x8029D12C = 0x733a2f2f; + *(u32*)0x800ECA0C = 0x3bc00000; + break; + case 'J': + memcpy((void*)0x80279DA0, newURL1, sizeof(newURL1)); + memcpy((void*)0x80279DA0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x80279DA0 + 0x4C, newURL3J, sizeof(newURL3J)); + *(u32*)0x802A0E0C = 0x733a2f2f; + *(u32*)0x800EC9CC = 0x3bc00000; + break; + case 'K': + memcpy((void*)0x802682B0, newURL1, sizeof(newURL1)); + memcpy((void*)0x802682B0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x802682B0 + 0x4C, newURL3K, sizeof(newURL3K)); + *(u32*)0x8028F474 = 0x733a2f2f; + *(u32*)0x800ECB24 = 0x3bc00000; + break; + } + + // Make some space on heap (0x400) for our custom code. + u32 old_heap_ptr = *(u32*)0x80003110; + *((u32*)0x80003110) = (old_heap_ptr - 0x400); + u32 heap_space = old_heap_ptr-0x400; + memset((void*)old_heap_ptr-0x400, 0xed, 0x400); + + // Binary blobs with Wiimmfi patches. Do not modify. + // Provided by Leseratte on 2018-12-14. + + int binary[] = { 0x37C849A2, 0x8BC32FA4, 0xC9A34B71, 0x1BCB49A2, + 0x2F119304, 0x5F402684, 0x3E4FDA29, 0x50849A21, + 0xB88B3452, 0x627FC9C1, 0xDC24D119, 0x5844350F, + 0xD893444F, 0x19A588DC, 0x16C91184, 0x0C3E237C, + 0x75906CED, 0x6E68A55E, 0x58791842, 0x072237E9, + 0xAB24906F, 0x0A8BDF21, 0x4D11BE42, 0x1AAEDDC8, + 0x1C42F908, 0x280CF2B2, 0x453A1BA4, 0x9A56C869, + 0x786F108E, 0xE8DF05D2, 0x6DB641EB, 0x6DFC84BB, + 0x7E980914, 0x0D7FB324, 0x23442185, 0xA7744966, + 0x53901359, 0xBF2103CC, 0xC24A4EB7, 0x32049A02, + 0xC1683466, 0xCA93689D, 0xD8245106, 0xA84987CF, + 0xEC9B47C9, 0x6FA688FE, 0x0A4D11A6, 0x8B653C7B, + 0x09D27E30, 0x5B936208, 0x5DD336DE, 0xCD092487, + 0xEF2C6D36, 0x1E09DF2D, 0x75B1BE47, 0xE68A7F22, + 0xB0E5F90D, 0xEC49F216, 0xAD1DCC24, 0xE2B5C841, + 0x066F6F63, 0xF4D90926, 0x299F42CD, 0xA3F125D6, + 0x077B093C, 0xB5721268, 0x1BE424D1, 0xEBC30BF0, + 0x77867BED, 0x4F0C9BCA, 0x3E195930, 0xDC32DE2C, + 0x1865D189, 0x70C67E7A, 0x71FA7329, 0x532233D3, + 0x06D2E87B, 0x6CBEBA7F, 0x99F08532, 0x52FA601C, + 0x05F4B82C, 0x4B64839C, 0xB5C65009, 0x1B8396E3, + 0x0A8B2DAF, 0x0DB85BE6, 0x12F1B71D, 0x186F6E4D, + 0x2870DC2E, 0x5960B8E6, 0x8F4D71BD, 0x0614E3C3, + 0x05E8C725, 0x365D8E3D, 0x74351CDE, 0xE1AB3930, + 0xFEDA721B, 0xE53AE4E9, 0xC3B4C9A6, 0xBAE59346, + 0x6D45269D, 0x634E4D1A, 0x2FD99A30, 0x26393449, + 0xE49768D1, 0x81E1D1A1, 0xFCE1A34A, 0x7EB44697, + 0xEB2F8D2D, 0xCECFE5AF, 0x81BD34B6, 0xB1F1696E, + 0x5E6ED2B2, 0xA473A4A0, 0x41664B70, 0xBF40968A, + 0x662F2CCB, 0xC5DF5B8C, 0xB632B772, 0x74EB6F39, + 0xE017DC71, 0xFDA3B890, 0xE3C9713D, 0xCE53E397, + 0xA12BC743, 0x5AD98EA5, 0xBC721C9F, 0x4568395A, + 0x925E72B4, 0x2D7DE4D7, 0x6777C9C7, 0xD6619396, + 0xA502268A, 0x77884D75, 0xF79E9AF0, 0xE6FC3461, + 0xF07468A5, 0xF866D11D, 0xF90CA342, 0xCF9546FF, + 0x87A48D81, 0x06881A51, 0x309C34D1, 0x79B669CE, + 0xFAADD2D7, 0xC8D7A5D1, 0x89214BE5, 0x1B8396EF, + 0x0A8B2DE9, 0x0D985B06, 0x12F1B711, 0x186F6E57, + 0x2850DC0E, 0x5960B8EA, 0x8F4D71AC, 0x0614E3E3, + 0x05E8C729, 0x365D8E39, 0x74351CFE, 0x518E3943, + 0x4A397268, 0x9D58E4B8, 0xD394C9A2, 0x0E069344, + 0xB522268B, 0x636E4D77, 0x2FF99A37, 0xF6DC346D, + 0xE49268B4, 0x2001D1A0, 0x4929A365, 0x7B764691, + 0xFFC68D49, 0x16A81A53, 0x247A34D2, 0xA1D16967, + 0x4B6DD2D5, 0xDDF4A5B7, 0x454A4B70, 0x0FAE96E2, + 0x0A8A2DC7, 0x0D98A47A, 0x06DCB71D, 0x0CCC6E38, + 0x55F25CFB, 0xB08C1E88, 0xDF4259C9, 0x0714E387, + 0xB00D47AF, 0x7B722975, 0x48BE349A, 0x29CC393C, + 0xEA797228, 0x98986471, 0x3778E1A3, 0xD7626D06, + 0x1567268D, 0x668ECD00, 0xD614F5C8, 0x133037CF, + 0x92F26CF2, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000}; + + // Prepare patching process .... + int i = 3; + int idx = 0; + for (; i < 202; i++) { + if (i == 67 || i == 82) idx++; + binary[i] = binary[i] ^ binary[idx]; + binary[idx] = ((binary[idx] << 1) | ((binary[idx] >> (32 - 1)) & ~(-1 << 1))); + } + + + // Binary blob needs some changes for regions other than PAL ... + switch (region) { + case 'E': + binary[29] = binary[67]; + binary[37] = binary[68]; + binary[43] = binary[69]; + binary[185] = 0x61295C74; + binary[189] = 0x61295D40; + binary[198] = 0x61086F5C; + break; + case 'J': + binary[29] = binary[70]; + binary[37] = binary[71]; + binary[43] = binary[72]; + binary[185] = 0x612997CC; + binary[189] = 0x61299898; + binary[198] = 0x61086F1C; + break; + case 'K': + binary[6] = binary[73]; + binary[9] = binary[74]; + binary[11] = binary[75]; + binary[23] = binary[76]; + binary[29] = binary[77]; + binary[33] = binary[78]; + binary[37] = binary[79]; + binary[43] = binary[80]; + binary[63] = binary[81]; + binary[184] = 0x3D208088; + binary[185] = 0x61298AA4; + binary[188] = 0x3D208088; + binary[189] = 0x61298B58; + binary[198] = 0x61087358; + break; + } + + // Installing all the patches. + + memcpy((void*)heap_space, (void*)binary, 820); + u32 code_offset_1 = heap_space + 12; + u32 code_offset_2 = heap_space + 88; + u32 code_offset_3 = heap_space + 92; + u32 code_offset_4 = heap_space + 264; + u32 code_offset_5 = heap_space + 328; + + + *((u32*)patch1_offset) = 0x48000000 + (((u32)(code_offset_1) - ((u32)(patch1_offset))) & 0x3ffffff); + *((u32*)code_offset_2) = 0x48000000 + (((u32)(patch1_offset + 4) - ((u32)(code_offset_2))) & 0x3ffffff); + *((u32*)patch2_offset) = 0x48000000 + (((u32)(code_offset_3) - ((u32)(patch2_offset))) & 0x3ffffff); + *((u32*)code_offset_4) = 0x48000000 + (((u32)(patch2_offset + 4) - ((u32)(code_offset_4))) & 0x3ffffff); + *((u32*)patch3_offset) = 0x48000000 + (((u32)(code_offset_5) - ((u32)(patch3_offset))) & 0x3ffffff); + + // Patches successfully installed + // returns 0 when all patching is done and game is ready to be booted. + return 0; +} diff --git a/resources/wiiflow_game_booter/source/patchcode.h b/resources/wiiflow_game_booter/source/patchcode.h index 74b80c85..a53ca8f6 100644 --- a/resources/wiiflow_game_booter/source/patchcode.h +++ b/resources/wiiflow_game_booter/source/patchcode.h @@ -40,6 +40,7 @@ bool PatchReturnTo(void *Address, int Size, u32 id); void Patch_fwrite(void *Address, int Size); s32 BlockIOSReload(void); void PatchRegion(void *Address, int Size); +u32 do_new_wiimmfi(); void PrivateServerPatcher(void *addr, u32 len); void domainpatcher(void *addr, u32 len, const char* domain); diff --git a/source/menu/menu_config_game.cpp b/source/menu/menu_config_game.cpp index fed56667..33f6f4f9 100644 --- a/source/menu/menu_config_game.cpp +++ b/source/menu/menu_config_game.cpp @@ -1118,7 +1118,7 @@ void CMenu::_textGameSettings(void) m_btnMgr.setText(m_gameSettingsLblFlashSave, _t("cfgg32", L"Flash Save to NAND")); m_btnMgr.setText(m_gameSettingsBtnFlashSave, _t("cfgg33", L"Flash")); - m_btnMgr.setText(m_gameSettingsLblPrivateServer, _t("cfgg45", L"Private Server")); + m_btnMgr.setText(m_gameSettingsLblPrivateServer, _t("cfgg45", L"Private Server (Wiimmfi)")); m_btnMgr.setText(m_gameSettingsLblWidth, _t("cfgg54", L"Video Width")); m_btnMgr.setText(m_gameSettingsLblPos, _t("cfgg55", L"Video Position")); } diff --git a/wii/wiiflow/Languages/english.ini b/wii/wiiflow/Languages/english.ini index d21b9d66..48536c5b 100644 --- a/wii/wiiflow/Languages/english.ini +++ b/wii/wiiflow/Languages/english.ini @@ -140,7 +140,7 @@ cfgg41=Manage cfgg42=USB-HID Controller cfgg43=Native Control cfgg44=Video Deflicker -cfgg45=Private Server +cfgg45=Private Server (Wiimmfi) cfgg46=WiiU Widescreen cfgg47=Emulated MemCard cfgg48=Triforce Arcade Mode diff --git a/wii/wiiflow/Languages/german.ini b/wii/wiiflow/Languages/german.ini index f1729b34..dd3985e2 100644 --- a/wii/wiiflow/Languages/german.ini +++ b/wii/wiiflow/Languages/german.ini @@ -139,7 +139,7 @@ cfgg41=Einstellen cfgg42=USB-HID-Controller cfgg43=Native Control cfgg44=Video-Deflicker -cfgg45=Privater Server +cfgg45=Privater Server (Wiimmfi) cfgg46=Wii U Widescreen cfgg47=Emulierte MemCard cfgg48=Triforce Arcade Modus diff --git a/wii/wiiflow/Languages/italian.ini b/wii/wiiflow/Languages/italian.ini index 290545d5..82cd709d 100644 --- a/wii/wiiflow/Languages/italian.ini +++ b/wii/wiiflow/Languages/italian.ini @@ -134,7 +134,7 @@ cfgg41=Gestisci cfgg42=Controller USB-HID cfgg43=Controlli nativi cfgg44=Video Deflicker -cfgg45=Server Privato +cfgg45=Server Privato (Wiimmfi) cfgg46=WiiU Widescreen cfgg47=MemCard emulata cfgg48=Modalità Triforce Arcade diff --git a/wii/wiiflow/Languages/korean.ini b/wii/wiiflow/Languages/korean.ini index 05a12f82..e1e1eac6 100644 --- a/wii/wiiflow/Languages/korean.ini +++ b/wii/wiiflow/Languages/korean.ini @@ -140,7 +140,7 @@ cfgg41=관리 cfgg42=USB-HID 컨트롤러 cfgg43=네이티브 컨트롤 cfgg44=비디오 디플리커 -cfgg45=사설 서버 +cfgg45=사설 서버 (Wiimmfi) cfgg46=WiiU 와이드스크린 cfgg47=에뮬레이트 된 메모리카드 cfgg48=트라이포스 아케이드 모드 diff --git a/wii/wiiflow/Languages/spanish.ini b/wii/wiiflow/Languages/spanish.ini index 2a5e520a..8daa4ce5 100644 --- a/wii/wiiflow/Languages/spanish.ini +++ b/wii/wiiflow/Languages/spanish.ini @@ -116,7 +116,7 @@ cfgg41=Gestionar cfgg42=Control USB-HID cfgg43=Control nativo cfgg44=Antiparpadeo de video -cfgg45=Servidor privado +cfgg45=Servidor privado (Wiimmfi) cfgg46=Pantalla ancha en WiiU cfgg47=Memoria emulada cfgg48=Modo arcade Triforce @@ -455,4 +455,4 @@ wifiplayers= jugadores WiFi wii=Wii wiichannels=Canales de Wii oficiales wiiware=WiiWare -wiiu=Menú de Wii U \ No newline at end of file +wiiu=Menú de Wii U