bool vfsHDDFile::goto_block(u64 n) { vfsHDD_Block block_info; if (m_info.data_block >= m_hdd_info.block_count) { return false; } CHECK_ASSERTION(m_hdd.Seek(m_info.data_block * m_hdd_info.block_size) != -1); block_info.next_block = m_info.data_block; for (u64 i = 0; i < n; ++i) { if (!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count) { return false; } CHECK_ASSERTION(m_hdd.Seek(block_info.next_block * m_hdd_info.block_size) != -1); m_hdd.Read(&block_info, sizeof(vfsHDD_Block)); } return true; }
void vfsHDDFile::SaveInfo() { CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); m_hdd.Write(&m_info, sizeof(vfsHDD_Entry)); }
bool CheckDebugSelf(const std::string& self, const std::string& elf) { // Open the SELF file. fs::file s(self); if (!s) { LOG_ERROR(LOADER, "Could not open SELF file! (%s)", self.c_str()); return false; } // Get the key version. CHECK_ASSERTION(s.seek(0x08) != -1); u16 key_version; s.read(&key_version, sizeof(key_version)); // Check for DEBUG version. if (swap16(key_version) == 0x8000) { LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); // Get the real elf offset. CHECK_ASSERTION(s.seek(0x10) != -1); u64 elf_offset; s.read(&elf_offset, sizeof(elf_offset)); // Start at the real elf offset. elf_offset = swap64(elf_offset); CHECK_ASSERTION(s.seek(elf_offset) != -1); // Write the real ELF file back. fs::file e(elf, fom::rewrite); if (!e) { LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); return false; } // Copy the data. char buf[2048]; while (ssize_t size = s.read(buf, 2048)) { e.write(buf, size); } return true; } // Leave the file untouched. return false; }
u64 vfsHDDFile::Read(void* dst, u64 size) { if (!size) return 0; //vfsDeviceLocker lock(m_hdd); const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); u64 rsize = std::min<u64>(block_size - m_position, size); vfsHDD_Block cur_block_info; CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); m_hdd.Read(dst, rsize); size -= rsize; m_position += rsize; if (!size) { return rsize; } u64 offset = rsize; for (; size; size -= rsize, offset += rsize) { if (!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count) { return offset; } m_cur_block = cur_block_info.next_block; rsize = std::min<u64>(block_size, size); CHECK_ASSERTION(m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size) != -1); m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); if (m_hdd.Read((u8*)dst + offset, rsize) != rsize) { return offset; } } m_position = rsize; return offset; }
void vfsHDDManager::CreateHDD(const std::string& path, u64 size, u64 block_size) { fs::file f(path, fom::rewrite); static const u64 cur_dir_block = 1; vfsHDD_Hdr hdr; CreateBlock(hdr); hdr.next_block = cur_dir_block; hdr.magic = g_hdd_magic; hdr.version = g_hdd_version; hdr.block_count = (size + block_size) / block_size; hdr.block_size = block_size; f.write(&hdr, sizeof(vfsHDD_Hdr)); { vfsHDD_Entry entry; CreateEntry(entry); entry.type = vfsHDD_Entry_Dir; entry.data_block = hdr.next_block; entry.next_block = 0; f.seek(cur_dir_block * hdr.block_size); f.write(&entry, sizeof(vfsHDD_Entry)); f.write(".", 1); } u8 null = 0; CHECK_ASSERTION(f.seek(hdr.block_count * hdr.block_size - sizeof(null)) != -1); f.write(&null, sizeof(null)); }
s32 vfsHDD::OpenDir(const std::string& name) { LOG_WARNING(HLE, "OpenDir(%s)", name.c_str()); u64 entry_block; if (!SearchEntry(name, entry_block)) { return -1; } CHECK_ASSERTION(m_hdd_file.Seek(entry_block * m_hdd_info.block_size) != -1); vfsHDD_Entry entry; m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry)); if (entry.type == vfsHDD_Entry_File) { return 1; } m_cur_dir_block = entry.data_block; ReadEntry(m_cur_dir_block, m_cur_dir); return 0; }
void vfsHDD::ReadEntry(u64 block, std::string& name) { CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry)) != -1); name.resize(GetMaxNameLen()); m_hdd_file.Read(&name.front(), GetMaxNameLen()); }
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) { CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); m_hdd_file.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1)); }
bool fs::dir::close() { g_tls_error = fse::ok; if (!m_path) { return false; } m_path.reset(); #ifdef _WIN32 CHECK_ASSERTION(m_dd == -1 || FindClose((HANDLE)m_dd)); #else CHECK_ASSERTION(!::closedir((DIR*)m_dd)); #endif return true; }
//Copied some from AutoPause. //Tip: This one doesn't check for the file is being read or not. //This would always use a 0xFFFFFFFF as end of the pause.bin void AutoPauseManagerDialog::SaveEntries(void) { fs::file list(fs::get_config_dir() + "pause.bin", fom::rewrite); //System calls ID and Function calls ID are all u32 iirc. u32 num = 0; CHECK_ASSERTION(list.seek(0) != -1); for (size_t i = 0; i < m_entries.size(); ++i) { if (num == 0xFFFFFFFF) continue; num = m_entries[i]; list.write(&num, sizeof(u32)); } num = 0xFFFFFFFF; list.write(&num, sizeof(u32)); }
vfsHDD::vfsHDD(vfsDevice* device, const std::string& hdd_path) : m_hdd_file(device) , m_file(m_hdd_file, m_hdd_info) , m_hdd_path(hdd_path) , vfsFileBase(device) { m_hdd_file.Open(hdd_path, fom::read | fom::write); m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr)); m_cur_dir_block = m_hdd_info.next_block; if (!m_hdd_info.block_size) { LOG_ERROR(HLE, "Bad block size!"); m_hdd_info.block_size = 2048; } CHECK_ASSERTION(m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size) != -1); m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry)); }
bool IsSelfElf32(const std::string& path) { vfsLocalFile f(nullptr); if(!f.Open(path)) return false; SceHeader hdr; SelfHeader sh; hdr.Load(f); sh.Load(f); // Locate the class byte and check it. u8 elf_class[0x8]; CHECK_ASSERTION(f.Seek(sh.se_elfoff) != -1); f.Read(elf_class, 0x8); return (elf_class[4] == 1); }
void fnt_MoveAPoint( fnt_LocalGraphicStateType* gs, F26Dot6* x, F26Dot6* y, F26Dot6 delta) { register shortFrac pfProj = gs->pfProj; register shortFrac fx = gs->free.x; register shortFrac fy = gs->free.y; CHECK_PFPROJ( gs ); CHECK_ASSERTION( gs, x != y ); if ( pfProj != shortFrac1 ) { if ( fx ) *x += ShortMulDiv( delta, fx, pfProj ); if ( fy ) *y += ShortMulDiv( delta, fy, pfProj ); } else { if ( fx ) *x += ShortFracMul( delta, fx ); if ( fy ) *y += ShortFracMul( delta, fy ); } }
//Copied some from AutoPause. void AutoPauseManagerDialog::LoadEntries(void) { m_entries.clear(); m_entries.reserve(16); fs::file list(fs::get_config_dir() + "pause.bin"); if (list) { //System calls ID and Function calls ID are all u32 iirc. u32 num; size_t fmax = list.size(); size_t fcur = 0; CHECK_ASSERTION(list.seek(0) != -1); while (fcur <= fmax - sizeof(u32)) { list.read(&num, sizeof(u32)); fcur += sizeof(u32); if (num == 0xFFFFFFFF) break; m_entries.emplace_back(num); } } }
const std::string& entry::as_string() const { CHECK_ASSERTION(m_type == format::string || m_type == format::array); return m_value_string; }
entry& entry::operator =(const std::string& value) { CHECK_ASSERTION(m_type == format::string || m_type == format::array); m_value_string = value; return *this; }
entry& entry::operator =(u32 value) { CHECK_ASSERTION(m_type == format::integer); m_value_integer = value; return *this; }
void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data) { CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); m_hdd_file.Read(&data, sizeof(vfsHDD_Entry)); }
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data) { CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); }
registry load(const std::vector<char>& data) { registry result; // Hack for empty input (TODO) if (data.empty()) { return result; } // Check size CHECK_ASSERTION(data.size() >= sizeof(header_t)); CHECK_ASSERTION((std::uintptr_t)data.data() % 8 == 0); // Get header const header_t& header = reinterpret_cast<const header_t&>(data[0]); // Check magic and version CHECK_ASSERTION(header.magic == *(u32*)"\0PSF"); CHECK_ASSERTION(header.version == 0x101); CHECK_ASSERTION(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); CHECK_ASSERTION(header.off_key_table <= header.off_data_table); CHECK_ASSERTION(header.off_data_table <= data.size()); // Get indices (alignment should be fine) const def_table_t* indices = reinterpret_cast<const def_table_t*>(data.data() + sizeof(header_t)); // Load entries for (u32 i = 0; i < header.entries_num; ++i) { CHECK_ASSERTION(indices[i].key_off < header.off_data_table - header.off_key_table); // Get key name range const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off; const auto name_end = std::find(name_ptr , data.begin() + header.off_data_table, '\0'); // Get name (must be unique) std::string key(name_ptr, name_end); CHECK_ASSERTION(result.count(key) == 0); CHECK_ASSERTION(indices[i].param_len <= indices[i].param_max); CHECK_ASSERTION(indices[i].data_off < data.size() - header.off_data_table); CHECK_ASSERTION(indices[i].param_max < data.size() - indices[i].data_off); // Get data pointer const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off; if (indices[i].param_fmt == format::integer && indices[i].param_max == sizeof(u32) && indices[i].param_len == sizeof(u32)) { // Integer data result.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::forward_as_tuple(reinterpret_cast<const le_t<u32>&>(*value_ptr))); } else if (indices[i].param_fmt == format::string || indices[i].param_fmt == format::array) { // String/array data std::string value; if (indices[i].param_fmt == format::string) { // Find null terminator value.assign(value_ptr, std::find(value_ptr, value_ptr + indices[i].param_len, '\0')); } else { value.assign(value_ptr, value_ptr + indices[i].param_len); } result.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::forward_as_tuple(indices[i].param_fmt, indices[i].param_max, std::move(value))); } else { // Possibly unsupported format, entry ignored log.error("Unknown entry format (key='%s', fmt=0x%x, len=0x%x, max=0x%x)", key, indices[i].param_fmt, indices[i].param_len, indices[i].param_max); } } return result; }
bool SELFDecrypter::DecryptData() { aes_context aes; // Calculate the total data size. for (unsigned int i = 0; i < meta_hdr.section_count; i++) { if (meta_shdr[i].encrypted == 3) { if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count)) data_buf_length += meta_shdr[i].data_size; } } // Allocate a buffer to store decrypted data. data_buf = (u8*)malloc(data_buf_length); // Set initial offset. u32 data_buf_offset = 0; // Parse the metadata section headers to find the offsets of encrypted data. for (unsigned int i = 0; i < meta_hdr.section_count; i++) { size_t ctr_nc_off = 0; u8 ctr_stream_block[0x10]; u8 data_key[0x10]; u8 data_iv[0x10]; // Check if this is an encrypted section. if (meta_shdr[i].encrypted == 3) { // Make sure the key and iv are not out of boundaries. if((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count)) { // Get the key and iv from the previously stored key buffer. memcpy(data_key, data_keys + meta_shdr[i].key_idx * 0x10, 0x10); memcpy(data_iv, data_keys + meta_shdr[i].iv_idx * 0x10, 0x10); // Allocate a buffer to hold the data. u8 *buf = (u8 *)malloc(meta_shdr[i].data_size); // Seek to the section data offset and read the encrypted data. CHECK_ASSERTION(self_f.Seek(meta_shdr[i].data_offset) != -1); self_f.Read(buf, meta_shdr[i].data_size); // Zero out our ctr nonce. memset(ctr_stream_block, 0, sizeof(ctr_stream_block)); // Perform AES-CTR encryption on the data blocks. aes_setkey_enc(&aes, data_key, 128); aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf, buf); // Copy the decrypted data. memcpy(data_buf + data_buf_offset, buf, meta_shdr[i].data_size); // Advance the buffer's offset. data_buf_offset += meta_shdr[i].data_size; // Release the temporary buffer. free(buf); } } } return true; }
u64 vfsHDDFile::Write(const void* src, u64 size) { if (!size) return 0; //vfsDeviceLocker lock(m_hdd); const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); if (!m_cur_block) { if (!m_info.data_block) { u64 new_block = FindFreeBlock(); if (!new_block) { return 0; } WriteBlock(new_block, g_used_block); m_info.data_block = new_block; m_info.size = 0; SaveInfo(); } m_cur_block = m_info.data_block; m_position = 0; } u64 wsize = std::min<u64>(block_size - m_position, size); vfsHDD_Block block_info; ReadBlock(m_cur_block, block_info); if (wsize) { CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); m_hdd.Write(src, wsize); size -= wsize; m_info.size += wsize; m_position += wsize; SaveInfo(); if (!size) return wsize; } u64 last_block = m_cur_block; block_info.is_used = true; u64 offset = wsize; for (; size; size -= wsize, offset += wsize, m_info.size += wsize) { u64 new_block = FindFreeBlock(); if (!new_block) { m_position = 0; SaveInfo(); return offset; } m_cur_block = new_block; wsize = std::min<u64>(block_size, size); block_info.next_block = m_cur_block; CHECK_ASSERTION(m_hdd.Seek(last_block * m_hdd_info.block_size) != -1); if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) { m_position = 0; SaveInfo(); return offset; } block_info.next_block = 0; CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) { m_position = 0; SaveInfo(); return offset; } if ((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize) { m_info.size += wsize; SaveInfo(); return offset; } last_block = m_cur_block; } SaveInfo(); m_position = wsize; return offset; }
bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) { // Create a new ELF file. fs::file e(elf, fom::rewrite); if(!e) { LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); return false; } // Set initial offset. u32 data_buf_offset = 0; if (isElf32) { // Write ELF header. WriteEhdr(e, elf32_hdr); // Write program headers. for (u32 i = 0; i < elf32_hdr.e_phnum; ++i) { WritePhdr(e, phdr32_arr[i]); } for (unsigned int i = 0; i < meta_hdr.section_count; i++) { // PHDR type. if (meta_shdr[i].type == 2) { // Seek to the program header data offset and write the data. CHECK_ASSERTION(e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset) != -1); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); // Advance the data buffer offset by data size. data_buf_offset += meta_shdr[i].data_size; } } // Write section headers. if (self_hdr.se_shdroff != 0) { CHECK_ASSERTION(e.seek(elf32_hdr.e_shoff) != -1); for (u32 i = 0; i < elf32_hdr.e_shnum; ++i) { WriteShdr(e, shdr32_arr[i]); } } } else { // Write ELF header. WriteEhdr(e, elf64_hdr); // Write program headers. for (u32 i = 0; i < elf64_hdr.e_phnum; ++i) { WritePhdr(e, phdr64_arr[i]); } // Write data. for (unsigned int i = 0; i < meta_hdr.section_count; i++) { // PHDR type. if (meta_shdr[i].type == 2) { // Decompress if necessary. if (meta_shdr[i].compressed == 2) { // Allocate a buffer for decompression. u8 *decomp_buf = (u8 *)malloc(phdr64_arr[meta_shdr[i].program_idx].p_filesz); // Set up memory streams for input/output. wxMemoryInputStream decomp_stream_in(data_buf + data_buf_offset, meta_shdr[i].data_size); wxMemoryOutputStream decomp_stream_out; // Create a Zlib stream, read the data and flush the stream. wxZlibInputStream* z_stream = new wxZlibInputStream(decomp_stream_in); z_stream->Read(decomp_stream_out); delete z_stream; // Copy the decompressed result from the stream. decomp_stream_out.CopyTo(decomp_buf, phdr64_arr[meta_shdr[i].program_idx].p_filesz); // Seek to the program header data offset and write the data. CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); e.write(decomp_buf, phdr64_arr[meta_shdr[i].program_idx].p_filesz); // Release the decompression buffer. free(decomp_buf); } else { // Seek to the program header data offset and write the data. CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); } // Advance the data buffer offset by data size. data_buf_offset += meta_shdr[i].data_size; } } // Write section headers. if (self_hdr.se_shdroff != 0) { CHECK_ASSERTION(e.seek(elf64_hdr.e_shoff) != -1); for (u32 i = 0; i < elf64_hdr.e_shnum; ++i) { WriteShdr(e, shdr64_arr[i]); } } } return true; }
bool SELFDecrypter::LoadHeaders(bool isElf32) { // Read SCE header. CHECK_ASSERTION(self_f.Seek(0) != -1); sce_hdr.Load(self_f); // Check SCE magic. if (!sce_hdr.CheckMagic()) { LOG_ERROR(LOADER, "SELF: Not a SELF file!"); return false; } // Read SELF header. self_hdr.Load(self_f); // Read the APP INFO. CHECK_ASSERTION(self_f.Seek(self_hdr.se_appinfooff) != -1); app_info.Load(self_f); // Read ELF header. CHECK_ASSERTION(self_f.Seek(self_hdr.se_elfoff) != -1); if (isElf32) elf32_hdr.Load(self_f); else elf64_hdr.Load(self_f); // Read ELF program headers. if (isElf32) { phdr32_arr.clear(); if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum) { LOG_ERROR(LOADER, "SELF: ELF program header offset is null!"); return false; } self_f.Seek(self_hdr.se_phdroff); for(u32 i = 0; i < elf32_hdr.e_phnum; ++i) { phdr32_arr.emplace_back(); phdr32_arr.back().Load(self_f); } } else { phdr64_arr.clear(); if (elf64_hdr.e_phoff == 0 && elf64_hdr.e_phnum) { LOG_ERROR(LOADER, "SELF: ELF program header offset is null!"); return false; } CHECK_ASSERTION(self_f.Seek(self_hdr.se_phdroff) != -1); for (u32 i = 0; i < elf64_hdr.e_phnum; ++i) { phdr64_arr.emplace_back(); phdr64_arr.back().Load(self_f); } } // Read section info. secinfo_arr.clear(); CHECK_ASSERTION(self_f.Seek(self_hdr.se_secinfoff) != -1); for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) { secinfo_arr.emplace_back(); secinfo_arr.back().Load(self_f); } // Read SCE version info. CHECK_ASSERTION(self_f.Seek(self_hdr.se_sceveroff) != -1); scev_info.Load(self_f); // Read control info. ctrlinfo_arr.clear(); CHECK_ASSERTION(self_f.Seek(self_hdr.se_controloff) != -1); u32 i = 0; while(i < self_hdr.se_controlsize) { ctrlinfo_arr.emplace_back(); ControlInfo &cinfo = ctrlinfo_arr.back(); cinfo.Load(self_f); i += cinfo.size; } // Read ELF section headers. if (isElf32) { shdr32_arr.clear(); if (elf32_hdr.e_shoff == 0 && elf32_hdr.e_shnum) { LOG_WARNING(LOADER, "SELF: ELF section header offset is null!"); return true; } CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); for(u32 i = 0; i < elf32_hdr.e_shnum; ++i) { shdr32_arr.emplace_back(); shdr32_arr.back().Load(self_f); } } else { shdr64_arr.clear(); if (elf64_hdr.e_shoff == 0 && elf64_hdr.e_shnum) { LOG_WARNING(LOADER, "SELF: ELF section header offset is null!"); return true; } CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); for(u32 i = 0; i < elf64_hdr.e_shnum; ++i) { shdr64_arr.emplace_back(); shdr64_arr.back().Load(self_f); } } return true; }
bool SELFDecrypter::LoadMetadata() { aes_context aes; u32 metadata_info_size = sizeof32(meta_info); u8 *metadata_info = (u8 *)malloc(metadata_info_size); u32 metadata_headers_size = sce_hdr.se_hsize - (sizeof32(sce_hdr) + sce_hdr.se_meta + sizeof32(meta_info)); u8 *metadata_headers = (u8 *)malloc(metadata_headers_size); // Locate and read the encrypted metadata info. CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr)) != -1); self_f.Read(metadata_info, metadata_info_size); // Locate and read the encrypted metadata header and section header. CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size) != -1); self_f.Read(metadata_headers, metadata_headers_size); // Find the right keyset from the key vault. SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version); // Copy the necessary parameters. u8 metadata_key[0x20]; u8 metadata_iv[0x10]; memcpy(metadata_key, keyset.erk, 0x20); memcpy(metadata_iv, keyset.riv, 0x10); // Check DEBUG flag. if ((sce_hdr.se_flags & 0x8000) != 0x8000) { // Decrypt the NPDRM layer. if (!DecryptNPDRM(metadata_info, metadata_info_size)) return false; // Decrypt the metadata info. aes_setkey_dec(&aes, metadata_key, 256); // AES-256 aes_crypt_cbc(&aes, AES_DECRYPT, metadata_info_size, metadata_iv, metadata_info, metadata_info); } // Load the metadata info. meta_info.Load(metadata_info); // If the padding is not NULL for the key or iv fields, the metadata info // is not properly decrypted. if ((meta_info.key_pad[0] != 0x00) || (meta_info.iv_pad[0] != 0x00)) { LOG_ERROR(LOADER, "SELF: Failed to decrypt metadata info!"); return false; } // Perform AES-CTR encryption on the metadata headers. size_t ctr_nc_off = 0; u8 ctr_stream_block[0x10]; aes_setkey_enc(&aes, meta_info.key, 128); aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers, metadata_headers); // Load the metadata header. meta_hdr.Load(metadata_headers); // Load the metadata section headers. meta_shdr.clear(); for (unsigned int i = 0; i < meta_hdr.section_count; i++) { meta_shdr.emplace_back(); meta_shdr.back().Load(metadata_headers + sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i); } // Copy the decrypted data keys. data_keys_length = meta_hdr.key_count * 0x10; data_keys = (u8 *) malloc (data_keys_length); memcpy(data_keys, metadata_headers + sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader), data_keys_length); return true; }
void vfsHDDFile::ReadBlock(u64 block, vfsHDD_Block& data) { CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); m_hdd.Read(&data, sizeof(vfsHDD_Block)); }
void vfsHDDFile::WriteBlock(u64 block, const vfsHDD_Block& data) { CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); m_hdd.Write(&data, sizeof(vfsHDD_Block)); }
u32 entry::as_integer() const { CHECK_ASSERTION(m_type == format::integer); return m_value_integer; }