diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index 74e9bd43af..5ffec82fd8 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -135,9 +135,9 @@ std::tuple dec_section(unsigned char* metadata) dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); - u64 offset = swap64(*reinterpret_cast(&dec[0])); - s32 length = swap32(*reinterpret_cast(&dec[8])); - s32 compression_end = swap32(*reinterpret_cast(&dec[12])); + u64 offset = read_from_ptr>(dec, 0); + s32 length = read_from_ptr>(dec, 8); + s32 compression_end = read_from_ptr>(dec, 12); return std::make_tuple(offset, length, compression_end); } @@ -149,7 +149,7 @@ u128 get_block_key(int block, NPD_HEADER *npd) u128 dest_key{}; std::memcpy(&dest_key, src_key, 0xC); - s32 swappedBlock = swap32(block); + s32 swappedBlock = std::bit_cast>(block); std::memcpy(reinterpret_cast(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock)); return dest_key; } @@ -193,9 +193,9 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np // NOTE: For NPD version 1 the metadata is not encrypted. if (npd->version <= 1) { - offset = swap64(*reinterpret_cast(&metadata[0x10])); - length = swap32(*reinterpret_cast(&metadata[0x18])); - compression_end = swap32(*reinterpret_cast(&metadata[0x1C])); + offset = read_from_ptr>(metadata, 0x10); + length = read_from_ptr>(metadata, 0x18); + compression_end = read_from_ptr>(metadata, 0x1C); } else { @@ -433,17 +433,26 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: edat_log.warning("COMPRESSED data detected!"); } - const int block_num = static_cast((edat->file_size + edat->block_size - 1) / edat->block_size); - const int metadata_offset = 0x100; - const int metadata_size = metadata_section_size * block_num; + if (!edat->block_size) + { + return 1; + } + + const usz block_num = utils::aligned_div(edat->file_size, edat->block_size); + constexpr usz metadata_offset = 0x100; + const usz metadata_size = utils::mul_saturate(metadata_section_size, block_num); u64 metadata_section_offset = metadata_offset; - long bytes_read = 0; - long bytes_to_read = metadata_size; - std::unique_ptr metadata(new u8[metadata_size]); - std::unique_ptr empty_metadata(new u8[metadata_size]); + if (utils::add_saturate(utils::add_saturate(file_offset, metadata_section_offset), metadata_size) > f->size()) + { + return 1; + } - while (bytes_to_read > 0) + u64 bytes_read = 0; + const auto metadata = std::make_unique(metadata_size); + const auto empty_metadata = std::make_unique(metadata_size); + + while (bytes_read < metadata_size) { // Locate the metadata blocks. f->seek(file_offset + metadata_section_offset); @@ -453,7 +462,6 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: // Adjust sizes. bytes_read += metadata_section_size; - bytes_to_read -= metadata_section_size; if (((edat->flags & EDAT_FLAG_0x20) != 0)) // Metadata block before each data block. metadata_section_offset += (metadata_section_size + edat->block_size); @@ -553,18 +561,18 @@ bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd) return true; } - unsigned char dev[0x60] = { 0 }; + unsigned char dev[0x60]{}; // Build the dev buffer (first 0x60 bytes of NPD header in big-endian). - memcpy(dev, npd, 0x60); + std::memcpy(dev, npd, 0x60); // Fix endianness. - int version = swap32(npd->version); - int license = swap32(npd->license); - int type = swap32(npd->type); - memcpy(dev + 0x4, &version, 4); - memcpy(dev + 0x8, &license, 4); - memcpy(dev + 0xC, &type, 4); + s32 version = std::bit_cast>(npd->version); + s32 license = std::bit_cast>(npd->license); + s32 type = std::bit_cast>(npd->type); + std::memcpy(dev + 0x4, &version, 4); + std::memcpy(dev + 0x8, &license, 4); + std::memcpy(dev + 0xC, &type, 4); // Check for an empty dev_hash (can't validate if devklic is NULL); u128 klic; @@ -638,20 +646,20 @@ void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& E input->read(npd_header, sizeof(npd_header)); input->read(edat_header, sizeof(edat_header)); - memcpy(&NPD.magic, npd_header, 4); - NPD.version = swap32(*reinterpret_cast(&npd_header[4])); - NPD.license = swap32(*reinterpret_cast(&npd_header[8])); - NPD.type = swap32(*reinterpret_cast(&npd_header[12])); - memcpy(NPD.content_id, &npd_header[16], 0x30); - memcpy(NPD.digest, &npd_header[64], 0x10); - memcpy(NPD.title_hash, &npd_header[80], 0x10); - memcpy(NPD.dev_hash, &npd_header[96], 0x10); - NPD.activate_time = swap64(*reinterpret_cast(&npd_header[112])); - NPD.expire_time = swap64(*reinterpret_cast(&npd_header[120])); + std::memcpy(&NPD.magic, npd_header, 4); + NPD.version = read_from_ptr>(npd_header, 4); + NPD.license = read_from_ptr>(npd_header, 8); + NPD.type = read_from_ptr>(npd_header, 12); + std::memcpy(NPD.content_id, &npd_header[16], 0x30); + std::memcpy(NPD.digest, &npd_header[64], 0x10); + std::memcpy(NPD.title_hash, &npd_header[80], 0x10); + std::memcpy(NPD.dev_hash, &npd_header[96], 0x10); + NPD.activate_time = read_from_ptr>(npd_header, 112); + NPD.expire_time = read_from_ptr>(npd_header, 120); - EDAT.flags = swap32(*reinterpret_cast(&edat_header[0])); - EDAT.block_size = swap32(*reinterpret_cast(&edat_header[4])); - EDAT.file_size = swap64(*reinterpret_cast(&edat_header[8])); + EDAT.flags = read_from_ptr>(edat_header, 0); + EDAT.block_size = read_from_ptr>(edat_header, 4); + EDAT.file_size = read_from_ptr>(edat_header, 8); } bool extract_all_data(const fs::file* input, const fs::file* output, const char* input_file_name, unsigned char* devklic, bool verbose) diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 16cbf0cb1c..d693ae5abb 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -365,22 +365,14 @@ void MetadataInfo::Show() const void MetadataHeader::Load(u8* in) { - memcpy(&signature_input_length, in, 8); - memcpy(&unknown1, in + 8, 4); - memcpy(§ion_count, in + 12, 4); - memcpy(&key_count, in + 16, 4); - memcpy(&opt_header_size, in + 20, 4); - memcpy(&unknown2, in + 24, 4); - memcpy(&unknown3, in + 28, 4); - // Endian swap. - signature_input_length = swap64(signature_input_length); - unknown1 = swap32(unknown1); - section_count = swap32(section_count); - key_count = swap32(key_count); - opt_header_size = swap32(opt_header_size); - unknown2 = swap32(unknown2); - unknown3 = swap32(unknown3); + signature_input_length = read_from_ptr>(in); + unknown1 = read_from_ptr>(in, 8); + section_count = read_from_ptr>(in, 12); + key_count = read_from_ptr>(in, 16); + opt_header_size = read_from_ptr>(in, 20); + unknown2 = read_from_ptr>(in, 24); + unknown3 = read_from_ptr>(in, 28); } void MetadataHeader::Show() const @@ -396,28 +388,17 @@ void MetadataHeader::Show() const void MetadataSectionHeader::Load(u8* in) { - memcpy(&data_offset, in, 8); - memcpy(&data_size, in + 8, 8); - memcpy(&type, in + 16, 4); - memcpy(&program_idx, in + 20, 4); - memcpy(&hashed, in + 24, 4); - memcpy(&sha1_idx, in + 28, 4); - memcpy(&encrypted, in + 32, 4); - memcpy(&key_idx, in + 36, 4); - memcpy(&iv_idx, in + 40, 4); - memcpy(&compressed, in + 44, 4); - // Endian swap. - data_offset = swap64(data_offset); - data_size = swap64(data_size); - type = swap32(type); - program_idx = swap32(program_idx); - hashed = swap32(hashed); - sha1_idx = swap32(sha1_idx); - encrypted = swap32(encrypted); - key_idx = swap32(key_idx); - iv_idx = swap32(iv_idx); - compressed = swap32(compressed); + data_offset = read_from_ptr>(in); + data_size = read_from_ptr>(in, 8); + type = read_from_ptr>(in, 16); + program_idx = read_from_ptr>(in, 20); + hashed = read_from_ptr>(in, 24); + sha1_idx = read_from_ptr>(in, 28); + encrypted = read_from_ptr>(in, 32); + key_idx = read_from_ptr>(in, 36); + iv_idx = read_from_ptr>(in, 40); + compressed = read_from_ptr>(in, 44); } void MetadataSectionHeader::Show() const @@ -936,19 +917,29 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info) } } - // Read section info. m_seg_ext_hdr.clear(); self_f.seek(m_ext_hdr.segment_ext_hdr_offset); - for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) + for(u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) { + if (self_f.pos() >= self_f.size()) + { + return false; + } + m_seg_ext_hdr.emplace_back(); m_seg_ext_hdr.back().Load(self_f); } + if (m_ext_hdr.version_hdr_offset == 0 || utils::add_saturate(m_ext_hdr.version_hdr_offset, sizeof(version_header)) > self_f.size()) + { + return false; + } + // Read SCE version info. self_f.seek(m_ext_hdr.version_hdr_offset); + m_version_hdr.Load(self_f); // Read control info. @@ -957,6 +948,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info) for (u64 i = 0; i < m_ext_hdr.supplemental_hdr_size;) { + if (self_f.pos() >= self_f.size()) + { + return false; + } + m_supplemental_hdr_arr.emplace_back(); supplemental_header& cinfo = m_supplemental_hdr_arr.back(); cinfo.Load(self_f); diff --git a/rpcs3/Crypto/utils.h b/rpcs3/Crypto/utils.h index 156ba2437b..3e36989dfe 100644 --- a/rpcs3/Crypto/utils.h +++ b/rpcs3/Crypto/utils.h @@ -5,39 +5,12 @@ // http://www.gnu.org/licenses/gpl-2.0.txt #include "util/types.hpp" +#include "util/asm.hpp" #include enum { CRYPTO_MAX_PATH = 4096 }; -// Auxiliary functions (endian swap, xor, and file name). -inline u16 swap16(u16 i) -{ -#if defined(__GNUG__) - return __builtin_bswap16(i); -#else - return _byteswap_ushort(i); -#endif -} - -inline u32 swap32(u32 i) -{ -#if defined(__GNUG__) - return __builtin_bswap32(i); -#else - return _byteswap_ulong(i); -#endif -} - -inline u64 swap64(u64 i) -{ -#if defined(__GNUG__) - return __builtin_bswap64(i); -#else - return _byteswap_uint64(i); -#endif -} - char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH]); std::string sha256_get_hash(const char* data, usz size, bool lower_case);