diff --git a/Source/Core/DolphinWX/DolphinWX.vcproj b/Source/Core/DolphinWX/DolphinWX.vcproj index fa39cb8e9f..0af4eef3e1 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcproj +++ b/Source/Core/DolphinWX/DolphinWX.vcproj @@ -1097,46 +1097,6 @@ RelativePath=".\src\GameListCtrl.h" > - - - - - - - - - - - - - - - - @@ -1505,6 +1465,58 @@ > + + + + + + + + + + + + + + + + + + + + + + Append(IDM_LUA, _T("New &Lua Console")); - toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager")); + toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager (GC)")); + toolsMenu->Append(IDM_IMPORTSAVE, _T("Wii Save Import (experimental)")); toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager")); #if defined(HAVE_SFML) && HAVE_SFML @@ -782,10 +784,30 @@ void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event)) void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) { -m_bModalDialogOpen = true; + m_bModalDialogOpen = true; CMemcardManager MemcardManager(this); MemcardManager.ShowModal(); -m_bModalDialogOpen = false; + m_bModalDialogOpen = false; +} + +void CFrame::OnImportSave(wxCommandEvent& WXUNUSED (event)) +{ + wxString path = wxFileSelector(_T("Select the save file"), + wxEmptyString, wxEmptyString, wxEmptyString, + wxString::Format + ( + _T("Wii save files|data.bin|All files (%s)|%s"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr + ), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, + this); + + if (!path.IsEmpty()) + { + CWiiSaveCrypted saveFile(path.ToUTF8().data()); + saveFile.Extract(); + } } void CFrame::OnOpenLuaWindow(wxCommandEvent& WXUNUSED (event)) diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 43341230b0..8f107b25aa 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -219,6 +219,7 @@ enum IDM_NOTIFYMAPLOADED, IDM_OPENCONTAININGFOLDER, IDM_OPENSAVEFOLDER, + IDM_IMPORTSAVE, IDM_SETDEFAULTGCM, IDM_DELETEGCM, IDM_COMPRESSGCM, diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp new file mode 100644 index 0000000000..f82bb49155 --- /dev/null +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp @@ -0,0 +1,225 @@ +// Copyright (C) 2003 Dolphin Project. + +// 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/ + +// Based off of tachtig http://git.infradead.org/?p=users/segher/wii.git + +#include "stdafx.h" + +#include "WiiSaveCrypted.h" +#include "FileUtil.h" + +u8 SD_IV[0x10] = {0x21, 0x67, 0x12, 0xE6, 0xAA, 0x1F, 0x68, 0x9F, + 0x95, 0xC5, 0xA2, 0x23, 0x24, 0xDC, 0x6A, 0x98}; + +CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName) +{ + _filename = std::string(FileName); + + const u8 SDKey[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, + 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; + AES_set_decrypt_key(SDKey, 128, &m_AES_KEY); + b_valid = true; + ReadHDR(); + ReadBKHDR(); +} + +void CWiiSaveCrypted::ReadHDR() +{ + saveFileP = fopen(_filename.c_str(), "rb"); + if (!saveFileP) + { + PanicAlert("Cannot open %s", _filename.c_str()); + b_valid = false; + return; + } + Data_Bin_HDR * tmpHDR = new Data_Bin_HDR; + + if (fread(tmpHDR, HDR_SZ, 1, saveFileP) != 1) + { + PanicAlert("failed to read header"); + b_valid = false; + return; + } + AES_cbc_encrypt((const u8*)tmpHDR, (u8*)&hdr, HDR_SZ, &m_AES_KEY, SD_IV, AES_DECRYPT); + delete tmpHDR; + _bannerSize = Common::swap32(hdr.BannerSize); + if ((_bannerSize < FULL_BNR_MIN) || (_bannerSize > FULL_BNR_MAX) || + (((_bannerSize - BNR_SZ) % ICON_SZ) != 0)) + { + PanicAlert("not a wii save or read failure for file header size %x", _bannerSize); + b_valid = false; + return; + } + _saveGameTitle = Common::swap64(hdr.SaveGameTitle); + fclose(saveFileP); +} +void CWiiSaveCrypted::ReadBKHDR() +{ + if (!b_valid) return; + saveFileP = fopen(_filename.c_str(), "rb"); + if (!saveFileP) + { + PanicAlert("Cannot open %s", _filename.c_str()); + b_valid = false; + return; + } + fseek(saveFileP, HDR_SZ + FULL_BNR_MAX/*_bannerSize*/, SEEK_SET); + + if (fread(&bkhdr, BK_SZ, 1, saveFileP) != 1) + { + PanicAlert("failed to read bk header"); + b_valid = false; + return; + } + + if (Common::swap64((u8*)&bkhdr) != 0x00000070426b0001ULL) + { + PanicAlert("Invalid Size or Magic word %016llx", bkhdr); + b_valid = false; + return; + } + if (_saveGameTitle != Common::swap64(bkhdr.SaveGameTitle)) + WARN_LOG(CONSOLE, "encrypted title (%x) does not match unencrypted title (%x)", _saveGameTitle, Common::swap64(bkhdr.SaveGameTitle)); + + _numberOfFiles = Common::swap32(bkhdr.numberOfFiles); + _sizeOfFiles = Common::swap32(bkhdr.sizeOfFiles); + _totalSize = Common::swap32(bkhdr.totalSize); + fclose(saveFileP); +} + +void CWiiSaveCrypted::Extract() +{ + if (!b_valid) return; + + saveFileP = fopen(_filename.c_str(), "rb"); + if (!saveFileP) + { + PanicAlert("Cannot open %s", _filename.c_str()); + b_valid = false; + return; + } + + sprintf(dir, FULL_WII_USER_DIR "title/%08x/%08x/data/", (u32)(_saveGameTitle>>32), (u32)_saveGameTitle); + + if (!PanicYesNo("Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to continue?", dir)) + return; + + INFO_LOG(CONSOLE, "%s", dir); + File::CreateFullPath(dir); + + fseek(saveFileP, HDR_SZ, SEEK_SET); + + _encryptedData = new u8[_bannerSize]; + _data = new u8[_bannerSize]; + if (fread(_encryptedData, _bannerSize, 1, saveFileP) != 1) + { + PanicAlert("failed to read banner"); + b_valid = false; + return; + } + + AES_cbc_encrypt((const u8*)_encryptedData, (u8*)_data, _bannerSize, &m_AES_KEY, SD_IV, AES_DECRYPT); + delete []_encryptedData; + + sprintf(path, "%sbanner.bin", dir); + + // remove after code is more thoroughly tested + sprintf(tmpPath, "%s.bak", path); + File::Copy(path, tmpPath); + // + + if (!File::Exists(path) || PanicYesNo("%s already exists, overwrite?", path)) + { + INFO_LOG(CONSOLE, "creating file %s", path); + outFileP = fopen(path, "wb"); + if (outFileP) + { + fwrite(_data, _bannerSize, 1, outFileP); + fclose(outFileP); + } + } + delete []_data; + + int lastpos = HDR_SZ + FULL_BNR_MAX /*_bannerSize */+ BK_SZ; + + + + + FileHDR _tmpFileHDR; + + for(u32 i = 0; i < _numberOfFiles; i++) + { + fseek(saveFileP, lastpos, SEEK_SET); + memset(&_tmpFileHDR, 0, FILE_HDR_SZ); + memset(IV, 0, 0x10); + u32 roundedsize; + + fread(&_tmpFileHDR, FILE_HDR_SZ, 1, saveFileP); + lastpos += FILE_HDR_SZ; + if(Common::swap32(_tmpFileHDR.magic) != 0x03adf17e) + { + PanicAlert("Bad File Header"); + break; + } + else + { + sprintf(path, "%s%s", dir, _tmpFileHDR.name); + if (_tmpFileHDR.type == 2) + { + PanicAlert("savegame with a dir, report me :p, %s", path); + // we should prolly write any future files to this new dir + // but tachtig doesnt do this... + File::CreateFullPath(path); + } + else + { + roundedsize = (Common::swap32(_tmpFileHDR.size));// + 63) & ~63; // rounding makes corrupted files for NSMBwii + lastpos += roundedsize; + _encryptedData = new u8[roundedsize]; + _data = new u8[roundedsize]; + fread(_encryptedData, roundedsize, 1, saveFileP); + memcpy(IV, _tmpFileHDR.IV, 0x10); + AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, roundedsize, &m_AES_KEY, IV, AES_DECRYPT); + delete []_encryptedData; + + // remove after code is more thoroughly tested + sprintf(tmpPath, "%s.bak", path); + File::Copy(path, tmpPath); + // + if (!File::Exists(path) || PanicYesNo("%s already exists, overwrite?", path)) + { + INFO_LOG(CONSOLE, "creating file %s", path); + + outFileP = fopen(path, "wb"); + if (outFileP) + { + fwrite(_data, roundedsize, 1, outFileP); + fclose(outFileP); + } + } + delete []_data; + } + + } + } +fclose(saveFileP); +} + +CWiiSaveCrypted::~CWiiSaveCrypted() +{ +} + diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h new file mode 100644 index 0000000000..1fa4673428 --- /dev/null +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h @@ -0,0 +1,114 @@ +// Copyright (C) 2003 Dolphin Project. + +// 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/ + +#ifndef _WII_SAVE_CRYPTED +#define _WII_SAVE_CRYPTED + +#include "AES/aes.h" +#include "StringUtil.h" + +// --- this is used for encrypted Wii save files + + + +class CWiiSaveCrypted +{ +public: + CWiiSaveCrypted(const char* FileName); + ~CWiiSaveCrypted(); + void ReadHDR(); + void ReadBKHDR(); + void Extract(); + +private: + FILE *saveFileP, + *outFileP; + AES_KEY m_AES_KEY; + + u8 IV[0x10], + *_encryptedData, + *_data; + + char dir[1024], + path[1024], + tmpPath[1024]; + + u32 _bannerSize, + _numberOfFiles, + _sizeOfFiles, + _totalSize; + + u64 _saveGameTitle; + + std::string _filename; + + bool b_valid; + + enum + { + HDR_SZ = 0x20, + BK_SZ = 0x80, + FILE_HDR_SZ = 0x80, + ICON_SZ = 0x1200, + BNR_SZ = 0x60a0, + FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ + FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ + }; + +#pragma pack(push,1) + struct Data_Bin_HDR // encrypted + { + u64 SaveGameTitle; + u32 BannerSize; // (0x72A0 or 0xF0A0, also seen 0xBAA0) + u8 Permissions; + u8 unk1; // maybe permissions is a be16 + u8 Md5[0x10]; // md5 of plaintext header with md5 blanker applied + u16 unk2; + }hdr; + + struct BK_Header // Not encrypted + { + u32 size; // 0x00000070 + u16 magic; // 'Bk' + u16 magic2; // or version (0x0001) + u32 NGid; + u32 numberOfFiles; + u32 sizeOfFiles; + u32 unk1; + u32 unk2; + u32 totalSize; + u8 unk3[64]; + u64 SaveGameTitle; + u64 MACaddress; + u8 padding[0x10]; + }bkhdr; + + struct FileHDR // encrypted + { + u32 magic; //0x03adf17e + u32 size; + u8 Permissions; + u8 attrib; + u8 type; // (1=file, 2=directory) + u8 name[0x45]; + u8 IV[0x10]; + u8 unk[0x20]; + }; +#pragma pack(pop) +}; + +#endif