mirror of
https://github.com/PretendoNetwork/GiveMiiYouTube.git
synced 2024-05-18 12:50:43 -04:00
parent
961c94b512
commit
1037e1b119
6
Dockerfile
Normal file
6
Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
|||
FROM wiiuenv/devkitppc:20220806
|
||||
|
||||
COPY --from=wiiuenv/libkernel:20220724 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiupluginsystem:20220826 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR /project
|
13
Makefile
13
Makefile
|
@ -11,6 +11,7 @@ TOPDIR ?= $(CURDIR)
|
|||
include $(DEVKITPRO)/wups/share/wups_rules
|
||||
|
||||
WUT_ROOT := $(DEVKITPRO)/wut
|
||||
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||
#-------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
|
@ -20,9 +21,9 @@ WUT_ROOT := $(DEVKITPRO)/wut
|
|||
#-------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := .
|
||||
SOURCES := source source/patcher
|
||||
DATA := data
|
||||
INCLUDES :=
|
||||
INCLUDES := source
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
|
@ -32,18 +33,18 @@ CFLAGS := -Wall -O2 -ffunction-sections \
|
|||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
||||
|
||||
CXXFLAGS := $(CFLAGS)
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++20
|
||||
|
||||
ASFLAGS := $(ARCH)
|
||||
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
|
||||
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libkernel.ld $(WUPSSPECS)
|
||||
|
||||
LIBS := -lwups -lwut
|
||||
LIBS := -lkernel -lwups -lwut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
# containing include and lib
|
||||
#-------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT)
|
||||
LIBDIRS := $(PORTLIBS) $(WUMS_ROOT) $(WUPS_ROOT) $(WUT_ROOT)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
|
|
19
README.md
19
README.md
|
@ -13,10 +13,21 @@ This endpoint now responds with:
|
|||
The app then checks if acquiring this token has been sucessful and if not it will display the error. The acquired token itself is not used.
|
||||
This is a Wii U Plugin System plugin for Aroma which just makes this request always return sucess and thus allowing the YouTube app to continue functioning.
|
||||
|
||||
## Info about version 2.0
|
||||
On November 1st, 2022 YouTube started returning response 404 for the `WiiU` useragent platform.
|
||||
Since v2.0 this plugin patches the platform in the useragent for the YouTube app to `NoU` instead of `WiiU`, which bypasses this block.
|
||||
|
||||
## Special Thanks to
|
||||
[@ashquarky](https://github.com/ashquarky) for the awesome patcher framework which was taken from [Nimble](https://github.com/PretendoNetwork/Nimble).
|
||||
|
||||
## Building
|
||||
```bash
|
||||
# Build docker image (only needed once)
|
||||
docker build . -t givemiiyoutube_builder
|
||||
|
||||
For building you need:
|
||||
- [wups](https://github.com/wiiu-env/WiiUPluginSystem)
|
||||
- [wut](https://github.com/decaf-emu/wut)
|
||||
# make
|
||||
docker run -it --rm -v ${PWD}:/project givemiiyoutube_builder make
|
||||
|
||||
Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself.
|
||||
# make clean
|
||||
docker run -it --rm -v ${PWD}:/project givemiiyoutube_builder make clean
|
||||
```
|
||||
|
|
21
main.cpp
21
main.cpp
|
@ -1,21 +0,0 @@
|
|||
#include <wups.h>
|
||||
#include <string.h>
|
||||
|
||||
WUPS_PLUGIN_NAME("GiveMiiYouTube");
|
||||
WUPS_PLUGIN_DESCRIPTION("Allows the YouTube app to continue functioning after its discontinuation");
|
||||
WUPS_PLUGIN_VERSION("v1.0");
|
||||
WUPS_PLUGIN_AUTHOR("GaryOderNichts");
|
||||
WUPS_PLUGIN_LICENSE("MIT");
|
||||
|
||||
#define CLIENT_ID_YT "e921a604fce89365498613fdf001b492"
|
||||
|
||||
DECL_FUNCTION(int, AcquireIndependentServiceToken__Q2_2nn3actFPcPCc, uint8_t* token, const char* client_id)
|
||||
{
|
||||
if (strcmp(client_id, CLIENT_ID_YT) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return real_AcquireIndependentServiceToken__Q2_2nn3actFPcPCc(token, client_id);
|
||||
}
|
||||
|
||||
WUPS_MUST_REPLACE(AcquireIndependentServiceToken__Q2_2nn3actFPcPCc, WUPS_LOADER_LIBRARY_NN_ACT, AcquireIndependentServiceToken__Q2_2nn3actFPcPCc);
|
81
source/main.cpp
Normal file
81
source/main.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include <wups.h>
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_udp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <coreinit/title.h>
|
||||
|
||||
#include <patcher/rplinfo.h>
|
||||
#include <patcher/patcher.h>
|
||||
|
||||
WUPS_PLUGIN_NAME("GiveMiiYouTube");
|
||||
WUPS_PLUGIN_DESCRIPTION("Allows the YouTube app to continue functioning after its discontinuation");
|
||||
WUPS_PLUGIN_VERSION("v2.0");
|
||||
WUPS_PLUGIN_AUTHOR("GaryOderNichts");
|
||||
WUPS_PLUGIN_LICENSE("MIT");
|
||||
|
||||
#define YOUTUBE_CLIENT_ID "e921a604fce89365498613fdf001b492"
|
||||
#define YOUTUBE_TITLE_ID 0x0005000010105700llu
|
||||
#define YOUTUBE_USERAGENT_PLATFORM "WiiU; "
|
||||
#define YOUTUBE_USERAGENT_PLATFORM_REPLACEMENT "NoU; "
|
||||
|
||||
ON_APPLICATION_START()
|
||||
{
|
||||
// If this is not the YouTube app no need to do anything
|
||||
if (OSGetTitleID() != YOUTUBE_TITLE_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Init logging
|
||||
if (!WHBLogModuleInit()) {
|
||||
WHBLogCafeInit();
|
||||
WHBLogUdpInit();
|
||||
}
|
||||
|
||||
WHBLogPrintf("GiveMiiYouTube: applying patches...");
|
||||
|
||||
// Patch the dynload functions so GetRPLInfo works
|
||||
if (!PatchDynLoadFunctions()) {
|
||||
WHBLogPrintf("GiveMiiYouTube: Failed to patch dynload functions");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the RPLInfo
|
||||
auto rpl_info = TryGetRPLInfo();
|
||||
if (!rpl_info) {
|
||||
WHBLogPrintf("GiveMiiYouTube: Failed to get RPL info");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the rpx
|
||||
rplinfo rpls = *rpl_info;
|
||||
auto lb_shell_rpx = FindRPL(rpls, "lb_shell.rpx");
|
||||
if (!lb_shell_rpx) {
|
||||
WHBLogPrintf("GiveMiiYouTube: Failed to find lb_shell.rpx");
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch the useragent platform
|
||||
OSDynLoad_NotifyData rpx_data = *lb_shell_rpx;
|
||||
if (!replace_string(rpx_data.dataAddr, rpx_data.dataSize,
|
||||
YOUTUBE_USERAGENT_PLATFORM, sizeof(YOUTUBE_USERAGENT_PLATFORM),
|
||||
YOUTUBE_USERAGENT_PLATFORM_REPLACEMENT, sizeof(YOUTUBE_USERAGENT_PLATFORM_REPLACEMENT))) {
|
||||
WHBLogPrintf("GiveMiiYouTube: Failed to replace useragent platform");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int, AcquireIndependentServiceToken__Q2_2nn3actFPcPCc, uint8_t* token, const char* client_id)
|
||||
{
|
||||
// If this is the YouTube client, return sucess
|
||||
if (client_id && strcmp(client_id, YOUTUBE_CLIENT_ID) == 0) {
|
||||
WHBLogPrintf("GiveMiiYouTube: Faking service sucess for '%s'", client_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return real_AcquireIndependentServiceToken__Q2_2nn3actFPcPCc(token, client_id);
|
||||
}
|
||||
|
||||
WUPS_MUST_REPLACE(AcquireIndependentServiceToken__Q2_2nn3actFPcPCc, WUPS_LOADER_LIBRARY_NN_ACT, AcquireIndependentServiceToken__Q2_2nn3actFPcPCc);
|
20
source/patcher/patcher.cpp
Normal file
20
source/patcher/patcher.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "patcher.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
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++) {
|
||||
int ret = memcmp(original_val, (void*)addr, original_val_sz);
|
||||
if (ret == 0) {
|
||||
DEBUG_FUNCTION_LINE("found str @%08x: %s", addr, (const char*)addr);
|
||||
KernelCopyData(OSEffectiveToPhysical(addr), OSEffectiveToPhysical((uint32_t)new_val), new_val_sz);
|
||||
DEBUG_FUNCTION_LINE("new str @%08x: %s", addr, (const char*)addr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
6
source/patcher/patcher.h
Normal file
6
source/patcher/patcher.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
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);
|
70
source/patcher/rplinfo.cpp
Normal file
70
source/patcher/rplinfo.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "rplinfo.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
std::optional<std::vector<OSDynLoad_NotifyData>> TryGetRPLInfo() {
|
||||
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
||||
if (num_rpls == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("num_rpls: %d", num_rpls);
|
||||
|
||||
std::vector<OSDynLoad_NotifyData> rpls;
|
||||
rpls.resize(num_rpls);
|
||||
|
||||
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
||||
if (!ret) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!PatchInstruction(patch1, 0x41820038 /* beq +38 */, 0x60000000 /*nop*/)) {
|
||||
return false;
|
||||
}
|
||||
if (!PatchInstruction(patch2, 0x41820100 /* beq +100 */, 0x60000000 /*nop*/)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
31
source/patcher/rplinfo.h
Normal file
31
source/patcher/rplinfo.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
using rplinfo = std::vector<OSDynLoad_NotifyData>;
|
||||
|
||||
std::optional<rplinfo> TryGetRPLInfo();
|
||||
bool PatchDynLoadFunctions();
|
||||
|
||||
constexpr inline std::optional<OSDynLoad_NotifyData> FindRPL(const rplinfo& rpls, const std::string& name) {
|
||||
auto res = std::find_if(rpls.cbegin(), rpls.cend(), [&](const OSDynLoad_NotifyData& data){ return std::string(data.name).ends_with(name); });
|
||||
if (res == rpls.cend()) return std::nullopt;
|
||||
return *res;
|
||||
}
|
30
source/utils/logger.h
Normal file
30
source/utils/logger.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
OSFatal_printf("[%s]%s@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);
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue