Implemented sceNpDrmGetTimelimit

This commit is contained in:
NicknineTheEagle 2022-03-20 16:27:06 +03:00 committed by Megamouse
parent e4225cbab8
commit 1df47352cc
4 changed files with 101 additions and 2 deletions

View file

@ -57,6 +57,7 @@ struct EDAT_HEADER
// Decrypts full file, or null/empty file // Decrypts full file, or null/empty file
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose); extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose);
extern void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT);
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER *npd_out = nullptr); extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER *npd_out = nullptr);
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file); u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);

View file

@ -1497,9 +1497,42 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key, NPD_HEADER* n
} }
} }
} }
return true; return true;
} }
bool get_npdrm_self_header(const fs::file& self, NPD_HEADER &npd_out)
{
if (!self)
return false;
self.seek(0);
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32 && !IsDebugSelf(self))
{
// Check the ELF file class (32 or 64 bit).
const bool isElf32 = IsSelfElf32(self);
// Start the decrypter on this SELF file.
SELFDecrypter self_dec(self);
// Load the SELF file headers.
if (!self_dec.LoadHeaders(isElf32))
{
self_log.error("Failed to load SELF file headers!");
return false;
}
if (const NPD_HEADER* npd = self_dec.GetNPDHeader())
{
memcpy(&npd_out, npd, sizeof(NPD_HEADER));
return true;
}
}
return false;
}
u128 get_default_self_klic() u128 get_default_self_klic()
{ {
return std::bit_cast<u128>(NP_KLIC_FREE); return std::bit_cast<u128>(NP_KLIC_FREE);

View file

@ -498,5 +498,6 @@ private:
fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr); fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr, NPD_HEADER* npd_out = nullptr); bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr, NPD_HEADER* npd_out = nullptr);
bool get_npdrm_self_header(const fs::file& self, NPD_HEADER& npd);
u128 get_default_self_klic(); u128 get_default_self_klic();

View file

@ -608,15 +608,79 @@ error_code sceNpDrmExecuteGamePurchase()
error_code sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain) error_code sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain)
{ {
sceNp.todo("sceNpDrmGetTimelimit(path=%s, time_remain=*0x%x)", path, time_remain); sceNp.warning("sceNpDrmGetTimelimit(path=%s, time_remain=*0x%x)", path, time_remain);
if (!path || !time_remain) if (!path || !time_remain)
{ {
return SCE_NP_DRM_ERROR_INVALID_PARAM; return SCE_NP_DRM_ERROR_INVALID_PARAM;
} }
*time_remain = SCE_NP_DRM_TIME_INFO_ENDLESS; vm::var<s64> sec;
vm::var<s64> nsec;
// Get system time (real or fake) to compare to
error_code ret = sys_time_get_current_time(sec, nsec);
if (ret != CELL_OK)
{
return ret;
}
const std::string enc_drm_path(path.get_ptr(), std::find(path.get_ptr(), path.get_ptr() + 0x100, '\0'));
const auto [fs_error, ppath, real_path, enc_file, type] = lv2_file::open(enc_drm_path, 0, 0);
if (fs_error)
{
return {fs_error, enc_drm_path};
}
u32 magic;
NPD_HEADER npd;
enc_file.read<u32>(magic);
enc_file.seek(0);
// Read expiration time from NPD header which is Unix timestamp in milliseconds
if (magic == "SCE\0"_u32)
{
if (!get_npdrm_self_header(enc_file, npd))
{
sceNp.error("sceNpDrmGetTimelimit(): Failed to read NPD header from sce file '%s'", enc_drm_path);
return {SCE_NP_DRM_ERROR_BAD_FORMAT, enc_drm_path};
}
}
else if (magic == "NPD\0"_u32)
{
// edata / sdata files
EDAT_HEADER edat;
read_npd_edat_header(&enc_file, npd, edat);
}
else
{
// Unknown file type
return {SCE_NP_DRM_ERROR_BAD_FORMAT, enc_drm_path};
}
// Convert time to milliseconds
s64 msec = *sec * 1000ll + *nsec / 1000ll;
// Return the remaining time in microseconds
if (npd.activate_time != 0 && msec < npd.activate_time)
{
return SCE_NP_DRM_ERROR_SERVICE_NOT_STARTED;
}
if (npd.expire_time == 0)
{
*time_remain = SCE_NP_DRM_TIME_INFO_ENDLESS;
return CELL_OK;
}
if (msec >= npd.expire_time)
{
return SCE_NP_DRM_ERROR_TIME_LIMIT;
}
*time_remain = (npd.expire_time - msec) * 1000ll;
return CELL_OK; return CELL_OK;
} }