mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-29 07:37:03 +00:00
olv/hle: Functioning Miiverse applet (#1747)
This commit is contained in:
parent
42da9712a9
commit
7dd0b90f53
8 changed files with 138 additions and 19 deletions
|
|
@ -524,6 +524,10 @@ void Account::ParseFile(class FileStream* file)
|
|||
m_country = ConvertString<uint32>(value, 16);
|
||||
else if (key == "SimpleAddressId")
|
||||
m_simple_address_id = ConvertString<uint32>(value, 16);
|
||||
else if (key == "TimeZoneId")
|
||||
m_timezone_id = value;
|
||||
else if (key == "UtcOffset")
|
||||
m_utc_offset = ConvertString<uint64>(value, 16);
|
||||
else if (key == "PrincipalId")
|
||||
m_principal_id = ConvertString<uint32>(value, 16);
|
||||
else if (key == "IsPasswordCacheEnabled")
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ public:
|
|||
[[nodiscard]] std::string_view GetEmail() const { return m_email; }
|
||||
[[nodiscard]] uint32 GetCountry() const { return m_country; }
|
||||
[[nodiscard]] uint32 GetSimpleAddressId() const { return m_simple_address_id; }
|
||||
[[nodiscard]] std::string_view GetTimeZoneId() const { return m_timezone_id; }
|
||||
[[nodiscard]] sint64 GetUtcOffset() const { return m_utc_offset; }
|
||||
[[nodiscard]] uint32 GetPrincipalId() const { return m_principal_id; }
|
||||
[[nodiscard]] bool IsPasswordCacheEnabled() const { return m_password_cache_enabled != 0; }
|
||||
[[nodiscard]] const std::array<uint8, 32>& GetAccountPasswordCache() const { return m_account_password_cache; }
|
||||
|
|
@ -90,6 +92,8 @@ public:
|
|||
void SetGender(uint8 gender) { m_gender = gender; }
|
||||
void SetEmail(std::string_view email) { m_email = email; }
|
||||
void SetCountry(uint32 country) { m_country = country; }
|
||||
void SetTimeZoneId(std::string_view timezone_id) { m_timezone_id = timezone_id; }
|
||||
void SetUtcOffset(sint64 utc_offset) { m_utc_offset = utc_offset; }
|
||||
|
||||
// this will always return at least one account (default one)
|
||||
static const std::vector<Account>& RefreshAccounts();
|
||||
|
|
@ -123,6 +127,8 @@ private:
|
|||
std::string m_email;
|
||||
uint32 m_country = 0;
|
||||
uint32 m_simple_address_id = 0;
|
||||
std::string m_timezone_id;
|
||||
sint64 m_utc_offset;
|
||||
uint32 m_principal_id = 0;
|
||||
uint8 m_password_cache_enabled = 0;
|
||||
std::array<uint8, 32> m_account_password_cache{};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "Cafe/OS/RPL/rpl.h"
|
||||
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
|
||||
#include "CafeSystem.h"
|
||||
#include "config/ActiveSettings.h" // Selectively add some patches based on network settings.
|
||||
|
||||
void hleExport_breathOfTheWild_busyLoop(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
|
|
@ -268,6 +269,16 @@ static_assert(sizeof(bayo2_audioQueueFixSignature) == sizeof(bayo2_audioQueueFix
|
|||
|
||||
uint8 cars3_avro_schema_incref[] = { 0x2C,0x03,0x00,0x00,0x94,0x21,0xFF,0xE8,0x41,0x82,0x00,0x40,0x39,0x03,0x00,0x08,0x39,0x41,0x00,0x08,0x91,0x01,0x00,0x08,0x7D,0x80,0x50,0x28,0x2C,0x0C,0xFF,0xFF,0x41,0x82,0x00,0x28,0x39,0x21,0x00,0x0C,0x38,0x0C,0x00,0x01,0x38,0xE0,0x00,0x01,0x91,0x01,0x00,0x0C,0x7C,0x00,0x49,0x2D };
|
||||
|
||||
// For USA titles: 000500301001610a / 000500301001410a
|
||||
uint8 miiverse_eshop_url_match_whitelist_func[] = {
|
||||
// For both titles, the code fully matches with the relative
|
||||
// branch targets, even if the absolute targets are different.
|
||||
0x89,0x45,0x00,0x00, // lbz r10, 0x0(r5)
|
||||
0x2c,0x0a,0x00,0x2e, // cmpwi r10, 0x2e
|
||||
0x40,0x82,0x00,0x08, // bne LAB_020ff3a8
|
||||
0x4b,0xff,0xff,0x5c // b FUN_020ff300
|
||||
};
|
||||
uint8 wave_libopenssl_ssl_verify_cert_chain[] = { 0x94,0x21,0xff,0x58,0x93,0xc1,0x00,0xa0,0x93,0xe1,0x00,0xa4,0x7c,0x9f,0x23,0x79,0x7c,0x7e,0x1b,0x78,0x90,0x01,0x00,0xac,0x41,0x82,0x00,0x14,0x7f,0xe3,0xfb,0x78 }; // rpl function for the above applets
|
||||
|
||||
sint32 hleIndex_h000000001 = -1;
|
||||
sint32 hleIndex_h000000002 = -1;
|
||||
|
|
@ -461,6 +472,36 @@ void GamePatch_scan()
|
|||
memory_writeU32(hleAddr + 0x64, 0x60000000);
|
||||
}
|
||||
|
||||
// Patch function in Miiverse/eShop wave.rpx that matches
|
||||
// a domain against another to validate its whitelist.
|
||||
// This allows those browsers to load any domain.
|
||||
const NetworkService service = ActiveSettings::GetNetworkService();
|
||||
if (service != NetworkService::Nintendo // Only patch for custom services.
|
||||
&& CafeSystem::GetForegroundTitleArgStr().ends_with("wave.rpx")
|
||||
&& (hleAddr = hle_locate(miiverse_eshop_url_match_whitelist_func,
|
||||
nullptr, sizeof(miiverse_eshop_url_match_whitelist_func))))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Patching Miiverse/eShop whitelist check at: 0x{:08x}", hleAddr);
|
||||
// Always return 1. (Note that the matched pattern is not at the beginning but still works)
|
||||
memory_writeU32(hleAddr, 0x38600001);
|
||||
memory_writeU32(hleAddr + 0x4, 0x4e800020);
|
||||
// Note that the same applies to Account Settings, but
|
||||
// its version of this function differs a lot.
|
||||
// Search: 88 0c ff ff 2c 00 00 2e (lbz r0,-0x1(r12); cmpwi r0,0x2e)
|
||||
}
|
||||
|
||||
// Additionally patch out SSL checks for libopenssl.rpl, used by the browser.
|
||||
if (IsNetworkServiceSSLDisabled(service)
|
||||
&& RPLLoader_GetHandleByModuleName("libopenssl.rpl") != RPL_INVALID_HANDLE
|
||||
&& (hleAddr = hle_locate(wave_libopenssl_ssl_verify_cert_chain,
|
||||
nullptr, sizeof(wave_libopenssl_ssl_verify_cert_chain))))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Patching OpenSSL ssl_verify_cert_chain at: 0x{:08x}", hleAddr);
|
||||
// Reference: https://github.com/PretendoNetwork/Meowth/blob/meowth/src/patcher/patches/webkit_applets.cpp
|
||||
memory_writeU32(hleAddr + 0x28, 0x60000000);
|
||||
memory_writeU32(hleAddr + 0x40, 0x38600001);
|
||||
}
|
||||
|
||||
uint32 hleInstallEnd = GetTickCount();
|
||||
cemuLog_log(LogType::Force, "HLE scan time: {}ms", hleInstallEnd-hleInstallStart);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ struct actAccountData_t
|
|||
// country & language
|
||||
uint32 countryIndex;
|
||||
char country[8];
|
||||
char timeZoneId[16];
|
||||
sint64 utcOffset;
|
||||
// Mii
|
||||
FFLData_t miiData;
|
||||
uint16le miiNickname[ACT_NICKNAME_LENGTH];
|
||||
|
|
@ -84,6 +86,8 @@ void FillAccountData(const Account& account, const bool online_enabled, int inde
|
|||
// country & language
|
||||
data.countryIndex = account.GetCountry();
|
||||
strcpy(data.country, NCrypto::GetCountryAsString(data.countryIndex));
|
||||
std::copy(account.GetTimeZoneId().cbegin(), account.GetTimeZoneId().cend(), data.timeZoneId);
|
||||
data.utcOffset = account.GetUtcOffset() / 1'000'000;
|
||||
// Mii
|
||||
std::copy(account.GetMiiData().begin(), account.GetMiiData().end(), (uint8*)&data.miiData);
|
||||
std::copy(account.GetMiiName().begin(), account.GetMiiName().end(), data.miiNickname);
|
||||
|
|
@ -808,6 +812,13 @@ int iosuAct_thread()
|
|||
strcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].country);
|
||||
actCemuRequest->setACTReturnCode(0);
|
||||
}
|
||||
else if (actCemuRequest->requestCode == IOSU_ARC_TIMEZONEID)
|
||||
{
|
||||
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
|
||||
_cancelIfAccountDoesNotExist();
|
||||
strcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].timeZoneId);
|
||||
actCemuRequest->setACTReturnCode(0);
|
||||
}
|
||||
else if (actCemuRequest->requestCode == IOSU_ARC_ISNETWORKACCOUNT)
|
||||
{
|
||||
accountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ struct iosuActCemuRequest_t
|
|||
#define IOSU_ARC_MIIDATA 0x0A
|
||||
#define IOSU_ARC_ACQUIREINDEPENDENTTOKEN 0x0B
|
||||
#define IOSU_ARC_ACQUIREPIDBYNNID 0x0C
|
||||
#define IOSU_ARC_TIMEZONEID 0x0D
|
||||
|
||||
uint32 iosuAct_getAccountIdOfCurrentAccount();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,22 +15,6 @@ namespace nn
|
|||
{
|
||||
namespace olv
|
||||
{
|
||||
struct PortalAppParam_t
|
||||
{
|
||||
/* +0x1A663B */ char serviceToken[32]; // size is unknown
|
||||
};
|
||||
|
||||
void exportPortalAppParam_GetServiceToken(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
// r3 = PortalAppParam
|
||||
ppcDefineParamTypePtr(portalAppParam, PortalAppParam_t, 0);
|
||||
|
||||
strcpy(portalAppParam->serviceToken, "servicetoken");
|
||||
// this token is probably just the act IndependentServiceToken for the Miiverse title?
|
||||
|
||||
osLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(&portalAppParam->serviceToken));
|
||||
}
|
||||
|
||||
static SysAllocator<OSThread_t> s_OlvReleaseBgThread;
|
||||
SysAllocator<uint8, 1024> s_OlvReleaseBgThreadStack;
|
||||
SysAllocator<char, 32> s_OlvReleaseBgThreadName;
|
||||
|
|
@ -126,8 +110,6 @@ namespace nn
|
|||
|
||||
cafeExportRegisterFunc(GetErrorCode, "nn_olv", "GetErrorCode__Q2_2nn3olvFRCQ2_2nn6Result", LogType::NN_OLV);
|
||||
|
||||
osLib_addFunction("nn_olv", "GetServiceToken__Q4_2nn3olv6hidden14PortalAppParamCFv", exportPortalAppParam_GetServiceToken);
|
||||
|
||||
cafeExportRegisterFunc(StubPostApp, "nn_olv", "UploadPostDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv28UploadPostDataByPostAppParam", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(StubPostApp, "nn_olv", "UploadCommentDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv31UploadCommentDataByPostAppParam", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(StubPostApp, "nn_olv", "UploadDirectMessageDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv37UploadDirectMessageDataByPostAppParam", LogType::NN_OLV);
|
||||
|
|
|
|||
|
|
@ -277,6 +277,21 @@ namespace nn
|
|||
return OLV_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
sint32 InitializePortalApp(nn::olv::PortalAppParam* pPortalAppParam, nn::olv::InitializeParam* pInitializeParam)
|
||||
{
|
||||
sint32 result = Initialize(pInitializeParam);
|
||||
if (result != OLV_RESULT_SUCCESS)
|
||||
return result;
|
||||
|
||||
memcpy(pPortalAppParam->m_ParamPack, g_ParamPack.encodedParamPack, sizeof(g_ParamPack.encodedParamPack));
|
||||
memcpy(pPortalAppParam->m_ServiceToken, g_DiscoveryResults.serviceToken, sizeof(g_DiscoveryResults.serviceToken));
|
||||
|
||||
snprintf(reinterpret_cast<char*>(pPortalAppParam->m_StartUrl), sizeof(pPortalAppParam->m_StartUrl),
|
||||
"%s/titles/show?src=menu", g_DiscoveryResults.portalEndpoint);
|
||||
|
||||
return OLV_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
namespace Report
|
||||
{
|
||||
uint32 GetReportTypes()
|
||||
|
|
@ -295,4 +310,4 @@ namespace nn
|
|||
return g_IsInitialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -101,6 +101,58 @@ namespace nn
|
|||
};
|
||||
static_assert(sizeof(nn::olv::InitializeParam) == 0x40, "sizeof(nn::olv::InitializeParam) != 0x40");
|
||||
|
||||
class PortalAppParam
|
||||
{
|
||||
public:
|
||||
PortalAppParam()
|
||||
{
|
||||
m_ParamPack[0] = 0;
|
||||
m_ServiceToken[0] = 0;
|
||||
m_StartUrl[0] = 0;
|
||||
}
|
||||
static PortalAppParam* __ctor(PortalAppParam* _this)
|
||||
{
|
||||
if (!_this)
|
||||
{
|
||||
assert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
return new (_this) PortalAppParam();
|
||||
}
|
||||
|
||||
uint8be* GetParamPack()
|
||||
{
|
||||
return m_ParamPack;
|
||||
}
|
||||
static uint8be* __GetParamPack(PortalAppParam* _this)
|
||||
{
|
||||
return _this->GetParamPack();
|
||||
}
|
||||
|
||||
uint8be* GetServiceToken()
|
||||
{
|
||||
return m_ServiceToken;
|
||||
}
|
||||
static uint8be* __GetServiceToken(PortalAppParam* _this)
|
||||
{
|
||||
return _this->GetServiceToken();
|
||||
}
|
||||
|
||||
uint8be* GetStartUrl()
|
||||
{
|
||||
return m_StartUrl;
|
||||
}
|
||||
static uint8be* __GetStartUrl(PortalAppParam* _this)
|
||||
{
|
||||
return _this->GetStartUrl();
|
||||
}
|
||||
|
||||
public:
|
||||
/* +0x1A5C3C */ uint8be m_ParamPack[0x200];
|
||||
/* +0x1A663B */ uint8be m_ServiceToken[0x201]; // IndependentServiceToken for Miiverse title
|
||||
/* +0x1A5E3C */ uint8be m_StartUrl[0x7ff]; // https://portal-us.olv.nintendo.net/titles/show?src=menu
|
||||
};
|
||||
|
||||
namespace Report
|
||||
{
|
||||
|
|
@ -110,6 +162,7 @@ namespace nn
|
|||
|
||||
bool IsInitialized();
|
||||
sint32 Initialize(nn::olv::InitializeParam* pParam);
|
||||
sint32 InitializePortalApp(nn::olv::PortalAppParam* pPortalAppParam, nn::olv::InitializeParam* pInitializeParam);
|
||||
|
||||
static void loadOliveInitializeTypes()
|
||||
{
|
||||
|
|
@ -123,6 +176,12 @@ namespace nn
|
|||
cafeExportRegisterFunc(InitializeParam::__SetWork, "nn_olv", "SetWork__Q3_2nn3olv15InitializeParamFPUcUi", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(InitializeParam::__SetReportTypes, "nn_olv", "SetReportTypes__Q3_2nn3olv15InitializeParamFUi", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(InitializeParam::__SetSysArgs, "nn_olv", "SetSysArgs__Q3_2nn3olv15InitializeParamFPCvUi", LogType::NN_OLV);
|
||||
|
||||
cafeExportRegisterFunc(InitializePortalApp, "nn_olv", "InitializePortalApp__Q3_2nn3olv6hiddenFPQ4_2nn3olv6hidden14PortalAppParamPCQ3_2nn3olv15InitializeParam", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(PortalAppParam::__ctor, "nn_olv", "__ct__Q4_2nn3olv6hidden14PortalAppParamFv", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(PortalAppParam::__GetParamPack, "nn_olv", "GetParamPack__Q4_2nn3olv6hidden14PortalAppParamCFv", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(PortalAppParam::__GetServiceToken, "nn_olv", "GetServiceToken__Q4_2nn3olv6hidden14PortalAppParamCFv", LogType::NN_OLV);
|
||||
cafeExportRegisterFunc(PortalAppParam::__GetStartUrl, "nn_olv", "GetStartUrl__Q4_2nn3olv6hidden14PortalAppParamCFv", LogType::NN_OLV);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue