From 2620957aba8b8f7b70744d7f11f7c834b43fb96d Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Wed, 12 Aug 2020 20:28:14 +0700 Subject: [PATCH] An attempt to simulate a fake PSN authentication on Patapon 3 --- Core/HLE/sceNet.cpp | 22 +++ Core/HLE/sceNp.cpp | 332 +++++++++++++++++++++++++++++++++++++++----- Core/HLE/sceNp.h | 261 +++++++++++++++++++++++++++++++++- 3 files changed, 577 insertions(+), 38 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index a631ee09c9..f26f6dee4f 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -44,6 +44,7 @@ #include "Core/HLE/proAdhoc.h" #include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNet.h" +#include "Core/HLE/sceNp.h" #include "Core/Reporting.h" #include "Core/Instance.h" @@ -481,6 +482,27 @@ void __NetApctlCallbacks() } } + // We are temporarily borrowing APctl thread for NpAuth callbacks for testing to simulate authentication + if (!npAuthEvents.empty()) + { + auto args = npAuthEvents.front(); + auto id = &args.data[0]; + auto result = &args.data[1]; + auto argAddr = &args.data[2]; + npAuthEvents.pop_front(); + + delayus = (adhocEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; + + int handlerID = *id - 1; + for (std::map::iterator it = npAuthHandlers.begin(); it != npAuthHandlers.end(); ++it) { + if (it->first == handlerID) { + DEBUG_LOG(SCENET, "NpAuthCallback [HandlerID=%i][RequestID=%d][Result=%d][ArgsPtr=%08x]", it->first, *id, *result, it->second.argument); + // TODO: Update result / args.data[1] with the actual ticket length (or error code?) + hleEnqueueCall(it->second.entryPoint, 3, args.data); + } + } + } + // Must be delayed long enough whenever there is a pending callback. hleDelayResult(0, "Prevent Apctl thread from blocking", delayus); } diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index 70dc77d9c7..639776485d 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -18,14 +18,89 @@ // This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values // to keep games happy anyway. +#include +#include +#include +#include +#include "Core/MemMapHelpers.h" +#include #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceNp.h" +#include -static int sceNpInit(u32 poolsize, u32 poolptr) + +bool npAuthInited = false; +SceNpAuthMemoryStat npAuthMemStat = {}; +std::string serviceId = ""; + +int parentalControl = PARENTAL_CONTROL_ENABLED; +int userAge = 24; // faking user Age to 24 yo +int chatRestriction = 0; // default/initial value on Patapon 3 is 1 (restricted boolean?) +std::string onlineId = "DummyOnlineId"; +std::string avatarUrl = "http://DummyAvatarUrl"; + +std::recursive_mutex npAuthEvtMtx; +std::deque npAuthEvents; +std::map npAuthHandlers; + + +// Tickets data are in big-endian based on captured packets +int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { + if (buffer == nullptr) return 0; + + u16_be sz = (data == nullptr)? static_cast(0): size; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + if (sz>0) memcpy(buffer + 4, data, sz); + + return sz + 4; +} + +int writeTicketStringParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { + if (buffer == nullptr) return 0; + + u16_be sz = (data == nullptr) ? static_cast(0) : size; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + if (sz > 0) { + memset(buffer + 4, 0, sz); + truncate_cpy((char*)buffer + 4, sz, data); + } + return sz + 4; +} + +int writeTicketU32Param(u8* buffer, const u16_be type, const u32_be data) { + if (buffer == nullptr) return 0; + + u16_be sz = 4; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + memcpy(buffer + 4, &data, 4); + + return sz + 4; +} + +int writeTicketU64Param(u8* buffer, const u16_be type, const u64_be data) { + if (buffer == nullptr) return 0; + + u16_be sz = 8; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + memcpy(buffer + 4, &data, sz); + + return sz + 4; +} + +void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { + std::lock_guard npAuthGuard(npAuthEvtMtx); + npAuthEvents.push_back({ id, result, argAddr }); +} + +static int sceNpInit() { - ERROR_LOG(HLE, "UNIMPL %s(%08x, %08x) at %08x", __FUNCTION__, poolsize, poolptr, currentMIPS->pc); + ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); return 0; } @@ -36,16 +111,36 @@ static int sceNpTerm() return 0; } -static int sceNpGetContentRatingFlag() +static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) { - ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + WARN_LOG(HLE, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); + + if (!Memory::IsValidAddress(parentalControlAddr) || !Memory::IsValidAddress(userAgeAddr)) + return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::Write_U32(parentalControl, parentalControlAddr); + Memory::Write_U32(userAge, userAgeAddr); + + return 0; +} + +static int sceNpGetChatRestrictionFlag(u32 flagAddr) +{ + WARN_LOG(HLE, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); + + if (!Memory::IsValidAddress(flagAddr)) + return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::Write_U32(chatRestriction, flagAddr); + return 0; } const HLEFunction sceNp[] = { - {0X857B47D3, &WrapI_UU, "sceNpInit", 'i', "xx" }, + {0X857B47D3, &WrapI_V, "sceNpInit", 'i', "" }, {0X37E1E274, &WrapI_V, "sceNpTerm", 'i', "" }, - {0XBB069A87, &WrapI_V, "sceNpGetContentRatingFlag", 'i', "" }, + {0XBB069A87, &WrapI_UU, "sceNpGetContentRatingFlag", 'i', "xx" }, + {0X1D60AE4B, &WrapI_U, "sceNpGetChatRestrictionFlag", 'i', "x" }, }; void Register_sceNp() @@ -57,69 +152,205 @@ static int sceNpAuthTerm() { // No parameters ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + npAuthInited = false; return 0; } static int sceNpAuthInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(HLE, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); + ERROR_LOG(HLE, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); + npAuthMemStat.npMemSize = poolSize; + npAuthMemStat.npMaxMemSize = poolSize / 2; // Dummy + npAuthMemStat.npFreeMemSize = poolSize - 16; // Dummy. + + npAuthInited = true; + return 0; +} + +static int sceNpAuthGetMemoryStat(u32 memStatAddr) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); + + if (!Memory::IsValidAddress(memStatAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::WriteStruct(memStatAddr, &npAuthMemStat); + return 0; } /* "Authenticating matching server usage license" on Patapon 3. Could be waiting for a state change for eternity? probably need to trigger a callback handler? -unknownPtr seems to be a struct where offset: +TODO: Login to "https://auth.np.ac.playstation.net/nav/auth" based on https://www.psdevwiki.com/ps3/Online_Connections +param seems to be a struct where offset: +00: 32-bit is the size of the struct (ie. 36 bytes), - +04: 32-bit is also a small number (ie. 3) a mode/event/flag enum may be?, + +04: 32-bit is also a small number (ie. 3) a mode/event/flag/version may be?, +08: 32-bit is a pointer to a productId? (ie. "EP9000-UCES01421_00"), +0C: 4x 32-bit reserved? all zero - +1C: 32-bit random data or callback handler? optional handler? seems to be a valid pointer and pointing to a starting point of a function (have a label on the disassembly) + +1C: 32-bit callback handler? optional handler? seems to be a valid pointer and pointing to a starting point of a function (have a label on the disassembly) +20: 32-bit a pointer to a random data (4 to 8-bytes data max? both 2x 32-bit seems to be a valid pointer). optional handler args? return value >= 0 and <0 seems to be stored at a different location by the game (valid result vs error code?) */ -static int sceNpAuthCreateStartRequest(u32 unknownPtr) +static int sceNpAuthCreateStartRequest(u32 paramAddr) { - ERROR_LOG(HLE, "UNIMPL %s(%08x) at %08x", __FUNCTION__, unknownPtr, currentMIPS->pc); - if (!Memory::IsValidAddress(unknownPtr)) - return hleLogError(HLE, -1, "invalid arg"); + WARN_LOG(HLE, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); - u32* params = (u32*)Memory::GetPointer(unknownPtr); - INFO_LOG(HLE, "%s - Product ID: %s", __FUNCTION__, Memory::IsValidAddress(params[2]) ? Memory::GetCharPointer(params[2]):""); - // Forcing callback args to bypass all the proper procedure and attempt to go straight to a fake success, might not works properly tho. - // 1st Arg usually either an ID returned from Create/AddHandler function or an Event ID if the game expecting a sequence of events. - // 2nd Arg seems to be used if not a negative number and exits the handler if it's negative (error code?) - // 3rd Arg seems to be a data (ie. 92 bytes of data?) pointer and tested for null within callback handler (optional callback args?) - if (params[0] >= 32) { - // These callback's args seems to be similar to the args of Adhocctl handler? (ie. event/flag, error, handlerArg) - u32 args[3] = { 0, 0, (params[0] >= 36) ? params[8] : 0 }; - hleEnqueueCall(params[7], 3, args); + if (!Memory::IsValidAddress(paramAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpAuthRequestParameter params = {}; + int size = Memory::Read_U32(paramAddr); + Memory::Memcpy(¶ms, paramAddr, size); + serviceId = Memory::GetCharPointer(params.serviceIdAddr); + + INFO_LOG(HLE, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); + INFO_LOG(HLE, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); + INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); + INFO_LOG(HLE, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); + + u32 retval = 0; + if (params.size >= 32 && params.ticketCbAddr != 0) { + bool foundHandler = false; + + struct NpAuthHandler handler; + memset(&handler, 0, sizeof(handler)); + + while (npAuthHandlers.find(retval) != npAuthHandlers.end()) + ++retval; + + handler.entryPoint = params.ticketCbAddr; + handler.argument = params.cbArgAddr; + + for (std::map::iterator it = npAuthHandlers.begin(); it != npAuthHandlers.end(); it++) { + if (it->second.entryPoint == handler.entryPoint) { + foundHandler = true; + retval = it->first; + break; + } + } + + if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { + npAuthHandlers[retval] = handler; + WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, retval); + } + else { + ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + } + // Patapon 3 will only Abort & Destroy AuthRequest if the ID is larger than 0. Is 0 a valid request id? + retval++; + + // 1st Arg usually either an ID returned from Create/AddHandler function or an Event ID if the game is expecting a sequence of events. + // 2nd Arg seems to be used if not a negative number and exits the handler if it's negative (error code?) + // 3rd Arg seems to be a data (ie. 92 bytes of data?) pointer and tested for null within callback handler (optional callback args?) + u32 ticketLength = 248; // default ticket length? should be updated using the ticket length returned from login + notifyNpAuthHandlers(retval, ticketLength, (params.size >= 36) ? params.cbArgAddr : 0); } - hleDelayResult(0, "give time", 500000); + //hleDelayResult(0, "give time", 500000); + return retval; +} + +// Used within callback of sceNpAuthCreateStartRequest (arg1 = callback's args[0], arg2 = output structPtr?, arg3 = callback's args[1]) +// Is this using request id for Arg1 or cbId? +// JPCSP is using length = 248 for dummy ticket +static int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); + + if (!Memory::IsValidAddress(bufferAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + int result = length; + Memory::Memset(bufferAddr, 0, length); + SceNpTicket ticket = {}; + // Dummy Login ticket returned as Login response. Dummy ticket contents were taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket + ticket.header.version = TICKET_VER_2_1; + ticket.header.size = 0xF0; // size excluding the header + u8* buf = Memory::GetPointer(bufferAddr + sizeof(ticket)); + int ofs = 0; + ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key? + ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, 0x0100); // a flags? + PSPTimeval tv; + __RtcTimeOfDay(&tv); + u64 now = 1000ULL*tv.tv_sec + tv.tv_usec/1000ULL; // in milliseconds, since 1900? + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now); + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now + 10 * 60 * 1000); // now + 10 minutes, expired time? + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_LONG, 0x592e71c546e86859); // seems to be consistent, 8-bytes password hash may be? or related to entitlement? or console id? + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, onlineId.c_str(), 32); // username + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "fr\0\2", 4); // SceNpCountryCode ? ie. "fr" + 00 02 + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, "c9", 4); // 2-char code? related to country/lang code? ie. "c9" + 00 00 + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, serviceId.c_str(), 24); + int status = 0; + if (parentalControl == PARENTAL_CONTROL_ENABLED) { + status |= STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED; + } + status |= (userAge & 0x7F) << 24; + ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, status); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); + ticket.section.type = SECTION_TYPE_BODY; + ticket.section.size = ofs; + Memory::WriteStruct(bufferAddr, &ticket); + SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on ver 2.1 containing 4-chars ASCII + 20-chars ASCII + Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, &footer); + ofs += sizeof(footer); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x34\xcd\x3c\xa9", 4); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); + u8 unknownBytes[36] = {}; + Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, unknownBytes); + + result = ticket.header.size + sizeof(ticket.header); // dummy ticket is 248 bytes + + return result; +} + +// Used within callback of sceNpAuthCreateStartRequest (arg1 = structPtr?, arg2 = callback's args[1], arg3 = DLCcode? ie. "EP9000-UCES01421_00-DLL001", arg4 = Patapon 3 always set to 0?) +// Patapon 3 will loop (for each DLC?) through an array of 4+4 bytes, ID addr (pchar) + result (int). Each loop calls this function using the same ticket addr but use different ID addr (arg3) and store the return value in result field (default/initial = -1) +static int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); + INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); + // Do we return the entitlement through function result? or update the ticket content? or replace the arg3 data with SceNpEntitlement struct? + return 1; // dummy value assuming it's a boolean/flag, since we don't know how to return the entitlement result yet +} + +static int sceNpAuthAbortRequest(int requestId) +{ + WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + // TODO: Disconnect HTTPS connection & cancel the callback event + std::lock_guard npAuthGuard(npAuthEvtMtx); + for (auto it = npAuthEvents.begin(); it != npAuthEvents.end(); ) { + (it->data[0] == requestId) ? it = npAuthEvents.erase(it) : ++it; + } return 0; } -// Used within callback of sceNpAuthCreateStartRequest (arg1 = callback's args[0], arg2 = structPtr?, arg3 = args[1]) -static int sceNpAuthGetTicket(u32 arg1, u32 arg2Ptr, u32 arg3) +static int sceNpAuthDestroyRequest(int requestId) { - ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %d)", __FUNCTION__, arg1, arg2Ptr, arg3); + WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + // Remove callback handler + int handlerID = requestId - 1; + if (npAuthHandlers.find(handlerID) != npAuthHandlers.end()) { + npAuthHandlers.erase(handlerID); + WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + } + else { + ERROR_LOG(SCENET, "%s: Invalid request ID %d", __FUNCTION__, requestId); + } + // Patapon 3 is checking for error code 0x80550402 return 0; } -// Used within callback of sceNpAuthCreateStartRequest (arg1 = structPtr?, arg2 = args[1], arg3 = DLCcode? ie. "EP9000-UCES01421_00-DLL001", arg4 = 0) -static int sceNpAuthGetEntitlementById(u32 arg1Ptr, u32 arg2, u32 arg3Ptr, u32 arg4) -{ - ERROR_LOG(HLE, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, arg1Ptr, arg2, arg3Ptr, arg4); - INFO_LOG(HLE, "%s - Product ID: %s", __FUNCTION__, Memory::IsValidAddress(arg3Ptr) ? Memory::GetCharPointer(arg3Ptr) : ""); - return 0; -} const HLEFunction sceNpAuth[] = { {0X4EC1F667, &WrapI_V, "sceNpAuthTerm", 'i', "" }, {0XA1DE86F8, &WrapI_UUU, "sceNpAuthInit", 'i', "xxx" }, + {0XF4531ADC, &WrapI_U, "sceNpAuthGetMemoryStat", 'i', "x" }, {0XCD86A656, &WrapI_U, "sceNpAuthCreateStartRequest", 'i', "x" }, {0X3F1C1F70, &WrapI_UUU, "sceNpAuthGetTicket", 'i', "xxx" }, {0X6900F084, &WrapI_UUUU, "sceNpAuthGetEntitlementById", 'i', "xxxx" }, + {0XD99455DD, &WrapI_I, "sceNpAuthAbortRequest", 'i', "i" }, + {0X72BB0467, &WrapI_I, "sceNpAuthDestroyRequest", 'i', "i" }, }; void Register_sceNpAuth() @@ -140,9 +371,36 @@ static int sceNpServiceInit(u32 poolSize, u32 stackSize, u32 threadPrio) return 0; } +static int sceNpLookupCreateTransactionCtx(u32 lookupTitleCtxIdAddr) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, Memory::GetCharPointer(lookupTitleCtxIdAddr)); + // Patapon 3 will only Destroy if returned Id > 0. Is 0 a valid id? + return 1; // returning dummy transaction id +} + +// transId: id returned from sceNpLookupCreateTransactionCtx +static int sceNpLookupDestroyTransactionCtx(u32 transId) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d)", __FUNCTION__, transId); + return 0; +} + +// transId: id returned from sceNpLookupCreateTransactionCtx +// Patapon 3 always set Arg5 to 0 +// Addr args have something to do with GameUpdate? +static int sceNpLookupTitleSmallStorage(u32 transId, u32 arg2Addr, u32 arg3, u32 arg4Addr, u32 arg5) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %08x, %08x, %08x)", __FUNCTION__, transId, arg2Addr, arg3, arg4Addr, arg5); + return 0; +} + const HLEFunction sceNpService[] = { - {0X00ACFAC3, &WrapI_V, "sceNpServiceTerm", 'i', "" }, - {0X0F8F5821, &WrapI_UUU, "sceNpServiceInit", 'i', "xxx"}, + {0X00ACFAC3, &WrapI_V, "sceNpServiceTerm", 'i', "" }, + {0X0F8F5821, &WrapI_UUU, "sceNpServiceInit", 'i', "xxx" }, + {0X5494274B, &WrapI_U, "sceNpLookupCreateTransactionCtx", 'i', "x" }, + {0XA670D3A3, &WrapI_U, "sceNpLookupDestroyTransactionCtx", 'i', "x" }, + {0XC76F55ED, &WrapI_UUUUU, "sceNpLookupTitleSmallStorage", 'i', "xxxxx" }, }; void Register_sceNpService() diff --git a/Core/HLE/sceNp.h b/Core/HLE/sceNp.h index 7985a4d739..3c117b33c7 100644 --- a/Core/HLE/sceNp.h +++ b/Core/HLE/sceNp.h @@ -17,7 +17,266 @@ #pragma once +#ifdef _MSC_VER +#pragma pack(push,1) +#endif + +// Based on https://playstationdev.wiki/psvitadevwiki/index.php?title=Error_Codes +#define SCE_NP_ERROR_ALREADY_INITIALIZED 0x80550001 +#define SCE_NP_ERROR_NOT_INITIALIZED 0x80550002 +#define SCE_NP_ERROR_INVALID_ARGUMENT 0x80550003 + +#define SCE_NP_AUTH_ERROR_ALREADY_INITIALIZED 0x80550301 +#define SCE_NP_AUTH_ERROR_NOT_INITIALIZED 0x80550302 +#define SCE_NP_AUTH_ERROR_EINVAL 0x80550303 +#define SCE_NP_AUTH_ERROR_ENOMEM 0x80550304 +#define SCE_NP_AUTH_ERROR_ESRCH 0x80550305 +#define SCE_NP_AUTH_ERROR_EBUSY 0x80550306 +#define SCE_NP_AUTH_ERROR_ABORTED 0x80550307 +#define SCE_NP_AUTH_ERROR_INVALID_SERVICE_ID 0x80550308 +#define SCE_NP_AUTH_ERROR_INVALID_CREDENTIAL 0x80550309 +#define SCE_NP_AUTH_ERROR_INVALID_ENTITLEMENT_ID 0x8055030a +#define SCE_NP_AUTH_ERROR_INVALID_DATA_LENGTH 0x8055030b +#define SCE_NP_AUTH_ERROR_UNSUPPORTED_TICKET_VERSION 0x8055030c +#define SCE_NP_AUTH_ERROR_STACKSIZE_TOO_SHORT 0x8055030d +#define SCE_NP_AUTH_ERROR_TICKET_STATUS_CODE_INVALID 0x8055030e +#define SCE_NP_AUTH_ERROR_TICKET_PARAM_NOT_FOUND 0x8055030f +#define SCE_NP_AUTH_ERROR_INVALID_TICKET_VERSION 0x80550310 +#define SCE_NP_AUTH_ERROR_INVALID_ARGUMENT 0x80550311 + +#define SCE_NP_AUTH_ERROR_SERVICE_END 0x80550400 +#define SCE_NP_AUTH_ERROR_SERVICE_DOWN 0x80550401 +#define SCE_NP_AUTH_ERROR_SERVICE_BUSY 0x80550402 + +// Based on https://github.com/RPCS3/rpcs3/blob/psp2/rpcs3/Emu/PSP2/Modules/sceNpCommon.h +enum SceNpServiceState : s32 +{ + SCE_NP_SERVICE_STATE_UNKNOWN = 0, + SCE_NP_SERVICE_STATE_SIGNED_OUT, + SCE_NP_SERVICE_STATE_SIGNED_IN, + SCE_NP_SERVICE_STATE_ONLINE +}; + +struct SceNpCommunicationId +{ + char data[9]; + char term; + u8 num; + char dummy; +}; + +struct SceNpCommunicationPassphrase +{ + u8 data[128]; +}; + +struct SceNpCommunicationSignature +{ + u8 data[160]; +}; + +struct SceNpCommunicationConfig +{ + PSPPointer commId; + PSPPointer commPassphrase; + PSPPointer commSignature; +}; + +struct SceNpCountryCode +{ + char data[2]; + char term; + char padding[1]; +}; + +// Username? +struct SceNpOnlineId +{ + char data[16]; + char term; + char dummy[3]; +}; + +struct SceNpId +{ + SceNpOnlineId handle; + u8 opt[8]; + u8 reserved[8]; +}; + +struct SceNpAvatarUrl +{ + char data[127]; + char term; +}; + +struct SceNpUserInformation +{ + SceNpId userId; + SceNpAvatarUrl icon; + u8 reserved[52]; +}; + +struct SceNpMyLanguages +{ + s32_le language1; + s32_le language2; + s32_le language3; + u8 padding[4]; +}; + +struct SceNpAvatarImage +{ + u8 data[200 * 1024]; + u32_le size; + u8 reserved[12]; +}; + +enum SceNpAvatarSizeType : s32 +{ + SCE_NP_AVATAR_SIZE_LARGE, + SCE_NP_AVATAR_SIZE_MIDDLE, + SCE_NP_AVATAR_SIZE_SMALL +}; + +struct SceNpAboutMe +{ + char data[64]; +}; + +struct SceNpDate +{ + u16_le year; + u8 month; + u8 day; +}; + +union SceNpTicketParam +{ + s32_le _s32; + s64_le _s64; + u32_le _u32; + u64_le _u64; + SceNpDate date; + u8 data[256]; +}; + +struct SceNpTicketVersion +{ + u16_le major; + u16_le minor; +}; + +struct NpAuthHandler { + u32 entryPoint; + u32 argument; +}; + +struct NpAuthArgs { + u32_le data[3]; // id, result, ArgAddr +}; + +using SceNpAuthCallback = s32(s32 id, s32 result, PSPPointer arg); + +struct SceNpAuthRequestParameter +{ + u32_le size; // Size of this struct + SceNpTicketVersion version; // Highest ticket version supported by this game/device? so PSN server can return supported ticket + u32_le serviceIdAddr; //PSPPointer serviceId; // null-terminated string + u32_le cookieAddr; //PSPPointer cookie; // null-terminated string? + u32_le cookieSize; + u32_le entitlementIdAddr; //PSPPointer entitlementId; // null-terminated string + u32_le consumedCount; // related to entitlement? + u32 ticketCbAddr; //PSPPointer ticketCb + u32_le cbArgAddr; //PSPPointer cbArg +}; + +struct SceNpEntitlementId +{ + u8 data[32]; +}; + +struct SceNpEntitlement +{ + SceNpEntitlementId id; + u64_le createdDate; + u64_le expireDate; + u32_le type; + s32_le remainingCount; + u32_le consumedCount; + u8 padding[4]; +}; + +#define TICKET_VER_2_0 0x21000000; +#define TICKET_VER_2_1 0x21010000; +#define TICKET_VER_3_0 0x31000000; +#define TICKET_VER_4_0 0x41000000; + +#define NUMBER_PARAMETERS 12 + +#define PARAM_TYPE_NULL 0 +#define PARAM_TYPE_INT 1 +#define PARAM_TYPE_LONG 2 +#define PARAM_TYPE_STRING 4 // PSP returns maximum 255 bytes +#define PARAM_TYPE_DATE 7 +#define PARAM_TYPE_STRING_ASCII 8 // PSP returns maximum 255 bytes, can contains control code + +#define SECTION_TYPE_BODY 0x3000 +#define SECTION_TYPE_FOOTER 0x3002 + +// Tickets data are in big-endian based on captured packets +struct SceNpTicketParamData +{ + u16_be type; + u16_be length; + //u8 value[]; // optional data +}; + +struct SceNpTicketHeader +{ + u32_be version; // Version contents byte are: V1 0M 00 00, where V = major version, M = minor version according to https://www.psdevwiki.com/ps3/X-I-5-Ticket + s32_be size; // total ticket size (excluding this 8-bytes header struct) +}; + +// Section contents byte are: 30 XX 00 YY, where XX = section type, YY = section size according to https://www.psdevwiki.com/ps3/X-I-5-Ticket +// A section can contain other sections or param data, thus sharing their enum/def? +struct SceNpTicketSection +{ + u16_be type; // section type? ie. 30 XX where known XX are 00, 02, 10, 11 + u16_be size; // total section size (excluding this 4-bytes section delimiter struct) +}; + +struct SceNpTicket +{ + SceNpTicketHeader header; + SceNpTicketSection section; // Body or Parameter sections? + //SceNpTicketParamData parameters[]; // a list of TicketParamData + //u8 unknownBytes[]; // optional data? +}; + +#define PARENTAL_CONTROL_DISABLED 0 +#define PARENTAL_CONTROL_ENABLED 1 + +#define STATUS_ACCOUNT_SUSPENDED 0x80 +#define STATUS_ACCOUNT_CHAT_RESTRICTED 0x100 +#define STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED 0x200 + +struct SceNpAuthMemoryStat { + int npMemSize; // Memory allocated by the NP utility. + int npMaxMemSize; // Maximum memory used by the NP utility. + int npFreeMemSize; // Free memory available to use by the NP utility. +}; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + + +extern std::recursive_mutex npAuthEvtMtx; +extern std::deque npAuthEvents; +extern std::map npAuthHandlers; + void Register_sceNp(); void Register_sceNpCommerce2(); void Register_sceNpService(); -void Register_sceNpAuth(); \ No newline at end of file +void Register_sceNpAuth();