Merge pull request #1618 from JosJuice/dvd-low-open-partition

Fix Wii disc partitions
This commit is contained in:
skidau 2014-12-03 21:24:56 +11:00
commit b9b3277fb5
8 changed files with 107 additions and 69 deletions

View File

@ -225,14 +225,12 @@ bool CBoot::BootUp()
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
u32 _TMDsz = 0x208;
u8* _pTMD = new u8[_TMDsz];
pVolume->GetTMD(_pTMD, &_TMDsz);
if (_TMDsz)
u32 tmd_size;
std::unique_ptr<u8[]> tmd_buf = pVolume->GetTMD(&tmd_size);
if (tmd_size)
{
WII_IPC_HLE_Interface::ES_DIVerify(_pTMD, _TMDsz);
WII_IPC_HLE_Interface::ES_DIVerify(tmd_buf.get(), tmd_size);
}
delete []_pTMD;
_StartupPara.bWii = VolumeHandler::IsWii();

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cinttypes>
#include <memory>
#include "Common/CommonTypes.h"
#include "Common/Logging/LogManager.h"
@ -107,19 +108,16 @@ bool CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress)
_dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[1].m_Address == 0, "DVDLowOpenPartition with ticket");
_dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[2].m_Address == 0, "DVDLowOpenPartition with cert chain");
// Get TMD offset for requested partition...
u64 const TMDOffset = ((u64)Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address + 4) << 2 ) + 0x2c0;
u64 const partition_offset = ((u64)Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address + 4) << 2);
VolumeHandler::GetVolume()->ChangePartition(partition_offset);
INFO_LOG(WII_IPC_DVD, "DVDLowOpenPartition: TMDOffset 0x%016" PRIx64, TMDOffset);
static u32 const TMDsz = 0x208; //CommandBuffer.PayloadBuffer[0].m_Size;
u8 pTMD[TMDsz];
INFO_LOG(WII_IPC_DVD, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset);
// Read TMD to the buffer
VolumeHandler::RAWReadToPtr(pTMD, TMDOffset, TMDsz);
Memory::CopyToEmu(CommandBuffer.PayloadBuffer[0].m_Address, pTMD, TMDsz);
WII_IPC_HLE_Interface::ES_DIVerify(pTMD, TMDsz);
u32 tmd_size;
std::unique_ptr<u8[]> tmd_buf = VolumeHandler::GetVolume()->GetTMD(&tmd_size);
Memory::CopyToEmu(CommandBuffer.PayloadBuffer[0].m_Address, tmd_buf.get(), tmd_size);
WII_IPC_HLE_Interface::ES_DIVerify(tmd_buf.get(), tmd_size);
ReturnValue = 1;
}

View File

@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
@ -20,7 +21,11 @@ public:
virtual bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const = 0;
virtual bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const = 0;
virtual bool GetTitleID(u8*) const { return false; }
virtual void GetTMD(u8*, u32 *_sz) const { *_sz=0; }
virtual std::unique_ptr<u8[]> GetTMD(u32 *_sz) const
{
*_sz = 0;
return std::unique_ptr<u8[]>();
}
virtual std::string GetUniqueID() const = 0;
virtual std::string GetRevisionSpecificUniqueID() const { return ""; }
virtual std::string GetMakerID() const = 0;
@ -34,6 +39,8 @@ public:
virtual bool CheckIntegrity() const { return false; }
virtual bool IsDiscTwo() const { return false; }
virtual bool ChangePartition(u64 offset) { return false; }
// Increment CACHE_REVISION if values are changed (ISOFile.cpp)
enum ECountry
{

View File

@ -69,7 +69,7 @@ static const unsigned char s_master_key_korean[16] = {
0x13,0xf2,0xfe,0xfb,0xba,0x4c,0x9b,0x7e
};
static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum, bool Korean);
static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum);
EDiscType GetDiscType(IBlobReader& _rReader);
IVolume* CreateVolumeFromFilename(const std::string& _rFilename, u32 _PartitionGroup, u32 _VolumeNum)
@ -89,10 +89,7 @@ IVolume* CreateVolumeFromFilename(const std::string& _rFilename, u32 _PartitionG
case DISC_TYPE_WII_CONTAINER:
{
u8 region;
pReader->Read(0x3,1,&region);
IVolume* pVolume = CreateVolumeFromCryptedWiiImage(*pReader, _PartitionGroup, 0, _VolumeNum, region == 'K');
IVolume* pVolume = CreateVolumeFromCryptedWiiImage(*pReader, _PartitionGroup, 0, _VolumeNum);
if (pVolume == nullptr)
{
@ -140,7 +137,32 @@ bool IsVolumeWadFile(const IVolume *_rVolume)
return (Common::swap32(MagicWord) == 0x00204973 || Common::swap32(MagicWord) == 0x00206962);
}
static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum, bool Korean)
void VolumeKeyForParition(IBlobReader& _rReader, u64 offset, u8* VolumeKey)
{
CBlobBigEndianReader Reader(_rReader);
u8 SubKey[16];
_rReader.Read(offset + 0x1bf, 16, SubKey);
u8 IV[16];
memset(IV, 0, 16);
_rReader.Read(offset + 0x44c, 8, IV);
bool usingKoreanKey = false;
// Issue: 6813
// Magic value is at partition's offset + 0x1f1 (1byte)
// If encrypted with the Korean key, the magic value would be 1
// Otherwise it is zero
if (Reader.Read8(0x3) == 'K' && Reader.Read8(offset + 0x1f1) == 1)
usingKoreanKey = true;
aes_context AES_ctx;
aes_setkey_dec(&AES_ctx, (usingKoreanKey ? s_master_key_korean : s_master_key), 128);
aes_crypt_cbc(&AES_ctx, AES_DECRYPT, 16, IV, SubKey, VolumeKey);
}
static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum)
{
CBlobBigEndianReader Reader(_rReader);
@ -184,32 +206,11 @@ static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _Part
{
const SPartition& rPartition = PartitionGroup[_PartitionGroup].PartitionsVec.at(i);
if (rPartition.Type == _VolumeType || i == _VolumeNum)
if ((rPartition.Type == _VolumeType && (int)_VolumeNum == -1) || i == _VolumeNum)
{
u8 SubKey[16];
_rReader.Read(rPartition.Offset + 0x1bf, 16, SubKey);
u8 IV[16];
memset(IV, 0, 16);
_rReader.Read(rPartition.Offset + 0x44c, 8, IV);
bool usingKoreanKey = false;
// Issue: 6813
// Magic value is at partition's offset + 0x1f1 (1byte)
// If encrypted with the Korean key, the magic value would be 1
// Otherwise it is zero
if (Korean && Reader.Read8(rPartition.Offset + 0x1f1) == 1)
usingKoreanKey = true;
aes_context AES_ctx;
aes_setkey_dec(&AES_ctx, (usingKoreanKey ? s_master_key_korean : s_master_key), 128);
u8 VolumeKey[16];
aes_crypt_cbc(&AES_ctx, AES_DECRYPT, 16, IV, SubKey, VolumeKey);
// -1 means the caller just wanted the partition with matching type
if ((int)_VolumeNum == -1 || i == _VolumeNum)
return new CVolumeWiiCrypted(&_rReader, rPartition.Offset, VolumeKey);
VolumeKeyForParition(_rReader, rPartition.Offset, VolumeKey);
return new CVolumeWiiCrypted(&_rReader, rPartition.Offset, VolumeKey);
}
}

View File

@ -12,10 +12,12 @@ namespace DiscIO
{
class IVolume;
class IBlobReader;
IVolume* CreateVolumeFromFilename(const std::string& _rFilename, u32 _PartitionGroup = 0, u32 _VolumeNum = -1);
IVolume* CreateVolumeFromDirectory(const std::string& _rDirectory, bool _bIsWii, const std::string& _rApploader = "", const std::string& _rDOL = "");
bool IsVolumeWiiDisc(const IVolume *_rVolume);
bool IsVolumeWadFile(const IVolume *_rVolume);
void VolumeKeyForParition(IBlobReader& _rReader, u64 offset, u8* VolumeKey);
} // namespace

View File

@ -11,9 +11,11 @@
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Common/Logging/Log.h"
#include "DiscIO/Blob.h"
#include "DiscIO/Volume.h"
#include "DiscIO/VolumeCreator.h"
#include "DiscIO/VolumeGC.h"
#include "DiscIO/VolumeWiiCrypted.h"
@ -33,6 +35,17 @@ CVolumeWiiCrypted::CVolumeWiiCrypted(IBlobReader* _pReader, u64 _VolumeOffset,
m_pBuffer = new u8[0x8000];
}
bool CVolumeWiiCrypted::ChangePartition(u64 offset)
{
m_VolumeOffset = offset;
m_LastDecryptedBlockOffset = -1;
u8 volume_key[16];
DiscIO::VolumeKeyForParition(*m_pReader, offset, volume_key);
aes_setkey_dec(m_AES_ctx.get(), volume_key, 128);
return true;
}
CVolumeWiiCrypted::~CVolumeWiiCrypted()
{
@ -96,18 +109,32 @@ bool CVolumeWiiCrypted::GetTitleID(u8* _pBuffer) const
// TitleID offset in tik is 0x1DC
return RAWRead(m_VolumeOffset + 0x1DC, 8, _pBuffer);
}
void CVolumeWiiCrypted::GetTMD(u8* _pBuffer, u32 * _sz) const
{
*_sz = 0;
u32 tmdSz,
tmdAddr;
RAWRead(m_VolumeOffset + 0x2a4, sizeof(u32), (u8*)&tmdSz);
RAWRead(m_VolumeOffset + 0x2a8, sizeof(u32), (u8*)&tmdAddr);
tmdSz = Common::swap32(tmdSz);
tmdAddr = Common::swap32(tmdAddr) << 2;
RAWRead(m_VolumeOffset + tmdAddr, tmdSz, _pBuffer);
*_sz = tmdSz;
std::unique_ptr<u8[]> CVolumeWiiCrypted::GetTMD(u32 *size) const
{
*size = 0;
u32 tmd_size;
u32 tmd_address;
RAWRead(m_VolumeOffset + 0x2a4, sizeof(u32), (u8*)&tmd_size);
RAWRead(m_VolumeOffset + 0x2a8, sizeof(u32), (u8*)&tmd_address);
tmd_size = Common::swap32(tmd_size);
tmd_address = Common::swap32(tmd_address) << 2;
if (tmd_size > 1024 * 1024 * 4)
{
// The size is checked so that a malicious or corrupt ISO
// can't force Dolphin to allocate up to 4 GiB of memory.
// 4 MiB should be much bigger than the size of TMDs and much smaller
// than the amount of RAM in a computer that can run Dolphin.
PanicAlert("TMD > 4 MiB");
tmd_size = 1024 * 1024 * 4;
}
std::unique_ptr<u8[]> buf{ new u8[tmd_size] };
RAWRead(m_VolumeOffset + tmd_address, tmd_size, buf.get());
*size = tmd_size;
return buf;
}
std::string CVolumeWiiCrypted::GetUniqueID() const

View File

@ -27,7 +27,7 @@ public:
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const override;
bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const override;
bool GetTitleID(u8* _pBuffer) const override;
void GetTMD(u8* _pBuffer, u32* _sz) const override;
virtual std::unique_ptr<u8[]> GetTMD(u32 *_sz) const override;
std::string GetUniqueID() const override;
std::string GetMakerID() const override;
std::vector<std::string> GetNames() const override;
@ -41,6 +41,8 @@ public:
bool SupportsIntegrityCheck() const override { return true; }
bool CheckIntegrity() const override;
bool ChangePartition(u64 offset) override;
private:
std::unique_ptr<IBlobReader> m_pReader;
std::unique_ptr<aes_context> m_AES_ctx;

View File

@ -130,20 +130,23 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW
bool IsWiiDisc = DiscIO::IsVolumeWiiDisc(OpenISO);
if (IsWiiDisc)
{
for (u32 i = 0; i < 0xFFFFFFFF; i++) // yes, technically there can be OVER NINE THOUSAND partitions...
for (int group = 0; group < 4; group++)
{
WiiPartition temp;
if ((temp.Partition = DiscIO::CreateVolumeFromFilename(fileName, 0, i)) != nullptr)
for (u32 i = 0; i < 0xFFFFFFFF; i++) // yes, technically there can be OVER NINE THOUSAND partitions...
{
if ((temp.FileSystem = DiscIO::CreateFileSystem(temp.Partition)) != nullptr)
WiiPartition temp;
if ((temp.Partition = DiscIO::CreateVolumeFromFilename(fileName, group, i)) != nullptr)
{
temp.FileSystem->GetFileList(temp.Files);
WiiDisc.push_back(temp);
if ((temp.FileSystem = DiscIO::CreateFileSystem(temp.Partition)) != nullptr)
{
temp.FileSystem->GetFileList(temp.Files);
WiiDisc.push_back(temp);
}
}
else
{
break;
}
}
else
{
break;
}
}
}