| 
									
										
										
										
											2009-07-28 21:32:10 +00:00
										 |  |  | // Copyright (C) 2003 Dolphin Project.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU General Public License 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-22 06:00:36 +00:00
										 |  |  | #include "Crypto/aes.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "VolumeCreator.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Volume.h"
 | 
					
						
							|  |  |  | #include "VolumeDirectory.h"
 | 
					
						
							|  |  |  | #include "VolumeGC.h"
 | 
					
						
							|  |  |  | #include "VolumeWiiCrypted.h"
 | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | #include "VolumeWad.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "Hash.h"
 | 
					
						
							| 
									
										
										
										
											2010-01-11 05:07:56 +00:00
										 |  |  | #include "StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace DiscIO | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | enum EDiscType | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	DISC_TYPE_UNK, | 
					
						
							|  |  |  | 	DISC_TYPE_WII, | 
					
						
							|  |  |  | 	DISC_TYPE_WII_CONTAINER, | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | 	DISC_TYPE_GC, | 
					
						
							|  |  |  | 	DISC_TYPE_WAD | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef _WIN32
 | 
					
						
							|  |  |  | struct SPartition | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 Offset; | 
					
						
							|  |  |  | 	u32 Type; | 
					
						
							|  |  |  | }; //gcc 4.3 cries if it's local
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CBlobBigEndianReader | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	CBlobBigEndianReader(IBlobReader& _rReader) : m_rReader(_rReader) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u32 Read32(u64 _Offset) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		u32 Temp; | 
					
						
							|  |  |  | 		m_rReader.Read(_Offset, 4, (u8*)&Temp); | 
					
						
							|  |  |  | 		return(Common::swap32(Temp)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	IBlobReader& m_rReader; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-26 13:29:51 +00:00
										 |  |  | const unsigned char g_MasterKey[16] = {0xeb,0xe4,0x2a,0x22,0x5e,0x85,0x93,0xe4,0x48,0xd9,0xc5,0x45,0x73,0x81,0xaa,0xf7}; | 
					
						
							|  |  |  | const unsigned char g_MasterKeyK[16] = {0x63,0xb8,0x2b,0xb4,0xf4,0x61,0x4e,0x2e,0x13,0xf2,0xfe,0xfb,0xba,0x4c,0x9b,0x7e}; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-02 18:21:20 +00:00
										 |  |  | static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum, bool Korean); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | EDiscType GetDiscType(IBlobReader& _rReader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | IVolume* CreateVolumeFromFilename(const std::string& _rFilename, u32 _PartitionGroup, u32 _VolumeNum) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	IBlobReader* pReader = CreateBlobReader(_rFilename.c_str()); | 
					
						
							|  |  |  | 	if (pReader == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (GetDiscType(*pReader)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 		case DISC_TYPE_WII: | 
					
						
							|  |  |  | 		case DISC_TYPE_GC: | 
					
						
							|  |  |  | 			return new CVolumeGC(pReader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | 		case DISC_TYPE_WAD: | 
					
						
							|  |  |  | 			return new CVolumeWAD(pReader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 		case DISC_TYPE_WII_CONTAINER: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			u8 region; | 
					
						
							|  |  |  | 			pReader->Read(0x3,1,®ion); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 			IVolume* pVolume = CreateVolumeFromCryptedWiiImage(*pReader, _PartitionGroup, 0, _VolumeNum, region == 'K'); | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (pVolume == NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				delete pReader; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-24 19:57:29 +00:00
										 |  |  | 			return pVolume; | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case DISC_TYPE_UNK: | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2010-01-11 05:07:56 +00:00
										 |  |  | 			std::string Filename, ext; | 
					
						
							|  |  |  | 			SplitPath(_rFilename, NULL, &Filename, &ext); | 
					
						
							|  |  |  | 			Filename += ext; | 
					
						
							|  |  |  | 			NOTICE_LOG(DISCIO, "%s does not have the Magic word for a gcm, wiidisc or wad file\n" | 
					
						
							|  |  |  | 						"Set Log Verbosity to Warning and attempt to load the game again to view the values", Filename.c_str()); | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 			delete pReader; | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// unreachable code
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-10 09:16:10 +00:00
										 |  |  | IVolume* CreateVolumeFromDirectory(const std::string& _rDirectory, bool _bIsWii, const std::string& _rApploader, const std::string& _rDOL) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (CVolumeDirectory::IsValidDirectory(_rDirectory)) | 
					
						
							| 
									
										
										
										
											2009-12-10 09:16:10 +00:00
										 |  |  | 		return new CVolumeDirectory(_rDirectory, _bIsWii, _rApploader, _rDOL); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool IsVolumeWiiDisc(const IVolume *_rVolume) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 MagicWord = 0; | 
					
						
							|  |  |  | 	_rVolume->Read(0x18, 4, (u8*)&MagicWord); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (Common::swap32(MagicWord) == 0x5D1C9EA3); | 
					
						
							| 
									
										
										
										
											2009-05-27 06:41:01 +00:00
										 |  |  | 	//Gamecube 0xc2339f3d
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | bool IsVolumeWadFile(const IVolume *_rVolume) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 MagicWord = 0; | 
					
						
							|  |  |  | 	_rVolume->Read(0x02, 4, (u8*)&MagicWord); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-08 02:25:21 +00:00
										 |  |  | 	return (Common::swap32(MagicWord) == 0x00204973 || Common::swap32(MagicWord) == 0x00206962); | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-02 18:21:20 +00:00
										 |  |  | static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _PartitionGroup, u32 _VolumeType, u32 _VolumeNum, bool Korean) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	CBlobBigEndianReader Reader(_rReader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 	u32 numPartitions = Reader.Read32(0x40000 + (_PartitionGroup * 8)); | 
					
						
							|  |  |  | 	u64 PartitionsOffset = (u64)Reader.Read32(0x40000 + (_PartitionGroup * 8) + 4) << 2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-10 17:19:30 +00:00
										 |  |  | 	// Check if we're looking for a valid partition
 | 
					
						
							| 
									
										
										
										
											2010-02-24 03:38:36 +00:00
										 |  |  | 	if ((int)_VolumeNum != -1 && _VolumeNum > numPartitions) | 
					
						
							| 
									
										
										
										
											2009-03-10 17:19:30 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	#ifdef _WIN32
 | 
					
						
							|  |  |  | 	struct SPartition | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		u64 Offset; | 
					
						
							|  |  |  | 		u32 Type; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	#endif
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 	struct SPartitionGroup | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		u32 numPartitions; | 
					
						
							|  |  |  | 		u64 PartitionsOffset; | 
					
						
							|  |  |  | 		std::vector<SPartition> PartitionsVec; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	SPartitionGroup PartitionGroup[4]; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	// read all partitions
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 	for (u32 x = 0; x < 4; x++) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 		for (u32 i = 0; i < numPartitions; i++) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			SPartition Partition; | 
					
						
							|  |  |  | 			Partition.Offset = ((u64)Reader.Read32(PartitionsOffset + (i * 8) + 0)) << 2; | 
					
						
							|  |  |  | 			Partition.Type   = Reader.Read32(PartitionsOffset + (i * 8) + 4); | 
					
						
							|  |  |  | 			PartitionGroup[x].PartitionsVec.push_back(Partition); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-10 17:19:30 +00:00
										 |  |  | 	// return the partition type specified or number
 | 
					
						
							|  |  |  | 	// types: 0 = game, 1 = firmware update, 2 = channel installer
 | 
					
						
							|  |  |  | 	//  some partitions on ssbb use the ascii title id of the demo VC game they hold...
 | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 	for (size_t i = 0; i < PartitionGroup[_PartitionGroup].PartitionsVec.size(); i++) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-22 00:36:44 +00:00
										 |  |  | 		const SPartition& rPartition = PartitionGroup[_PartitionGroup].PartitionsVec.at(i); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-10 17:19:30 +00:00
										 |  |  | 		if (rPartition.Type == _VolumeType || i == _VolumeNum) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			u8 SubKey[16]; | 
					
						
							|  |  |  | 			_rReader.Read(rPartition.Offset + 0x1bf, 16, SubKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			u8 IV[16]; | 
					
						
							|  |  |  | 			memset(IV, 0, 16); | 
					
						
							|  |  |  | 			_rReader.Read(rPartition.Offset + 0x44c, 8, IV); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			AES_KEY AES_KEY; | 
					
						
							| 
									
										
										
										
											2009-02-16 06:17:21 +00:00
										 |  |  | 			AES_set_decrypt_key((Korean ? g_MasterKeyK : g_MasterKey), 128, &AES_KEY); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			u8 VolumeKey[16]; | 
					
						
							|  |  |  | 			AES_cbc_encrypt(SubKey, VolumeKey, 16, &AES_KEY, IV, AES_DECRYPT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-10 17:19:30 +00:00
										 |  |  | 			// -1 means the caller just wanted the partition with matching type
 | 
					
						
							| 
									
										
										
										
											2010-02-24 03:38:36 +00:00
										 |  |  | 			if ((int)_VolumeNum == -1 || i == _VolumeNum) | 
					
						
							| 
									
										
										
										
											2010-09-08 00:20:19 +00:00
										 |  |  | 				return new CVolumeWiiCrypted(&_rReader, rPartition.Offset, VolumeKey); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EDiscType GetDiscType(IBlobReader& _rReader) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CBlobBigEndianReader Reader(_rReader); | 
					
						
							| 
									
										
										
										
											2010-06-01 20:47:07 +00:00
										 |  |  | 	u32 WiiMagic = Reader.Read32(0x18); | 
					
						
							|  |  |  | 	u32 WiiContainerMagic = Reader.Read32(0x60); | 
					
						
							|  |  |  | 	u32 WADMagic = Reader.Read32(0x02); | 
					
						
							|  |  |  | 	u32 GCMagic = Reader.Read32(0x1C); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-01 20:47:07 +00:00
										 |  |  | 	// check for Wii
 | 
					
						
							|  |  |  | 	if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic != 0) | 
					
						
							|  |  |  | 		return DISC_TYPE_WII; | 
					
						
							|  |  |  | 	if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic == 0) | 
					
						
							|  |  |  | 		return DISC_TYPE_WII_CONTAINER; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | 	// check for WAD
 | 
					
						
							| 
									
										
										
										
											2010-06-01 20:47:07 +00:00
										 |  |  | 	// 0x206962 for boot2 wads
 | 
					
						
							|  |  |  | 	if (WADMagic == 0x00204973 || WADMagic == 0x00206962) | 
					
						
							|  |  |  | 		return DISC_TYPE_WAD; | 
					
						
							| 
									
										
										
										
											2009-06-07 02:54:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	// check for GC
 | 
					
						
							| 
									
										
										
										
											2010-06-01 20:47:07 +00:00
										 |  |  | 	if (GCMagic == 0xC2339F3D) | 
					
						
							|  |  |  | 		return DISC_TYPE_GC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WARN_LOG(DISCIO, "No known magic words found"); | 
					
						
							|  |  |  | 	WARN_LOG(DISCIO, "Wii  offset: 0x18 value: 0x%08x", WiiMagic); | 
					
						
							|  |  |  | 	WARN_LOG(DISCIO, "WiiC offset: 0x60 value: 0x%08x", WiiContainerMagic); | 
					
						
							|  |  |  | 	WARN_LOG(DISCIO, "WAD  offset: 0x02 value: 0x%08x", WADMagic); | 
					
						
							|  |  |  | 	WARN_LOG(DISCIO, "GC   offset: 0x1C value: 0x%08x", GCMagic); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return DISC_TYPE_UNK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace
 |