diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adfbbeb..3af1753 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ -name: Inkay-CI +name: wups-CI on: push jobs: - build-inkay: + build-wups: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: build toolchain container run: docker build . -t builder - uses: ammaraskar/gcc-problem-matcher@master - - name: build Inkay + - name: build WUPS plugin run: docker run --rm -v ${PWD}:/app -w /app builder - uses: actions/upload-artifact@master with: - name: inkay + name: plugin path: "*.wps" diff --git a/.gitignore b/.gitignore index 74caf8d..fa7ebaa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/ /build *.elf +*.wps diff --git a/Inkay-pretendo.wps b/Inkay-pretendo.wps deleted file mode 100644 index 71555e5..0000000 Binary files a/Inkay-pretendo.wps and /dev/null differ diff --git a/Makefile b/Makefile index 1ae0b48..a59b5ca 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ WUMS_ROOT := $(DEVKITPRO)/wums # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files #------------------------------------------------------------------------------- -TARGET := Inkay-pretendo +TARGET := meowth-ssl BUILD := build SOURCES := src src/utils src/patcher src/patcher/patches DATA := data diff --git a/src/main.cpp b/src/main.cpp index 41cc333..72c7797 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -28,50 +27,21 @@ #include #include "wut_extra.h" #include -#include "url_patches.h" #include "patcher/ingame.h" /** Mandatory plugin information. If not set correctly, the loader will refuse to use the plugin. **/ -WUPS_PLUGIN_NAME("Inkay"); -WUPS_PLUGIN_DESCRIPTION("Pretendo Network Patcher"); -WUPS_PLUGIN_VERSION("v2.1"); -WUPS_PLUGIN_AUTHOR("Pretendo contributors"); +WUPS_PLUGIN_NAME("Meowth"); +WUPS_PLUGIN_DESCRIPTION("SSL Patcher"); +WUPS_PLUGIN_VERSION("v0.1"); +WUPS_PLUGIN_AUTHOR("quarky + Pretendo contributors"); WUPS_PLUGIN_LICENSE("ISC"); -WUPS_USE_STORAGE("inkay"); - -bool skipPatches = false; -bool prevSkipValue = false; - #include #include -//thanks @Gary#4139 :p -static void write_string(uint32_t addr, const char* str) -{ - int len = strlen(str) + 1; - int remaining = len % 4; - int num = len - remaining; - - for (int i = 0; i < (num / 4); i++) { - Mocha_IOSUKernelWrite32(addr + i * 4, *(uint32_t*)(str + i * 4)); - } - - if (remaining > 0) { - uint8_t buf[4]; - Mocha_IOSUKernelRead32(addr + num, (uint32_t*)&buf); - - for (int i = 0; i < remaining; i++) { - buf[i] = *(str + num + i); - } - - Mocha_IOSUKernelWrite32(addr + num, *(uint32_t*)&buf); - } -} - static bool is555(MCP_SystemVersion version) { return (version.major == 5) && (version.minor == 5) && (version.patch >= 5); } @@ -79,30 +49,6 @@ static bool is555(MCP_SystemVersion version) { INITIALIZE_PLUGIN() { WHBLogUdpInit(); - WUPSStorageError storageRes = WUPS_OpenStorage(); - if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); - } - else { - // Try to get value from storage - if ((storageRes = WUPS_GetBool(nullptr, "skipPatches", &skipPatches)) == WUPS_STORAGE_ERROR_NOT_FOUND) { - // Add the value to the storage if it's missing. - if (WUPS_StoreBool(nullptr, "skipPatches", skipPatches) != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to store bool"); - } - } - else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); - } - - prevSkipValue = skipPatches; - - // Close storage - if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to close storage"); - } - } - auto res = Mocha_InitLibrary(); if (res != MOCHA_RESULT_SUCCESS) { @@ -124,24 +70,12 @@ INITIALIZE_PLUGIN() { os_version.major, os_version.minor, os_version.patch, os_version.region ); - if (!skipPatches) { - if (is555(os_version)) { - Mocha_IOSUKernelWrite32(0xE1019F78, 0xE3A00001); // mov r0, #1 - } - else { - Mocha_IOSUKernelWrite32(0xE1019E84, 0xE3A00001); // mov r0, #1 - } - - for (const auto& patch : url_patches) { - write_string(patch.address, patch.url); - } - - DEBUG_FUNCTION_LINE("Pretendo URL and NoSSL patches applied successfully."); + // IOS-NSEC SSL patch + if (is555(os_version)) { + Mocha_IOSUKernelWrite32(0xE1019F78, 0xE3A00001); // mov r0, #1 + } else { + Mocha_IOSUKernelWrite32(0xE1019E84, 0xE3A00001); // mov r0, #1 } - else { - DEBUG_FUNCTION_LINE("Pretendo URL and NoSSL patches skipped."); - } - MCP_Close(mcp); } @@ -150,58 +84,9 @@ DEINITIALIZE_PLUGIN() { Mocha_DeInitLibrary(); } -void skipPatchesChanged(ConfigItemBoolean* item, bool newValue) { - DEBUG_FUNCTION_LINE("New value in skipPatchesChanged: %d", newValue); - skipPatches = newValue; - // If the value has changed, we store it in the storage. - WUPS_StoreInt(nullptr, "skipPatches", skipPatches); -} - -WUPS_GET_CONFIG() { - // We open the storage so we can persist the configuration the user did. - if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to open storage"); - return 0; - } - - WUPSConfigHandle config; - WUPSConfig_CreateHandled(&config, "Inkay"); - - WUPSConfigCategoryHandle cat; - WUPSConfig_AddCategoryByNameHandled(config, "Patching", &cat); - - WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, "skipPatches", "Skip Pretendo Network patches", skipPatches, &skipPatchesChanged); - - return config; -} - -bool isRelaunching = false; - -WUPS_CONFIG_CLOSED() { - // Save all changes - if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to close storage"); - } - - if (prevSkipValue != skipPatches) { - if (!isRelaunching) { - // Need to reload the console so the patches reset - OSForceFullRelaunch(); - SYSLaunchMenu(); - isRelaunching = true; - } - } - prevSkipValue = skipPatches; -} - ON_APPLICATION_START() { WHBLogUdpInit(); - - DEBUG_FUNCTION_LINE("Inkay: hewwo!\n"); - - if (!skipPatches) RunPatcher(); + RunPatcher(); } -ON_APPLICATION_ENDS() { - DEBUG_FUNCTION_LINE("Inkay: shutting down...\n"); -} +ON_APPLICATION_ENDS() {} diff --git a/src/patcher/ingame.cpp b/src/patcher/ingame.cpp index 473cd38..a198d58 100644 --- a/src/patcher/ingame.cpp +++ b/src/patcher/ingame.cpp @@ -18,7 +18,7 @@ #include -#include "patches/nn_olv.h" +#include "patches/youtube.h" void RunPatcher() { auto orplinfo = TryGetRPLInfo(); @@ -52,5 +52,5 @@ void RunPatcher() { auto titleVer = __OSGetTitleVersion(); // "always" patches - Patch_nn_olv(titleVer, titleId, rpls); + Patch_youtube(titleVer, titleId, rpls); } diff --git a/src/patcher/patcher.cpp b/src/patcher/patcher.cpp index 1bdfc6c..ebafada 100644 --- a/src/patcher/patcher.cpp +++ b/src/patcher/patcher.cpp @@ -4,6 +4,7 @@ #include #include +#include bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz) { for (uint32_t addr = start; addr < start + size - original_val_sz; addr++) { @@ -18,3 +19,19 @@ bool replace_string(uint32_t start, uint32_t size, const char* original_val, siz return false; } + +bool PatchInstruction(void* instr, uint32_t original, uint32_t replacement) { + uint32_t current = *(uint32_t*)instr; + DEBUG_FUNCTION_LINE("current instr %08x", current); + if (current != original) return current == replacement; + + KernelCopyData(OSEffectiveToPhysical((uint32_t)instr), OSEffectiveToPhysical((uint32_t)&replacement), sizeof(replacement)); + //Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead + DCFlushRange(instr, 4); + ICInvalidateRange(instr, 4); + + current = *(uint32_t*)instr; + DEBUG_FUNCTION_LINE("patched instr %08x", current); + + return true; +} diff --git a/src/patcher/patcher.h b/src/patcher/patcher.h index 4881854..0bfdec2 100644 --- a/src/patcher/patcher.h +++ b/src/patcher/patcher.h @@ -6,4 +6,6 @@ bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz); +bool PatchInstruction(void* instr, uint32_t original, uint32_t replacement); + #endif //INKAY_PATCHER_H diff --git a/src/patcher/patches/nn_olv.cpp b/src/patcher/patches/nn_olv.cpp deleted file mode 100644 index e018130..0000000 --- a/src/patcher/patches/nn_olv.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "nn_olv.h" -#include "utils/logger.h" -#include "patcher/patcher.h" - -#include - -const char original_url[] = "discovery.olv.nintendo.net/v1/endpoint"; -const char new_url[] = "discovery.olv.pretendo.cc/v1/endpoint"; -_Static_assert(sizeof(original_url) > sizeof(new_url), - "new_url too long! Must be less than 38chars."); - -std::optional checkForOlvLibs(const rplinfo& rpls) { - auto res = FindRPL(rpls, "nn_olv.rpl"); - if (res) return res; - - res = FindRPL(rpls, "nn_olv2.rpl"); - if (res) return res; - - return std::nullopt; -} - -void Patch_nn_olv(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls) { - auto olv_rpl = checkForOlvLibs(rpls); - if (!olv_rpl) { - DEBUG_FUNCTION_LINE("olv not loaded?"); - return; - } - - replace_string(olv_rpl->dataAddr, olv_rpl->dataSize, original_url, sizeof(original_url), new_url, sizeof(new_url)); -} diff --git a/src/patcher/patches/nn_olv.h b/src/patcher/patches/nn_olv.h deleted file mode 100644 index f31c773..0000000 --- a/src/patcher/patches/nn_olv.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _TPATCH_NN_OLV_H -#define _TPATCH_NN_OLV_H - -#include "patcher/rplinfo.h" - -void Patch_nn_olv(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls); - -#endif //_TPATCH_NN_OLV_H diff --git a/src/patcher/patches/youtube.cpp b/src/patcher/patches/youtube.cpp new file mode 100644 index 0000000..57b1e88 --- /dev/null +++ b/src/patcher/patches/youtube.cpp @@ -0,0 +1,25 @@ +// +// Created by ash on 24/10/22. +// + +#include "youtube.h" +#include "utils/logger.h" +#include "patcher/patcher.h" + +#include + +void Patch_youtube(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls) { + DEBUG_FUNCTION_LINE("YouTube %016llx v%d", titleId, titleVer); + if (titleId == 0x0005000010105700 && titleVer == 193) { + auto res = FindRPL(rpls, "lb_shell.rpx"); + if (!res) return; + + DEBUG_FUNCTION_LINE("patching..."); + // OpenSSL ssl_verify_cert_chain + PatchInstruction((void*)(res->textAddr + 0x8dfdbc), 0x40820020, 0x60000000); + PatchInstruction((void*)(res->textAddr + 0x8dfdd4), 0x38600000, 0x38600001); + // OpenSSL X509_verify_cert (called by cert_verify_proc_openssl.cc) + PatchInstruction((void*)(res->textAddr + 0x9208e8), 0x9421ffb8, 0x38600001); + PatchInstruction((void*)(res->textAddr + 0x9208ec), 0xbe410010, 0x4e800020); + } +} diff --git a/src/patcher/patches/youtube.h b/src/patcher/patches/youtube.h new file mode 100644 index 0000000..4085d75 --- /dev/null +++ b/src/patcher/patches/youtube.h @@ -0,0 +1,12 @@ +// +// Created by ash on 24/10/22. +// + +#ifndef INKAY_YOUTUBE_H +#define INKAY_YOUTUBE_H + +#include "patcher/rplinfo.h" + +void Patch_youtube(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls); + +#endif //INKAY_YOUTUBE_H diff --git a/src/patcher/rplinfo.cpp b/src/patcher/rplinfo.cpp index f5b7e4f..cc273ea 100644 --- a/src/patcher/rplinfo.cpp +++ b/src/patcher/rplinfo.cpp @@ -14,12 +14,10 @@ #include "rplinfo.h" #include "utils/logger.h" +#include "patcher/patcher.h" #include -#include -#include - std::optional> TryGetRPLInfo() { int num_rpls = OSDynLoad_GetNumberOfRPLs(); if (num_rpls == 0) { @@ -39,22 +37,6 @@ std::optional> TryGetRPLInfo() { return rpls; } -bool PatchInstruction(void* instr, uint32_t original, uint32_t replacement) { - uint32_t current = *(uint32_t*)instr; - DEBUG_FUNCTION_LINE("current instr %08x", current); - if (current != original) return current == replacement; - - KernelCopyData(OSEffectiveToPhysical((uint32_t)instr), OSEffectiveToPhysical((uint32_t)&replacement), sizeof(replacement)); - //Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead - DCFlushRange(instr, 4); - ICInvalidateRange(instr, 4); - - current = *(uint32_t*)instr; - DEBUG_FUNCTION_LINE("patched instr %08x", current); - - return true; -} - bool PatchDynLoadFunctions() { uint32_t *patch1 = ((uint32_t *) &OSDynLoad_GetNumberOfRPLs) + 6; uint32_t *patch2 = ((uint32_t *) &OSDynLoad_GetRPLInfo) + 22; diff --git a/src/url_patches.h b/src/url_patches.h deleted file mode 100644 index 8065f98..0000000 --- a/src/url_patches.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _PATCHER_H -#define _PATCHER_H - -typedef struct URL_Patch -{ - unsigned int address; - char url[80]; -} URL_Patch; - -static const URL_Patch url_patches[] = { - //nim-boss .rodata - {0xE2282550, "http://pushmore.wup.shop.pretendo.cc/pushmore/r/%s"}, - {0xE229A0A0, "http://npns-dev.c.app.pretendo.cc/bst.dat"}, - {0xE229A0D0, "http://npns-dev.c.app.pretendo.cc/bst2.dat"}, - {0xE2281964, "https://tagaya.wup.shop.pretendo.cc/tagaya/versionlist/%s/%s/%s"}, - {0xE22819B4, "https://tagaya.wup.shop.pretendo.cc/tagaya/versionlist/%s/%s/latest_version"}, - {0xE2282584, "http://pushmo.wup.shop.pretendo.cc/pushmo/d/%s/%u"}, - {0xE22825B8, "http://pushmo.wup.shop.pretendo.cc/pushmo/c/%u/%u"}, - {0xE2282DB4, "https://ecs.wup.shop.pretendo.cc/ecs/services/ECommerceSOAP"}, - {0xE22830A0, "https://ecs.wup.shop.pretendo.cc/ecs/services/ECommerceSOAP"}, - {0xE22830E0, "https://nus.wup.shop.pretendo.cc/nus/services/NetUpdateSOAP"}, - {0xE2299990, "nppl.app.pretendo.cc"}, - {0xE229A600, "https://pls.wup.shop.pretendo.cc/pls/upload"}, - {0xE229A6AC, "https://npvk-dev.app.pretendo.cc/reports"}, - {0xE229A6D8, "https://npvk.app.pretendo.cc/reports"}, - {0xE229B1F4, "https://npts.app.pretendo.cc/p01/tasksheet/%s/%s/%s/%s?c=%s&l=%s"}, - {0xE229B238, "https://npts.app.pretendo.cc/p01/tasksheet/%s/%s/%s?c=%s&l=%s"}, - {0xE22AB2D8, "https://idbe-wup.cdn.pretendo.cc/icondata/%02X/%016llX.idbe"}, - {0xE22AB318, "https://idbe-ctr.cdn.pretendo.cc/icondata/%02X/%016llX.idbe"}, - {0xE22AB358, "https://idbe-wup.cdn.pretendo.cc/icondata/%02X/%016llX-%d.idbe"}, - {0xE22AB398, "https://idbe-ctr.cdn.pretendo.cc/icondata/%02X/%016llX-%d.idbe"}, - {0xE22B3EF8, "https://ecs.c.shop.pretendo.cc"}, - {0xE22B3F30, "https://ecs.c.shop.pretendo.cc/ecs/services/ECommerceSOAP"}, - {0xE22B3F70, "https://ias.c.shop.pretendo.cc/ias/services/IdentityAuthenticationSOAP"}, - {0xE22B3FBC, "https://cas.c.shop.pretendo.cc/cas/services/CatalogingSOAP"}, - {0xE22B3FFC, "https://nus.c.shop.pretendo.cc/nus/services/NetUpdateSOAP"}, - {0xE229DE0C, "n.app.pretendo.cc"}, - //nim-boss .bss - {0xE24B8A24, "https://nppl.app.pretendo.cc/p01/policylist/1/1/UNK"}, //bit of a hack - {0xE31930D4, "https://%s%saccount.pretendo.cc/v%u/api/"} - -}; - -#endif