Skip to content

Commit

Permalink
WiiSave: Use Common::BigEndianValue to simplify parsing
Browse files Browse the repository at this point in the history
Gets rid of the need to manually cast when reading/writing, which is
error prone and repetitive.
  • Loading branch information
leoetlino committed May 13, 2018
1 parent fb39efb commit 956df21
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 55 deletions.
65 changes: 28 additions & 37 deletions Source/Core/Core/HW/WiiSave.cpp
Expand Up @@ -29,7 +29,6 @@
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Common/NandPaths.h" #include "Common/NandPaths.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Swap.h"


constexpr u8 s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, constexpr u8 s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08,
0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D};
Expand Down Expand Up @@ -153,15 +152,15 @@ void WiiSave::ReadHDR()


mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv,
(const u8*)&m_encrypted_header, (u8*)&m_header); (const u8*)&m_encrypted_header, (u8*)&m_header);
u32 banner_size = Common::swap32(m_header.hdr.banner_size); u32 banner_size = m_header.hdr.banner_size;
if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) ||
(((banner_size - BNR_SZ) % ICON_SZ) != 0)) (((banner_size - BNR_SZ) % ICON_SZ) != 0))
{ {
ERROR_LOG(CONSOLE, "Not a Wii save or read failure for file header size %x", banner_size); ERROR_LOG(CONSOLE, "Not a Wii save or read failure for file header size %x", banner_size);
m_valid = false; m_valid = false;
return; return;
} }
m_title_id = Common::swap64(m_header.hdr.save_game_title); m_title_id = m_header.hdr.save_game_title;


u8 md5_file[16]; u8 md5_file[16];
u8 md5_calc[16]; u8 md5_calc[16];
Expand Down Expand Up @@ -205,9 +204,9 @@ void WiiSave::WriteHDR()


std::string banner_file_path = m_wii_title_path + "/banner.bin"; std::string banner_file_path = m_wii_title_path + "/banner.bin";
u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path)); u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path));
m_header.hdr.banner_size = Common::swap32(banner_size); m_header.hdr.banner_size = banner_size;


m_header.hdr.save_game_title = Common::swap64(m_title_id); m_header.hdr.save_game_title = m_title_id;
memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); memcpy(m_header.hdr.md5, s_md5_blanker, 0x10);
m_header.hdr.permissions = 0x3C; m_header.hdr.permissions = 0x3C;


Expand Down Expand Up @@ -257,47 +256,41 @@ void WiiSave::ReadBKHDR()
} }
fpData_bin.Close(); fpData_bin.Close();


if (m_bk_hdr.size != Common::swap32(BK_LISTED_SZ) || if (m_bk_hdr.size != BK_LISTED_SZ || m_bk_hdr.magic != BK_HDR_MAGIC)
m_bk_hdr.magic != Common::swap32(BK_HDR_MAGIC))
{ {
ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", m_bk_hdr.size, m_bk_hdr.magic); ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", u32(m_bk_hdr.size),
u32(m_bk_hdr.magic));
m_valid = false; m_valid = false;
return; return;
} }


m_files_list_size = Common::swap32(m_bk_hdr.number_of_files); if (m_bk_hdr.size_of_files + FULL_CERT_SZ != m_bk_hdr.total_size)
m_size_of_files = Common::swap32(m_bk_hdr.size_of_files);
m_total_size = Common::swap32(m_bk_hdr.total_size);

if (m_size_of_files + FULL_CERT_SZ != m_total_size)
{ {
WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files, WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)",
FULL_CERT_SZ, m_total_size); u32(m_bk_hdr.size_of_files), FULL_CERT_SZ, u32(m_bk_hdr.total_size));
} }
if (m_title_id != Common::swap64(m_bk_hdr.save_game_title)) if (m_title_id != m_bk_hdr.save_game_title)
{ {
WARN_LOG(CONSOLE, WARN_LOG(CONSOLE,
"Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")", "Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")",
m_title_id, Common::swap64(m_bk_hdr.save_game_title)); m_title_id, u64(m_bk_hdr.save_game_title));
} }
} }


void WiiSave::WriteBKHDR() void WiiSave::WriteBKHDR()
{ {
if (!m_valid) if (!m_valid)
return; return;
m_files_list_size = 0; u32 number_of_files = 0, size_of_files = 0;
m_size_of_files = 0; ScanForFiles(m_wii_title_path, m_files_list, &number_of_files, &size_of_files);

ScanForFiles(m_wii_title_path, m_files_list, &m_files_list_size, &m_size_of_files);
memset(&m_bk_hdr, 0, BK_SZ); memset(&m_bk_hdr, 0, BK_SZ);
m_bk_hdr.size = Common::swap32(BK_LISTED_SZ); m_bk_hdr.size = BK_LISTED_SZ;
m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC); m_bk_hdr.magic = BK_HDR_MAGIC;
m_bk_hdr.ngid = s_ng_id; m_bk_hdr.ngid = s_ng_id;
m_bk_hdr.number_of_files = Common::swap32(m_files_list_size); m_bk_hdr.number_of_files = number_of_files;
m_bk_hdr.size_of_files = Common::swap32(m_size_of_files); m_bk_hdr.size_of_files = size_of_files;
m_bk_hdr.total_size = Common::swap32(m_size_of_files + FULL_CERT_SZ); m_bk_hdr.total_size = size_of_files + FULL_CERT_SZ;
m_bk_hdr.save_game_title = Common::swap64(m_title_id); m_bk_hdr.save_game_title = m_title_id;


File::IOFile data_file(m_encrypted_save_path, "ab"); File::IOFile data_file(m_encrypted_save_path, "ab");
if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ)) if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ))
Expand All @@ -324,19 +317,18 @@ void WiiSave::ImportWiiSaveFiles()


FileHDR file_hdr_tmp; FileHDR file_hdr_tmp;


for (u32 i = 0; i < m_files_list_size; ++i) for (u32 i = 0; i < m_bk_hdr.number_of_files; ++i)
{ {
memset(&file_hdr_tmp, 0, FILE_HDR_SZ); memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
memset(m_iv, 0, 0x10); memset(m_iv, 0, 0x10);
u32 file_size = 0;


if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ)) if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ))
{ {
ERROR_LOG(CONSOLE, "Failed to read header for file %d", i); ERROR_LOG(CONSOLE, "Failed to read header for file %d", i);
m_valid = false; m_valid = false;
} }


if (Common::swap32(file_hdr_tmp.magic) != FILE_HDR_MAGIC) if (file_hdr_tmp.magic != FILE_HDR_MAGIC)
{ {
ERROR_LOG(CONSOLE, "Bad File Header"); ERROR_LOG(CONSOLE, "Bad File Header");
break; break;
Expand All @@ -352,8 +344,7 @@ void WiiSave::ImportWiiSaveFiles()
const File::FileInfo file_info(file_path_full); const File::FileInfo file_info(file_path_full);
if (file_hdr_tmp.type == 1) if (file_hdr_tmp.type == 1)
{ {
file_size = Common::swap32(file_hdr_tmp.size); u32 file_size_rounded = Common::AlignUp<u32>(file_hdr_tmp.size, BLOCK_SZ);
u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ);
std::vector<u8> file_data(file_size_rounded); std::vector<u8> file_data(file_size_rounded);
std::vector<u8> file_data_enc(file_size_rounded); std::vector<u8> file_data_enc(file_size_rounded);


Expand All @@ -371,7 +362,7 @@ void WiiSave::ImportWiiSaveFiles()
INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str()); INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str());


File::IOFile raw_save_file(file_path_full, "wb"); File::IOFile raw_save_file(file_path_full, "wb");
raw_save_file.WriteBytes(file_data.data(), file_size); raw_save_file.WriteBytes(file_data.data(), file_hdr_tmp.size);
} }
else if (file_hdr_tmp.type == 2) else if (file_hdr_tmp.type == 2)
{ {
Expand All @@ -396,7 +387,7 @@ void WiiSave::ExportWiiSaveFiles()
if (!m_valid) if (!m_valid)
return; return;


for (u32 i = 0; i < m_files_list_size; i++) for (u32 i = 0; i < m_bk_hdr.number_of_files; i++)
{ {
FileHDR file_hdr_tmp; FileHDR file_hdr_tmp;
memset(&file_hdr_tmp, 0, FILE_HDR_SZ); memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
Expand All @@ -414,8 +405,8 @@ void WiiSave::ExportWiiSaveFiles()
} }


u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ); u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ);
file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC); file_hdr_tmp.magic = FILE_HDR_MAGIC;
file_hdr_tmp.size = Common::swap32(file_size); file_hdr_tmp.size = file_size;
file_hdr_tmp.permissions = 0x3c; file_hdr_tmp.permissions = 0x3c;


std::string name = std::string name =
Expand Down Expand Up @@ -514,7 +505,7 @@ void WiiSave::do_sig()
generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash);
make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0);


data_size = Common::swap32(m_bk_hdr.size_of_files) + 0x80; data_size = m_bk_hdr.size_of_files + 0x80;


File::IOFile data_file(m_encrypted_save_path, "rb"); File::IOFile data_file(m_encrypted_save_path, "rb");
if (!data_file) if (!data_file)
Expand Down
33 changes: 15 additions & 18 deletions Source/Core/Core/HW/WiiSave.h
Expand Up @@ -9,6 +9,7 @@
#include <vector> #include <vector>


#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Swap.h"


class WiiSave class WiiSave
{ {
Expand Down Expand Up @@ -44,10 +45,6 @@ class WiiSave


u8 m_iv[0x10]; u8 m_iv[0x10];


u32 m_files_list_size;
u32 m_size_of_files;
u32 m_total_size;

u64 m_title_id; u64 m_title_id;


bool m_valid; bool m_valid;
Expand Down Expand Up @@ -78,12 +75,12 @@ class WiiSave


struct DataBinHeader // encrypted struct DataBinHeader // encrypted
{ {
u64 save_game_title; Common::BigEndianValue<u64> save_game_title;
u32 banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0) Common::BigEndianValue<u32> banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0)
u8 permissions; u8 permissions;
u8 unk1; // maybe permissions is a be16 u8 unk1; // maybe permissions is a be16
u8 md5[0x10]; // md5 of plaintext header with md5 blanker applied u8 md5[0x10]; // md5 of plaintext header with md5 blanker applied
u16 unk2; Common::BigEndianValue<u16> unk2;
}; };


struct Header struct Header
Expand All @@ -94,26 +91,26 @@ class WiiSave


struct BkHeader // Not encrypted struct BkHeader // Not encrypted
{ {
u32 size; // 0x00000070 Common::BigEndianValue<u32> size; // 0x00000070
// u16 magic; // 'Bk' // u16 magic; // 'Bk'
// u16 magic2; // or version (0x0001) // u16 magic2; // or version (0x0001)
u32 magic; // 0x426B0001 Common::BigEndianValue<u32> magic; // 0x426B0001
u32 ngid; Common::BigEndianValue<u32> ngid;
u32 number_of_files; Common::BigEndianValue<u32> number_of_files;
u32 size_of_files; Common::BigEndianValue<u32> size_of_files;
u32 unk1; Common::BigEndianValue<u32> unk1;
u32 unk2; Common::BigEndianValue<u32> unk2;
u32 total_size; Common::BigEndianValue<u32> total_size;
u8 unk3[64]; u8 unk3[64];
u64 save_game_title; Common::BigEndianValue<u64> save_game_title;
u8 mac_address[6]; u8 mac_address[6];
u8 padding[0x12]; u8 padding[0x12];
}; };


struct FileHDR // encrypted struct FileHDR // encrypted
{ {
u32 magic; // 0x03adf17e Common::BigEndianValue<u32> magic; // 0x03adf17e
u32 size; Common::BigEndianValue<u32> size;
u8 permissions; u8 permissions;
u8 attrib; u8 attrib;
u8 type; // (1=file, 2=directory) u8 type; // (1=file, 2=directory)
Expand Down

0 comments on commit 956df21

Please sign in to comment.