summaryrefslogtreecommitdiff
path: root/Source/Core/DiscIO
diff options
context:
space:
mode:
authorLéo Lam <leo@innovatetechnologi.es>2018-05-26 11:56:51 +0200
committerGitHub <noreply@github.com>2018-05-26 11:56:51 +0200
commit92ec97f8997fbd511406c09d83a79728cae5ec08 (patch)
tree48d6ad6d0bb23868ad1765f75e710cd140f2f91b /Source/Core/DiscIO
parent3f81c30e8ab351d1f3eb1d1d3fae81acf0bd06c5 (diff)
parent58743416bbdeb01ef36838c555bfc5419dc32e7f (diff)
Merge pull request #6947 from JosJuice/unencrypted-wii-disc
Make the support for unencrypted Wii disc images less broken
Diffstat (limited to 'Source/Core/DiscIO')
-rw-r--r--Source/Core/DiscIO/DirectoryBlob.cpp9
-rw-r--r--Source/Core/DiscIO/DiscExtractor.cpp3
-rw-r--r--Source/Core/DiscIO/Volume.h5
-rw-r--r--Source/Core/DiscIO/VolumeWii.cpp66
-rw-r--r--Source/Core/DiscIO/VolumeWii.h8
5 files changed, 65 insertions, 26 deletions
diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp
index 61aac73694..8628c50fc0 100644
--- a/Source/Core/DiscIO/DirectoryBlob.cpp
+++ b/Source/Core/DiscIO/DirectoryBlob.cpp
@@ -54,6 +54,8 @@ enum class PartitionType : u32
// 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J
constexpr u32 INVALID_REGION = 0xFF;
+constexpr u32 PARTITION_DATA_OFFSET = 0x20000;
+
constexpr u8 ENTRY_SIZE = 0x0c;
constexpr u8 FILE_ENTRY = 0;
constexpr u8 DIRECTORY_ENTRY = 1;
@@ -508,8 +510,8 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti
const u64 partition_data_size = partitions[i].partition.GetDataSize();
m_partitions.emplace(partition_address, std::move(partitions[i].partition));
- const u64 unaligned_next_partition_address =
- VolumeWii::PartitionOffsetToRawOffset(partition_data_size, Partition(partition_address));
+ const u64 unaligned_next_partition_address = VolumeWii::EncryptedPartitionOffsetToRawOffset(
+ partition_data_size, Partition(partition_address), PARTITION_DATA_OFFSET);
partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull);
}
m_data_size = partition_address;
@@ -546,7 +548,6 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti
partition_root + "h3.bin");
constexpr u32 PARTITION_HEADER_SIZE = 0x1c;
- constexpr u32 DATA_OFFSET = 0x20000;
const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000;
m_partition_headers.emplace_back(PARTITION_HEADER_SIZE);
std::vector<u8>& partition_header = m_partition_headers.back();
@@ -555,7 +556,7 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti
Write32(static_cast<u32>(cert_size), 0x8, &partition_header);
Write32(static_cast<u32>(cert_offset >> 2), 0x0C, &partition_header);
Write32(H3_OFFSET >> 2, 0x10, &partition_header);
- Write32(DATA_OFFSET >> 2, 0x14, &partition_header);
+ Write32(PARTITION_DATA_OFFSET >> 2, 0x14, &partition_header);
Write32(static_cast<u32>(data_size >> 2), 0x18, &partition_header);
m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header);
diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp
index 7494bd5ab7..eaba17b68a 100644
--- a/Source/Core/DiscIO/DiscExtractor.cpp
+++ b/Source/Core/DiscIO/DiscExtractor.cpp
@@ -361,7 +361,8 @@ bool ExportSystemData(const Volume& volume, const Partition& partition,
success &= ExportTicket(volume, partition, export_folder + "/ticket.bin");
success &= ExportTMD(volume, partition, export_folder + "/tmd.bin");
success &= ExportCertificateChain(volume, partition, export_folder + "/cert.bin");
- success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin");
+ if (volume.IsEncryptedAndHashed())
+ success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin");
}
return success;
diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h
index f1625a9681..2d800da31a 100644
--- a/Source/Core/DiscIO/Volume.h
+++ b/Source/Core/DiscIO/Volume.h
@@ -58,6 +58,7 @@ public:
return temp ? static_cast<u64>(*temp) << GetOffsetShift() : std::optional<u64>();
}
+ virtual bool IsEncryptedAndHashed() const { return false; }
virtual std::vector<Partition> GetPartitions() const { return {}; }
virtual Partition GetGamePartition() const { return PARTITION_NONE; }
virtual std::optional<u32> GetPartitionType(const Partition& partition) const { return {}; }
@@ -70,6 +71,10 @@ public:
virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; }
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
+ virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
+ {
+ return offset;
+ }
std::string GetGameID() const { return GetGameID(GetGamePartition()); }
virtual std::string GetGameID(const Partition& partition) const = 0;
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }
diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp
index d4558c0c99..9816b0cb66 100644
--- a/Source/Core/DiscIO/VolumeWii.cpp
+++ b/Source/Core/DiscIO/VolumeWii.cpp
@@ -33,19 +33,13 @@
namespace DiscIO
{
-constexpr u64 PARTITION_DATA_OFFSET = 0x20000;
-
VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
: m_pReader(std::move(reader)), m_game_partition(PARTITION_NONE),
m_last_decrypted_block(UINT64_MAX)
{
ASSERT(m_pReader);
- if (m_pReader->ReadSwapped<u32>(0x60) != u32(0))
- {
- // No partitions - just read unencrypted data like with a GC disc
- return;
- }
+ m_encrypted = m_pReader->ReadSwapped<u32>(0x60) == u32(0);
for (u32 partition_group = 0; partition_group < 4; ++partition_group)
{
@@ -118,12 +112,16 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
return file_system->IsValid() ? std::move(file_system) : nullptr;
};
+ auto get_data_offset = [this, partition]() -> u64 {
+ return ReadSwappedAndShifted(partition.offset + 0x2b8, PARTITION_NONE).value_or(0);
+ };
+
m_partitions.emplace(
partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key),
Common::Lazy<IOS::ES::TicketReader>(get_ticket),
Common::Lazy<IOS::ES::TMDReader>(get_tmd),
Common::Lazy<std::unique_ptr<FileSystem>>(get_file_system),
- *partition_type});
+ Common::Lazy<u64>(get_data_offset), *partition_type});
}
}
}
@@ -137,14 +135,21 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
if (partition == PARTITION_NONE)
return m_pReader->Read(_ReadOffset, _Length, _pBuffer);
- if (m_pReader->SupportsReadWiiDecrypted())
- return m_pReader->ReadWiiDecrypted(_ReadOffset, _Length, _pBuffer, partition.offset);
-
- // Get the decryption key for the partition
auto it = m_partitions.find(partition);
if (it == m_partitions.end())
return false;
- mbedtls_aes_context* aes_context = it->second.key->get();
+ const PartitionDetails& partition_details = it->second;
+
+ if (!m_encrypted)
+ {
+ return m_pReader->Read(partition.offset + *partition_details.data_offset + _ReadOffset, _Length,
+ _pBuffer);
+ }
+
+ if (m_pReader->SupportsReadWiiDecrypted())
+ return m_pReader->ReadWiiDecrypted(_ReadOffset, _Length, _pBuffer, partition.offset);
+
+ mbedtls_aes_context* aes_context = partition_details.key->get();
if (!aes_context)
return false;
@@ -152,8 +157,8 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
while (_Length > 0)
{
// Calculate offsets
- u64 block_offset_on_disc =
- partition.offset + PARTITION_DATA_OFFSET + _ReadOffset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE;
+ u64 block_offset_on_disc = partition.offset + *partition_details.data_offset +
+ _ReadOffset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE;
u64 data_offset_in_block = _ReadOffset % BLOCK_DATA_SIZE;
if (m_last_decrypted_block != block_offset_on_disc)
@@ -190,6 +195,11 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
return true;
}
+bool VolumeWii::IsEncryptedAndHashed() const
+{
+ return m_encrypted;
+}
+
std::vector<Partition> VolumeWii::GetPartitions() const
{
std::vector<Partition> partitions;
@@ -235,15 +245,29 @@ const FileSystem* VolumeWii::GetFileSystem(const Partition& partition) const
return it != m_partitions.end() ? it->second.file_system->get() : nullptr;
}
-u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition)
+u64 VolumeWii::EncryptedPartitionOffsetToRawOffset(u64 offset, const Partition& partition,
+ u64 partition_data_offset)
{
if (partition == PARTITION_NONE)
return offset;
- return partition.offset + PARTITION_DATA_OFFSET + (offset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE) +
+ return partition.offset + partition_data_offset + (offset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE) +
(offset % BLOCK_DATA_SIZE);
}
+u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
+{
+ auto it = m_partitions.find(partition);
+ if (it == m_partitions.end())
+ return offset;
+ const u64 data_offset = *it->second.data_offset;
+
+ if (!m_encrypted)
+ return partition.offset + data_offset + offset;
+
+ return EncryptedPartitionOffsetToRawOffset(offset, partition, data_offset);
+}
+
std::string VolumeWii::GetGameID(const Partition& partition) const
{
char ID[6];
@@ -357,11 +381,15 @@ u64 VolumeWii::GetRawSize() const
bool VolumeWii::CheckIntegrity(const Partition& partition) const
{
+ if (!m_encrypted)
+ return false;
+
// Get the decryption key for the partition
auto it = m_partitions.find(partition);
if (it == m_partitions.end())
return false;
- mbedtls_aes_context* aes_context = it->second.key->get();
+ const PartitionDetails& partition_details = it->second;
+ mbedtls_aes_context* aes_context = partition_details.key->get();
if (!aes_context)
return false;
@@ -373,7 +401,7 @@ bool VolumeWii::CheckIntegrity(const Partition& partition) const
u32 nClusters = (u32)(partDataSize / 0x8000);
for (u32 clusterID = 0; clusterID < nClusters; ++clusterID)
{
- u64 clusterOff = partition.offset + PARTITION_DATA_OFFSET + (u64)clusterID * 0x8000;
+ u64 clusterOff = partition.offset + *partition_details.data_offset + (u64)clusterID * 0x8000;
// Read and decrypt the cluster metadata
u8 clusterMDCrypted[0x400];
diff --git a/Source/Core/DiscIO/VolumeWii.h b/Source/Core/DiscIO/VolumeWii.h
index a173d17aa7..ede26959f9 100644
--- a/Source/Core/DiscIO/VolumeWii.h
+++ b/Source/Core/DiscIO/VolumeWii.h
@@ -33,6 +33,7 @@ public:
VolumeWii(std::unique_ptr<BlobReader> reader);
~VolumeWii();
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& partition) const override;
+ bool IsEncryptedAndHashed() const override;
std::vector<Partition> GetPartitions() const override;
Partition GetGamePartition() const override;
std::optional<u32> GetPartitionType(const Partition& partition) const override;
@@ -40,6 +41,9 @@ public:
const IOS::ES::TicketReader& GetTicket(const Partition& partition) const override;
const IOS::ES::TMDReader& GetTMD(const Partition& partition) const override;
const FileSystem* GetFileSystem(const Partition& partition) const override;
+ static u64 EncryptedPartitionOffsetToRawOffset(u64 offset, const Partition& partition,
+ u64 partition_data_offset);
+ u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const override;
std::string GetGameID(const Partition& partition) const override;
std::string GetMakerID(const Partition& partition) const override;
std::optional<u16> GetRevision(const Partition& partition) const override;
@@ -59,8 +63,6 @@ public:
u64 GetSize() const override;
u64 GetRawSize() const override;
- static u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition);
-
static constexpr unsigned int BLOCK_HEADER_SIZE = 0x0400;
static constexpr unsigned int BLOCK_DATA_SIZE = 0x7C00;
static constexpr unsigned int BLOCK_TOTAL_SIZE = BLOCK_HEADER_SIZE + BLOCK_DATA_SIZE;
@@ -75,12 +77,14 @@ private:
Common::Lazy<IOS::ES::TicketReader> ticket;
Common::Lazy<IOS::ES::TMDReader> tmd;
Common::Lazy<std::unique_ptr<FileSystem>> file_system;
+ Common::Lazy<u64> data_offset;
u32 type;
};
std::unique_ptr<BlobReader> m_pReader;
std::map<Partition, PartitionDetails> m_partitions;
Partition m_game_partition;
+ bool m_encrypted;
mutable u64 m_last_decrypted_block;
mutable u8 m_last_decrypted_block_data[BLOCK_DATA_SIZE];