From 8b736cf7c5f0b6332c006f097e98805a55f201ca Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Tue, 5 Jan 2010 07:34:03 +0000 Subject: [PATCH] Work towards importing data.bin wii save files (issue 1945) so far only tested with NSMB save (which works) !!backup any existing save before importing save for the same game!! also adds VS files and folders to the ignore list git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4784 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DolphinWX/DolphinWX.vcproj | 92 +++---- Source/Core/DolphinWX/Src/Frame.cpp | 1 + Source/Core/DolphinWX/Src/Frame.h | 1 + Source/Core/DolphinWX/Src/FrameTools.cpp | 28 ++- Source/Core/DolphinWX/Src/Globals.h | 1 + .../Src/MemoryCards/WiiSaveCrypted.cpp | 225 ++++++++++++++++++ .../Src/MemoryCards/WiiSaveCrypted.h | 114 +++++++++ 7 files changed, 419 insertions(+), 43 deletions(-) create mode 100644 Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp create mode 100644 Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h 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