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; }
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; }
bool CVolumeWiiCrypted::CheckIntegrity() const { // Get partition data size u32 partSizeDiv4; RAWRead(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4); u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4; u32 nClusters = (u32)(partDataSize / 0x8000); for (u32 clusterID = 0; clusterID < nClusters; ++clusterID) { u64 clusterOff = m_VolumeOffset + dataOffset + (u64)clusterID * 0x8000; // Read and decrypt the cluster metadata u8 clusterMDCrypted[0x400]; u8 clusterMD[0x400]; u8 IV[16] = { 0 }; if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID); return false; } AES_cbc_encrypt(clusterMDCrypted, clusterMD, 0x400, &m_AES_KEY, IV, AES_DECRYPT); // Some clusters have invalid data and metadata because they aren't // meant to be read by the game (for example, holes between files). To // try to avoid reporting errors because of these clusters, we check // the 0x00 paddings in the metadata. // // This may cause some false negatives though: some bad clusters may be // skipped because they are *too* bad and are not even recognized as // valid clusters. To be improved. bool meaningless = false; for (u32 idx = 0x26C; idx < 0x280; ++idx) if (clusterMD[idx] != 0) meaningless = true; if (meaningless) continue; u8 clusterData[0x7C00]; if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID); return false; } for (u32 hashID = 0; hashID < 31; ++hashID) { u8 hash[20]; sha1(clusterData + hashID * 0x400, 0x400, hash); // Note that we do not use strncmp here if (memcmp(hash, clusterMD + hashID * 20, 20)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID, hashID); return false; } } } return true; }
bool CVolumeWiiCrypted::GetTitleID(u8* _pBuffer) const { // Tik is at m_VolumeOffset size 0x2A4 // TitleID offset in tik is 0x1DC return RAWRead(m_VolumeOffset + 0x1DC, 8, _pBuffer); }