diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Checker.cpp b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Checker.cpp index f9c466c..660b396 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Checker.cpp +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Checker.cpp @@ -19,6 +19,7 @@ #include "HeapManager.h" #include "SaveDataChecker.h" #include +#include "HeapChecker.h" namespace ConsoleBackup { @@ -58,6 +59,7 @@ void CheckSaveDataThreadFunc(bool erase) common::HeapManager heap(bufSize); if (heap.GetAddr() != NULL) { + bufSize = GetCheckedHeapSize(); s_pChecker = new NandSavedataChecker(heap.GetAddr(), bufSize); s_CheckerResult = s_pChecker->CleanUp(erase); } diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Controller.cpp b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Controller.cpp index e9630aa..a4ddc34 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Controller.cpp +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Controller.cpp @@ -32,6 +32,7 @@ namespace typedef enum BackupState { STARTUP, // 初期値 + CHECK_FCRAM, // FCRAMの確認 CHECK_SAVEDATA, // セーブデータの確認 EXPORT_TWL_NAND, // TWLセーブデータ領域の吸出し中 EXPORT_TWL_SOUND, // TWLサウンド領域の吸出し中 @@ -177,18 +178,48 @@ void ControlState(common::HardwareStateManager& manager, common::OperationMessag if (nextStep && !error) { - COMMON_LOGGER("Checking SaveData\n"); + COMMON_LOGGER("Checking Memory\n"); if(forceDelete) { s_BackupMode = BACKUP_MODE_DELETE_IF_FAILED; } - s_BackupState = CHECK_SAVEDATA; + s_BackupState = CHECK_FCRAM; } } break; + case CHECK_FCRAM: + { + static bool init = true; + if (init) + { + // ヒープをチェックする + CheckFcram(); + init = false; + } + + PutAliveMessage(operationMessage, "Checking Memory"); + + // 処理が完了した + if (IsExportThreadFinished()) + { + FinalizeExportThread(); + if (IsExportSucceeded()) + { + COMMON_LOGGER("Checking SaveData\n"); + s_BackupState = CHECK_SAVEDATA; + } + else + { + s_BackupState = FAIL; + } + } + + } + break; + case CHECK_SAVEDATA: { static bool init = true; diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.cpp b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.cpp index 9b0bfed..f57b751 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.cpp +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.cpp @@ -1,4 +1,4 @@ -/*---------------------------------------------------------------------------* +/*---------------------------------------------------------------------------* Project: Horizon File: Exporter.cpp @@ -48,6 +48,7 @@ #include "VersionDetect.h" #include "Util.h" #include "SaveDataMover.h" +#include "HeapChecker.h" namespace ConsoleBackup { @@ -165,6 +166,9 @@ nn::Result WriteTwlTitleList(std::vector& programIdList) } common::HeapManager manager(heapSize); + if (manager.GetAddr() != NULL) + { + heapSize = GetCheckedHeapSize(); char* titleListBuf = reinterpret_cast (manager.GetAddr()); size_t writeSize = 0; @@ -172,7 +176,8 @@ nn::Result WriteTwlTitleList(std::vector& programIdList) { for (std::vector::iterator it = programIdList.begin(); it != programIdList.end(); it++) { - nn::nstd::TSNPrintf(titleListBuf + writeSize, heapSize - writeSize, "%s\n", common::GetCharStr(it->c_str())); + nn::nstd::TSNPrintf(titleListBuf + writeSize, heapSize - writeSize, "%s\n", + common::GetCharStr(it->c_str())); NN_LOG("%ls\n", it->c_str()); writeSize += it->size() + sizeof('\n'); } @@ -186,6 +191,12 @@ nn::Result WriteTwlTitleList(std::vector& programIdList) nn::Result::DESCRIPTION_OUT_OF_MEMORY); } } + else + { + return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_APPLICATION, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } +} nn::Result WriteRegionData() @@ -502,6 +513,7 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path) void* buf = writeHeap.GetAddr(); if (buf != NULL) { + bufSize = GetCheckedHeapSize(); nn::fs::FileOutputStream list; result = list.TryInitialize(common::FILE_LIST_PATHNAME, true); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); @@ -623,6 +635,7 @@ void WriteTwlSaveData() void* buf = writeHeap.GetAddr(); if (buf != NULL) { + bufSize = GetCheckedHeapSize(); nn::fs::FileOutputStream list; result = list.TryInitialize(common::FILE_LIST_PATHNAME, true); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); @@ -786,6 +799,7 @@ void ExportThreadFunc() void* buf = writeHeap.GetAddr(); if (buf != NULL) { + bufSize = GetCheckedHeapSize(); common::SaveDataMover saveDataMover; saveDataMover.StartExport(buf, bufSize, &s_ExportProgress); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED( @@ -872,6 +886,52 @@ void AddShutDownPtmEvent() nn::fnd::DateTime::GetNow()); } +void HeapCheckerFunc() +{ + s_IsExportSucceeded = true; + size_t heapSize = common::GetAllocatableSize(); + if(heapSize > common::FILE_COPY_HEAP_SIZE) + { + heapSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(heapSize); + + nn::Result result; + result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); + + result = common::SdMountManager::Mount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); + + result = CheckHeap( + (::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + + ::std::wstring(L"/")).c_str(), heap.GetAddr(), heapSize); + if(result.IsFailure()) + { + s_IsExportSucceeded = false; + } + + result = common::SdMountManager::Unmount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); + + result = nn::fs::Unmount(common::NAND_ARCHIVE_NAME); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded); +} + +void CheckFcram() +{ + ::std::string sysSaveRoot; + // IVSからセーブデータディレクトリ名を計算 + common::Util::GetSaveDataDirectoryRoot(sysSaveRoot); + + ::std::mbstowcs(s_RootName, sysSaveRoot.c_str(), sysSaveRoot.size() + 1); + + NN_LOG("%ls\n", (::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str()); + + s_ExportThread.Start(HeapCheckerFunc, s_ExportThreadStack); +} + bool ExportData(common::HardwareStateManager& manager) { static bool init = true; diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.h b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.h index df7a8ee..33efb14 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.h +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/Exporter.h @@ -54,6 +54,9 @@ void FinalizeExportThread(); // 出力が成功したかどうか bool IsExportSucceeded(); +// 新たにスレッドを起動して、メモリチェックを行う +void CheckFcram(); + } #endif /* EXPORTER_H_ */ diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.cpp b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.cpp new file mode 100644 index 0000000..0e33b3c --- /dev/null +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.cpp @@ -0,0 +1,180 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: HeapChecker.cpp + + Copyright 2009-2011 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Rev$ + *---------------------------------------------------------------------------*/ + +#include + +#include "Aes_define.h" +#include "HeapChecker.h" +#include "SdReaderWriter.h" +#include "CommonLogger.h" + +namespace ConsoleBackup +{ + +namespace +{ +HeapChecker s_HeapChecker; +} + +nn::Result CheckHeap(std::wstring saveRoot, void* buf, size_t& bufSize) +{ + return s_HeapChecker.Check(saveRoot, buf, bufSize); +} + +size_t GetCheckedHeapSize() +{ + return s_HeapChecker.GetCheckedSize(); +} + + +HeapChecker::HeapChecker() : + m_CheckedSize(0), m_IsAlreadyChecked(false) +{ + +} + +HeapChecker::~HeapChecker() +{ + // TODO Auto-generated destructor stub +} + +nn::Result HeapChecker::Check(std::wstring saveRoot, void* buf, size_t& bufSize) +{ + // 2回目のチェックは行わない + if(m_IsAlreadyChecked) + { + NN_PANIC("HeapChecker Already checked"); + } + + nn::Result result; + common::SdReaderWriter sdReaderWriter; + + // cecdセーブデータが存在しない場合は値を変更せずreturnする + { + nn::fs::FileInputStream nandFile; + result = nandFile.TryInitialize(std::wstring(saveRoot + std::wstring(L"sysdata/00010026/00000000")).c_str()); + if (result <= nn::fs::ResultNotFound()) + { + COMMON_LOGGER("No Reference Data. Use Default Memory Size.\n"); + m_CheckedSize = bufSize; + m_IsAlreadyChecked = true; + return nn::ResultSuccess(); + } + } + + for(; HEAP_SIZE_MIN < bufSize; bufSize /= 2) + { + result = nn::fs::TryDeleteFile(HEAP_CHECKER_FILE); + if(!(result <= nn::fs::ResultNotFound())) + { + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + + // NANDから読み込む + nn::fs::FileInputStream nandFile; + result = nandFile.TryInitialize(std::wstring(saveRoot + std::wstring(L"sysdata/00010026/00000000")).c_str()); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + nn::fs::FileStream sdFile; + result = sdFile.TryInitialize(HEAP_CHECKER_FILE, + nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + s32 readSize = 0; + nn::crypto::Sha256Context writeContext; + writeContext.Initialize(); + nn::crypto::SwAesCtrContext aes; + aes.Initialize(common::checkiv, common::checkkey, sizeof(common::checkkey)); + for(;;) + { + result = nandFile.TryRead(&readSize, buf, bufSize); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + if(readSize == 0) + { + break; + } + + aes.Encrypt(buf, buf, readSize); + writeContext.Update(buf, readSize); + + s32 writeSize; + result = sdFile.TryWrite(&writeSize, buf, readSize, false); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = sdFile.TryFlush(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + + bit8 sha256WriteContext[nn::crypto::Sha256Context::HASH_SIZE]; + writeContext.GetHash(sha256WriteContext); + + nn::crypto::Sha256Context readContext; + readContext.Initialize(); + sdFile.SetPosition(0); + for(;;) + { + result = sdFile.TryRead(&readSize, buf, bufSize); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + if(readSize == 0) + { + break; + } + + readContext.Update(buf, readSize); + } + + bit8 sha256ReadContext[nn::crypto::Sha256Context::HASH_SIZE]; + readContext.GetHash(sha256ReadContext); + + if(std::memcmp(sha256WriteContext, sha256ReadContext, sizeof(sha256ReadContext)) != 0) + { + COMMON_LOGGER("MemoryCheck Failure!! Size: %d\n", bufSize); + } + else + { + // チェックOK + break; + } + } + + nn::fs::TryDeleteFile(HEAP_CHECKER_FILE); + + if(bufSize == HEAP_SIZE_MIN) + { + return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_APPLICATION, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + else + { + m_CheckedSize = bufSize; + m_IsAlreadyChecked = true; + return nn::ResultSuccess(); + } +} + +size_t HeapChecker::GetCheckedSize() +{ + if(m_IsAlreadyChecked) + { + return m_CheckedSize; + } + else + { + return 0; + } +} + +} /* namespace ConsoleBackup */ diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.h b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.h new file mode 100644 index 0000000..86a2bb1 --- /dev/null +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/HeapChecker.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: HeapChecker.h + + Copyright 2009-2011 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Rev$ + *---------------------------------------------------------------------------*/ + +#ifndef HEAPCHECKER_H_ +#define HEAPCHECKER_H_ + +#include + +#include + +namespace ConsoleBackup +{ + +nn::Result CheckHeap(std::wstring saveRoot, void* buf, size_t& bufSize); +size_t GetCheckedHeapSize(); + +//! @brief チェックするヒープサイズの下限です。 +const size_t HEAP_SIZE_MIN = 512 * 1024; + +//! @brief チェックに使うファイルへのパスです。 +const wchar_t* const HEAP_CHECKER_FILE = L"sdmc:/CTR_Console_Repair/Check"; + +class HeapChecker +{ +public: + HeapChecker(); + virtual ~HeapChecker(); + + /*! + @brief 与えられたバッファを使ってNANDから読み出したデータをSDカードに書き出し、データが正しく書き込めているか + チェックします。データが正しく書き込めていない場合、バッファサイズを半分にして繰り返しチェックします。 + 正しくデータを書き込めた時のbufSizeが設定されます。 + + @param[in] saveRoot NANDセーブデータのルートディレクトリのパス + @param[in] buf バッファ + @param[inout] buSize バッファサイズ + + @return ResultOutofMemory データが正しく書き込めるバッファが存在しない場合に返されます。 + @return ResultSuccess 上記以外 + */ + + nn::Result Check(std::wstring saveRoot, void* buf, size_t& bufSize); + + /*! + @brief チェック済みのサイズを返す + + @return Check関数 によってチェックされたサイズ。Check関数が呼び出されていない場合は0 + */ + size_t GetCheckedSize(); + +private: + size_t m_CheckedSize; + NN_PADDING3; + bool m_IsAlreadyChecked; + +}; + +} /* namespace ConsoleBackup */ +#endif /* HEAPCHECKER_H_ */ diff --git a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/OMakefile b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/OMakefile index 8f01daf..dfcdbfa 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/OMakefile +++ b/branches/work/VerificationFailed_2ndNUP/sources/ConsoleBackup/OMakefile @@ -28,6 +28,7 @@ SOURCES[] = Exporter.cpp Checker.cpp SavedataChecker.cpp + HeapChecker.cpp ../common/Util.cpp ../common/DrawSystemState.cpp ../common/FileTransfer.cpp diff --git a/branches/work/VerificationFailed_2ndNUP/sources/common/Aes_define.h b/branches/work/VerificationFailed_2ndNUP/sources/common/Aes_define.h index f6efb69..b7eeb2a 100644 --- a/branches/work/VerificationFailed_2ndNUP/sources/common/Aes_define.h +++ b/branches/work/VerificationFailed_2ndNUP/sources/common/Aes_define.h @@ -50,6 +50,18 @@ namespace common 0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9 }; + const bit8 checkkey[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) = + { + 0x5c, 0x5d, 0x56, 0x79, 0x20, 0x75, 0xfc, 0x56, + 0x82, 0x6e, 0xd7, 0x55, 0xf5, 0xec, 0x0c, 0xc4 + }; + + const bit8 checkiv[AES_BLOCK_SIZE] NN_ATTRIBUTE_ALIGN(4) = + { + 0xb8, 0x84, 0x87, 0xce, 0xd5, 0xfd, 0x0a, 0xd4, + 0x5b, 0x3f, 0x3b, 0xc8, 0xc9, 0x85, 0xdf, 0x8a + }; + #else const bit8 key[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) = { @@ -68,6 +80,19 @@ namespace common 0xe4, 0xcf, 0x58, 0xe5, 0xc9, 0xd6, 0xac, 0x7d, 0xf1, 0xb9, 0x82, 0xf9, 0xa2, 0xd8, 0xda, 0x7b }; + + const bit8 checkkey[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) = + { + 0xaf, 0xce, 0x0a, 0x87, 0xae, 0x24, 0x64, 0xad, + 0x1d, 0xfd, 0x11, 0x7a, 0xd5, 0xf3, 0xe8, 0x5b + }; + + const bit8 checkiv[AES_BLOCK_SIZE] NN_ATTRIBUTE_ALIGN(4) = + { + 0x17, 0x32, 0x7c, 0xf3, 0x00, 0xae, 0x58, 0x67, + 0x78, 0x5e, 0x56, 0xcd, 0x85, 0x70, 0xd7, 0x59 + }; + #endif