VCK および VCW タイトルのバックアップデータ検証を追加

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@3039 b08762b0-b915-fc4b-9d8c-17b2551a87ff
This commit is contained in:
n1481 2012-02-15 12:19:44 +00:00
parent d434b48745
commit 06fa1b3700
9 changed files with 1201 additions and 1 deletions

View File

@ -32,6 +32,9 @@ SRCS = sysmenu_lib.c \
device.c \ device.c \
keys.c \ keys.c \
title.c \ title.c \
SaveDataChecker/lgy_SaveDataChecker.c \
SaveDataChecker/lgy_VCK.c \
SaveDataChecker/lgy_VCW.c \
fs_wram.c \ fs_wram.c \
../common/src/status.c \ ../common/src/status.c \
../common/src/pxi.c \ ../common/src/pxi.c \

View File

@ -0,0 +1,198 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_SaveDataChecker.cpp
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 <twl.h>
#include "lgy_SaveDataChecker.h"
#include "lgy_VCK.h"
#include "lgy_VCW.h"
// title.c より定義を拝借
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
#ifdef USE_HYENA_COMPONENT
#define WRAM_SLOT_FOR_FS 5
#else
#define WRAM_SLOT_FOR_FS 0
#endif
enum GameCodeList
{
TARGET_ROM_VCK = 0,
TARGET_ROM_VCW,
TARGET_ROM_MAX
}GameCodeList;
char *game_code_list[TARGET_ROM_MAX] = { "VCK", "VCW" };
BOOL CheckBackupData( TitleProperty *rhs)
{
u8 list_num;
char test[5];
{
char* n = (char*)&rhs->titleID;
test[0] = n[3];
test[1] = n[2];
test[2] = n[1];
test[3] = n[0];
test[4] = '\0';
}
for( list_num = 0; list_num < TARGET_ROM_MAX; list_num++)
{
if( 0 == STD_CompareNString( test, game_code_list[list_num], 3))
{
switch( list_num)
{
case TARGET_ROM_VCK:
return checkVCK( rhs);
case TARGET_ROM_VCW:
if( test[3] == 'V')
{
return checkVCW( rhs, 0x00800354);
}
else if( test[3] == 'F')
{
return checkVCW( rhs, 0x00800355);
}
else if( test[3] == 'E')
{
return checkVCW( rhs, 0x00400810);
}
default:
return TRUE;
}
}
}
return TRUE;
}
void InitializeBackup( void)
{
u16 lock_id;
if( HOTSW_isEnableHotSW())
{
HOTSW_InvalidHotSW();
OS_TPrintf( "HOTSW is enable, so HOTSW_InvalidHotSW is done.\n");
}
OS_TPrintf( "ok, HOTSW is not enable.\n");
if( !HOTSW_isFinalized())
{
OS_TPrintf( "HOTSW is not Finalized!\n");
}
else
{
OS_TPrintf( "ok, HOTSW is Finalized.\n");
}
if( !HOTSW_isCardLoadCompleted())
{
OS_TPrintf( "HOTSW is not card load completed!\n");
}
else
{
OS_TPrintf( "ok, HOTSW is is card load completed.\n");
}
if( !CARD_IsAvailable())
{
CARD_Init();
OS_TPrintf( "CARD is not available, CARD_Init() is done.\n");
}
if( !CARD_IsEnabled())
{
CARD_Enable( TRUE);
OS_TPrintf( "CARD is not enable, CARD_Enable() is done.\n");
}
lock_id = (u16)OS_GetLockID();
CARD_LockBackup( lock_id);
if( !CARD_IdentifyBackup( CARD_BACKUP_TYPE_EEPROM_64KBITS))
{
OS_TPrintf( "CARD_IdentifyBackup failed.\n");
}
CARD_UnlockBackup( lock_id);
OS_TPrintf( "InitializeBackup done.\n");
}
void FinalizeBackup( void)
{
// while( 1) {};
}
BOOL readEEPROM( u32 src, void *dst, u32 len)
{
BOOL result;
u16 lock_id;
lock_id = (u16)OS_GetLockID();
CARD_LockBackup( lock_id);
/* CARD_ReadEeprom() は、 一時バッファ(CARDi_backup_cache_page_buf)に読み出したデータを
A9-CPUでdstへコピーしてくれるのでdstのメモリ空間はA7から見えなくても良い */
result = CARD_ReadEeprom( src, dst, len);
if( !result)
{
OS_TPrintf( "CARD_ReadEeprom failed! err:%d\n", (int)CARD_GetResultCode());
}
CARD_UnlockBackup( lock_id);
DC_FlushRange( dst, len);
return result;
}
BOOL writeEEPROM( u32 dst, const void *src, u32 len)
{
BOOL result;
u16 lock_id;
DC_FlushRange( src, len);
lock_id = (u16)OS_GetLockID();
CARD_LockBackup( lock_id);
/* CARD_WriteEeprom() は、 src上のデータをA9-CPUで一時バッファ(CARDi_backup_cache_page_buf)に
srcのメモリ空間はA7から見えなくても良い */
result = CARD_WriteEeprom( dst, src, len);
if( !result)
{
OS_TPrintf( "CARD_WriteEeprom failed! err:%d\n", (int)CARD_GetResultCode());
}
CARD_UnlockBackup( lock_id);
return result;
}
BOOL writeAndVerifyEEPROM( u32 dst, const void *src, u32 len)
{
BOOL result;
u16 lock_id;
DC_FlushRange( src, len);
lock_id = (u16)OS_GetLockID();
CARD_LockBackup( lock_id);
/* CARD_WriteAndVerifyEeprom() は、 src上のデータをA9-CPUで一時バッファ(CARDi_backup_cache_page_buf)に
srcのメモリ空間はA7から見えなくても良い */
result = CARD_WriteAndVerifyEeprom( dst, src, len);
if( !result)
{
OS_TPrintf( "CARD_WriteAndVerifyEeprom failed! err:%d\n", (int)CARD_GetResultCode());
}
CARD_UnlockBackup( lock_id);
return result;
}

View File

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_SaveDataChecker.cpp
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 __LGY_SAVEDATACHECKER_CPP__
#define __LGY_SAVEDATACHECKER_CPP__
#include <twl.h>
#include <sysmenu.h>
BOOL CheckBackupData( TitleProperty *rhs);
void InitializeBackup( void);
void FinalizeBackup( void);
BOOL readEEPROM( u32 src, void *dst, u32 len);
BOOL writeEEPROM( u32 dst, const void *src, u32 len);
BOOL writeAndVerifyEEPROM( u32 dst, const void *src, u32 len);
/*
// cardnor_NspiIfApi.cpp
namespace nn {
namespace drivers {
namespace cardnor {
namespace CTR {
namespace ARM946ES{
void InitializeTwlBackup( void);
nn::Result ReadTwlEEPROM(u32 address, u32* buffer, size_t size);
nn::Result WriteTwlEEPROM(u32 address, const u32* buffer, size_t size);
void FinalizeTwlBackup( void);
} // end of namespace ARM946ES
} // end of namespace CTR
} // end of namespace cardnor
} // end of namespace drivers
} // end of namespace nn
*/
//nn::Result ReadTwlEEPROM(u32 address, u32* buffer, size_t size);
//nn::Result WriteTwlEEPROM(u32 address, const u32* buffer, size_t size);
#endif

View File

@ -0,0 +1,256 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_VCK.cpp
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 <twl.h>
#include <sysmenu.h>
#include "lgy_VCK.h"
#include "lgy_SaveDataChecker.h"
// title.c より定義を拝借
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
#ifdef USE_HYENA_COMPONENT
#define WRAM_SLOT_FOR_FS 5
#else
#define WRAM_SLOT_FOR_FS 0
#endif
#define VCK_BACKUP_READ_SIZE (896)
//NN_COMPILER_ASSERT(VCK_BACKUP_READ_SIZE >= sizeof(VCK_SlotHeader) + sizeof(VCK_ProfileSlotBody));
//NN_COMPILER_ASSERT(VCK_BACKUP_READ_SIZE % 32 == 0);
// checksum を算出する
static u16 getChecksum( void* data);
// データが工場出荷状態か破壊されていれば TRUE を返す
static BOOL isFactoryOrBrokenForVCK( TitleProperty* tp, void* data, u16* ret_checksum);
// データが正常範囲内に収まっていれば TRUE を返す
static BOOL checkEepromRangeForVCK( void* data);
//using namespace nn::drivers::cardnor::CTR::ARM946ES;
typedef struct TitleID_num
{
u32 Lo;
u32 Hi;
}
TitleID_num;
// チェックAPIVCK*タイトル起動前にこれを呼べばOK
BOOL checkVCK( TitleProperty* tp)
{
u32 i;
u16 tick;
u32 *data;
VCK_SlotHeader *header;
VCK_ProfileSlotBody *body;
u8 *body_u8;
u16 S_checksum = 0;
u16 B_checksum;
u32 calculatedSha1[ MATH_SHA1_DIGEST_SIZE / sizeof(u32)];
MATHRandContext16 rc16;
u32 rseed;
OS_TPrintf("check VCK backup start.\n");
OS_TPrintf( "header size:0x%x, body size:0x%x\n", sizeof(VCK_SlotHeader), sizeof(VCK_ProfileSlotBody));
// EEPROM から読み出し
data = (u32*)(MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9));
OS_TPrintf("Buffer:0x%x\n", data);
InitializeBackup();
readEEPROM( 0, (u32*)data, VCK_BACKUP_READ_SIZE);//sizeof(VCK_SlotHeader) + sizeof(VCK_ProfileSlotBody)が32Bytesの倍数でないため
header = (VCK_SlotHeader*)data;
body = (VCK_ProfileSlotBody*)((u8*)data + sizeof(VCK_SlotHeader));
body_u8 = (u8*)body;
// 工場出荷状態またはデータ破壊状態かどうか確認
if( !isFactoryOrBrokenForVCK( tp, data, &S_checksum))
{
if( checkEepromRangeForVCK( data)) // データ範囲を確認
{
OS_TPrintf("VCK backup is correct.\n");
FinalizeBackup();
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
return TRUE;
}
}
else
{
if( !S_checksum)
{
S_checksum = getChecksum( body);
}
}
// checksumがBになるようにランダムな1箇所へ書き込み
tick = OS_GetTickLo();
#if 1
{
MATH_CalcSHA1( calculatedSha1, (const void*)data, sizeof(VCK_ProfileSlotBody));
}
#endif
rseed = (u32)(OS_GetTick()) + *(u32*)(calculatedSha1);
MATH_InitRand16( &rc16, rseed);
for( i=0; i<sizeof(VCK_ProfileSlotBody); i++)
{
body_u8[i] = (u8)(MATH_Rand16( &rc16, 0xFF));
}
B_checksum = getChecksum( body);
// 書き込んだ後の checksum が、S_checksum でも マジコンヘッダのchecksum にもならないようにする
while( (B_checksum == S_checksum) ||
( B_checksum == (0xFFFF - (header->m_uniqueIdentifier) - (header->m_slotCheckSum))))
{
B_checksum -= body_u8[sizeof(VCK_ProfileSlotBody) - 1];
body_u8[sizeof(VCK_ProfileSlotBody) - 1]++;
B_checksum += body_u8[sizeof(VCK_ProfileSlotBody) - 1];
}
// Backup デバイスへ反映
if( writeAndVerifyEEPROM( 0, data, VCK_BACKUP_READ_SIZE))
{
OS_TPrintf("launch ok.\n");
OS_TPrintf("ckecksum:0x%x, B_checksum:0x%x\n", getChecksum(body), B_checksum);
FinalizeBackup();
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
return TRUE;
}
OS_TPrintf("launch NG.\n");
OS_TPrintf("S_checksum:0x%x, ckecksum:0x%x, B_checksum:0x%x\n", S_checksum, getChecksum(body), B_checksum);
FinalizeBackup();
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
return FALSE;
}
// checksum を算出する
static u16 getChecksum( void* data)
{
u8 *data_u8;
u16 checksum = 0;
u16 i;
data_u8 = (u8*)data;
for( i=0; i<sizeof(VCK_ProfileSlotBody); ++i)
{
checksum += data_u8[i];
}
return checksum;
}
// データが工場出荷状態か破壊されていれば TRUE を返す
static BOOL isFactoryOrBrokenForVCK( TitleProperty* tp, void* data, u16* ret_checksum)
{
VCK_SlotHeader *header;
u8* body;
u16 checksum, i;
u8* pTitle_id;
u8* pIdentifier;
header = (VCK_SlotHeader*)data;
body = (u8*)data + sizeof(VCK_SlotHeader);
pTitle_id = (u8*)&(tp->titleID); // TWL:0x56434B45, CTR:0x454B4356
pIdentifier = (u8*)&(header->m_uniqueIdentifier); // 0x56434B45
/* 工場出荷状態のチェック */
#if 1
for( i=0; i<4; i++)
{
if( pTitle_id[i] != pIdentifier[i])
{
OS_TPrintf("%s, factory.\n", __FUNCTION__);
return TRUE;
}
}
OS_TPrintf("%s, not factory.\n", __FUNCTION__);
#endif
/* 破壊のチェック */
checksum = 0;
for( i=0; i<sizeof(VCK_ProfileSlotBody); i++)
{
checksum += body[i];
}
OS_TPrintf("%s : S_checksum:0x%x\n", __FUNCTION__, checksum);
*ret_checksum = checksum; // checksumを返す
checksum += (u16)(header->m_uniqueIdentifier);
checksum += header->m_slotCheckSum;
if( checksum != 0xFFFF)
{
OS_TPrintf("%s, broken.\n", __FUNCTION__);
return TRUE; // broken
}
OS_TPrintf("%s, not broken.\n", __FUNCTION__);
return FALSE;
}
// データが正常範囲内に収まっていれば TRUE を返す
static BOOL checkEepromRangeForVCK( void* data)
{
VCK_ProfileSlotBody *buf;
buf = (VCK_ProfileSlotBody*)((u8*)data + sizeof(VCK_SlotHeader));
if( buf->m_playerName[10] != '\0')
{
OS_TPrintf("%s, playerName is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( (buf->m_averageCookingTime < -1) || (buf->m_averageCookingTime > 2))
{
OS_TPrintf("%s, cookingTime is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( (buf->m_culinaryLevel < -1) || (buf->m_culinaryLevel > 2))
{
OS_TPrintf("%s, culinaryLevel is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( (buf->m_costImportance < -1) || (buf->m_costImportance > 2))
{
OS_TPrintf("%s, costImportance is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( (buf->m_numberCalories < -1) || (buf->m_numberCalories > 2))
{
OS_TPrintf("%s, numberCalories is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( buf->m_ROTD_index > 9)
{
OS_TPrintf("%s, ROTD_index is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( buf->m_uBirthDate_Day >0x1F)
{
OS_TPrintf("%s, birthdate_day is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( buf->m_uBirthDate_Month > 0x0C)
{
OS_TPrintf("%s, birthdate_month is out of range.\n", __FUNCTION__);
return FALSE;
}
else if( buf->m_numServings > 8)
{
OS_TPrintf("%s, numServings is out of range.\n", __FUNCTION__);
return FALSE;
}
OS_TPrintf("%s, good range.\n", __FUNCTION__);
return TRUE;
}

View File

@ -0,0 +1,159 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_VCK.h
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 __LGY_VCK_H__
#define __LGY_VCK_H__
#include <twl.h>
#include <sysmenu.h>
enum E_CookingCoachSavegameSlot
{
CCSS_ProfileSlot, // 0x00000x0377
CCSS_ShoppingListSlot, // 0x03780x0BCF
CCSS_CommentSlot1, // 0x0BD00x0F03
CCSS_CommentSlot2, // 0x0F040x1237
CCSS_PhotoSlot, // 0x12380x1F76
CCSS_SlotCount
};
#define C_PROFILENAME_MAXLENGTH 11 // Include \0 character at the end
#define DATASAVE_MAX_INGREDIENTS 8
#define DATASAVE_MAX_SHOPPINGLIST_CUSTOMITEMS 10
#define DATASAVE_MAX_SHOPPINGLIST_RECIPEITEMS 75
#define MAX_SHOPPING_LIST_RECIPES 6
#define DATASAVE_NUM_CALENDARRECIPES 50
#define DATASAVE_MAX_ROTD 10
#define DATASAVE_NUM_RECIPECOMMENTS_PER_SLOT 7
#define DATASAVE_RECIPECOMMENT_LENGTH 114
//the favorites are stored in an array of u32 used as a bitfield. each bit represents
//ONE recipe. Thus, the maximum number of recipes that can be remembered in this array
//is expressed by DATASAVE_FAVORITE_RECIPES_MAXNUMRECIPES
#define DATASAVE_FAVORITE_RECIPES_NB_U32 10
#define DATASAVE_FAVORITE_RECIPES_MAXNUMRECIPES (8*4*DATASAVE_FAVORITE_RECIPES_NB_U32)
#define QUANTITY_BUFFER_SIZE 20
typedef struct VCK_SlotHeader
{
u32 m_uniqueIdentifier;
u16 m_slotCheckSum;
u8 m_status;
u8 struct_padding;
}
VCK_SlotHeader;
typedef struct CalendarRecipe
{
u32 m_uDay;
u16 m_uRecipeID;
u8 m_recipeState;
}
CalendarRecipe;
typedef struct RecipeOfTheDay
{
u32 m_recipeID;
s32 m_dayProposed;
}
RecipeOfTheDay;
//EntryData is the base class for the two "slots" that will be saved individually.=
//the structs are defined in the base class just in case some of them must be used in
//both derived classes.
typedef struct VCK_ProfileSlotBody
{
//TODO : optimize the size of the EntryData structure
char m_playerName[C_PROFILENAME_MAXLENGTH]; // 11(0x080x12)
// 1(0x13)
s32 m_averageCookingTime; // 4(0x140x17) [取り得る値は -1,0,1,2のどれか]
s32 m_culinaryLevel; // 4(0x180x1B) [取り得る値は -1,0,1,2のどれか]
s32 m_costImportance; // 4(0x1C0x1F) [取り得る値は -1,0,1,2のどれか]
s32 m_numberCalories; // 4(0x200x23) [取り得る値は -1,0,1,2のどれか]
u32 m_ingredientsExcluded[DATASAVE_MAX_INGREDIENTS]; // 32(0x240x43)
u32 m_ingredientsPrefered[DATASAVE_MAX_INGREDIENTS]; // 32(0x440x63)
CalendarRecipe m_calendarRecipes[DATASAVE_NUM_CALENDARRECIPES]; //400(0x640x1F3)
u16 m_uNbCalendarRecipes; // 2(0x1F40x1F5)
RecipeOfTheDay m_recipeOfTheDay[DATASAVE_MAX_ROTD]; // 80(0x1F80x247)
u32 m_ROTD_index; // 4(0x2480x24B)
//---Music
s32 m_musicStyle; // (0x24C0x24F) 取り得る値は -1,0,1,2,3のどれか
u32 m_musicLocation; // (0x2500x253) 取り得る値は 0,1,2のどちらか
//---FAVORITES BIT FIELDS
u32 m_favoriteRecipes[DATASAVE_FAVORITE_RECIPES_NB_U32]; // 40(0x254)
u32 m_firstSessionDateInDay; // 4(0x27C)
s32 m_lastSessionDateInDay; // 4(0x280)
u8 m_uBirthDate_Day; // 1(0x284) [取り得る値は 10x1F]
u8 m_uBirthDate_Month; // 1(0x285) [取り得る値は 10x0C]
// recipe quantity info (300 quantity info saved on 2 bits each)
u32 m_recipeQuantity[QUANTITY_BUFFER_SIZE]; // 80
// save kitchen profile
u8 m_unitsUsed; // 1
u8 m_numServings; // 1(0x2D9) 取り得る値は 2,4,6,8のどれか
BOOL m_hasOven :1; // 0x2DA
BOOL m_hasMixer :1;
BOOL m_hasBBQ :1;
BOOL m_hasFoodProcessor :1;
// tutorial completed?
BOOL m_tutorialSearchCompleted :1;
BOOL m_tutorialCriteriaSearchCompleted :1;
BOOL m_tutorialPrecookCompleted :1;
BOOL m_tutorialTimelineCompleted :1;
BOOL m_tutorialCookbookCompleted :1; // 0x2DB
BOOL m_tutorialShoppingCompleted :1;
BOOL m_tutorialManagementCompleted :1;
BOOL m_tutorialExtraInfoCompleted :1;
BOOL m_tutorialCalendarCompleted :1;
BOOL m_searchFirstDeleteCompleted :1;
// introduction completed?
BOOL m_introductionCompleted :1;
BOOL m_tutorialFoodProfileCompleted :1;
BOOL m_tutorialFoodProfileFirstDeleteCompleted :1; // 0x2DC
BOOL m_tutorialCookbookTimerCompleted :1;
//---OPTIONS
//---Voice
BOOL m_vocalCommandsActivated :1;
BOOL m_narrationActivated :1;
BOOL m_birthdayRecipeIsLocked :1;
//---Welcome
BOOL m_forceShowBirthday :1;
BOOL m_plannedARecipe :1;
BOOL m_usedFavorites :1;
u8 m_welcomeMsgAlreadyDisplayed; //BIT FIELDS with msg that must be display only once // 0x2DD
//check enum E_WelcomeMsg for bit order.
u8 m_language; // 0x2DE
u8 padding[0x95];
//CookingCoach::ShoppingListCustomItem m_shoppingListCustomItems[DATASAVE_MAX_SHOPPINGLIST_CUSTOMITEMS];
}
VCK_ProfileSlotBody;
// チェックAPIVCK*タイトル起動前にこれを呼べばOK
BOOL checkVCK( TitleProperty* tp);
#endif

View File

@ -0,0 +1,255 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_VCW.cpp
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 <twl.h>
#include <sysmenu.h>
#include "lgy_VCW.h"
#include "lgy_SaveDataChecker.h"
// title.c より定義を拝借
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
#ifdef USE_HYENA_COMPONENT
#define WRAM_SLOT_FOR_FS 5
#else
#define WRAM_SLOT_FOR_FS 0
#endif
#define VCW_BACKUP_READ_SIZE (7808)
//NN_COMPILER_ASSERT(VCW_BACKUP_READ_SIZE >= ((sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck)) * 2));
//NN_COMPILER_ASSERT(VCW_BACKUP_READ_SIZE % 32 == 0);
/* VCW メソッド */
static u16 VCW_HeaderChecksumToChecksum( VCW* vcw);
static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid);
static BOOL VCW_IsFactoryOrBroken( VCW* vcw);
static BOOL VCW_CheckRange( VCW* vcw);
static u16 VCW_Modify( VCW* vcw);
static BOOL VCW_IsModified( VCW* vcw);
static void VCW_UpdateChecksum( VCW* vcw);
static u16 VCW_GetChecksum( VCW* vcw);
static void VCW_Finalize( VCW* vcw);
//using namespace nn::drivers::cardnor::CTR::ARM946ES;
// チェックAPIVCW*タイトル起動前にこれを呼べばOK
BOOL checkVCW( TitleProperty* tp, u32 ggid)
{
#pragma unused( tp)
u32 i;
u32 *data;
u8 *buf;
u16 B_checksum[2];
VCW vcw[2];
OS_TPrintf("check VCW backup start.\n");
OS_TPrintf( "header size:0x%x, body size:0x%x\n", sizeof(VCW_SavegameHeader), sizeof(VCW_BodyForCheck));
// EEPROM から読み出し
// base = MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
data = (u32*)(MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9));
OS_TPrintf("Buffer:0x%x\n", data);
InitializeBackup();
readEEPROM( 0, (u32*)data, VCW_BACKUP_READ_SIZE);
buf = (u8*)data;
VCW_Initialize( &vcw[0], buf, ggid);
buf = (u8*)data + (sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck));
VCW_Initialize( &vcw[1], buf, ggid);
for( i=0; i<2; i++)
{
// 工場出荷状態またはデータ破壊状態かどうか確認
if( !VCW_IsFactoryOrBroken( &vcw[i]))
{
if( VCW_CheckRange( &vcw[i]))
{
OS_TPrintf("VCW backup is correct.\n");
continue;
}
}
// ランダムな位置に書き込み
B_checksum[i] = VCW_Modify( &vcw[i]);
}
// バッファに書き込みしたならデバイスへの書き込みテストが必要
if( VCW_IsModified( &vcw[0]) || VCW_IsModified( &vcw[1]))
{
OS_TPrintf( "backup write testing..\n");
if( !writeAndVerifyEEPROM( 0, data, VCW_BACKUP_READ_SIZE))
{
OS_TPrintf("launch NG!\n");
VCW_Finalize( &vcw[0]);
VCW_Finalize( &vcw[1]);
FinalizeBackup();
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
return FALSE;
}
}
OS_TPrintf("launch ok.\n");
VCW_Finalize( &vcw[0]);
VCW_Finalize( &vcw[1]);
FinalizeBackup();
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
return TRUE;
}
/* VCWメソッド*/
static u16 VCW_HeaderChecksumToChecksum( VCW* vcw)
{
return (u16)(0xFFFF - (vcw->header->uniqueIdentifier) - (vcw->header->checkSum));
}
static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid)
{
vcw->buf = (u8*)buffer;
if( (u32)(vcw->buf) % 4)
{
OS_TPrintf( "Buffer alignment error!\n");
while( 1) {};
}
vcw->ggid = ggid;
vcw->header = (VCW_SavegameHeader*)(vcw->buf);
vcw->body = (VCW_BodyForCheck*)(vcw->buf + sizeof(VCW_SavegameHeader));
vcw->B_checksum = VCW_HeaderChecksumToChecksum( vcw);
}
/* 工場出荷状態かデータ破壊状態なら TRUE を返す */
static BOOL VCW_IsFactoryOrBroken( VCW* vcw)
{
u16 checksum;
/**/
VCW_UpdateChecksum( vcw);
/* 工場出荷状態のチェック */
if( vcw->ggid != vcw->header->uniqueIdentifier) // VCWV:0x00800354, VCWF:0x00800355, VCWE:0x00400810
{
OS_TPrintf("%s, factory.\n", __FUNCTION__);
return TRUE;
}
OS_TPrintf("%s, not factory.\n", __FUNCTION__);
/* 破壊のチェック */
checksum = VCW_GetChecksum( vcw);
checksum += (u16)(vcw->ggid);
checksum += vcw->header->checkSum;
if( checksum != 0xFFFF)
{
OS_TPrintf("%s, broken.\n", __FUNCTION__);
return TRUE; // broken
}
OS_TPrintf("%s, not broken.\n", __FUNCTION__);
return FALSE;
}
// データが正常範囲内に収まっていれば TRUE を返す
static BOOL VCW_CheckRange( VCW* vcw)
{
if( vcw->body->m_name[UBI_PLAYERINFO_NAME_LENGTH] != '\0')
{
OS_TPrintf("%s, playerName is out of range.\n", __FUNCTION__);
return FALSE;
}
OS_TPrintf("%s, good range.\n", __FUNCTION__);
return TRUE;
}
/* ランダムに一箇所書き換え、書き換え後のchecksumを返す */
static u16 VCW_Modify( VCW* vcw)
{
u16 S_checksum_tmp;
u32 i;
u16 tick;
u8* body_u8 = (u8*)(vcw->body);
u32 calculatedSha1[ MATH_SHA1_DIGEST_SIZE /sizeof(u32)];
MATHRandContext16 rc16;
u32 rseed;
S_checksum_tmp = VCW_GetChecksum( vcw);
// checksumがBになるようにランダムな1箇所へ書き込み
tick = OS_GetTickLo();
#if 1
{
MATH_CalcSHA1( calculatedSha1, (const void*)vcw->body, sizeof(VCW_BodyForCheck));
}
#endif
rseed = (u32)(OS_GetTick()) + *(u32*)(calculatedSha1);
MATH_InitRand16( &rc16, rseed);
for( i=0; i<sizeof(VCW_BodyForCheck); i++)
{
body_u8[i] = (u8)(MATH_Rand16( &rc16, 0xFF));
}
VCW_UpdateChecksum( vcw);
vcw->B_checksum = VCW_GetChecksum( vcw);
// 書き込んだ後の checksum が、S_checksum でも マジコンヘッダのchecksum にもならないようにする
while( (vcw->B_checksum == S_checksum_tmp) ||
( vcw->B_checksum == VCW_HeaderChecksumToChecksum( vcw)))
{
vcw->B_checksum -= body_u8[sizeof(VCW_BodyForCheck) - 1];
body_u8[sizeof(VCW_BodyForCheck) - 1]++;
vcw->B_checksum += body_u8[sizeof(VCW_BodyForCheck) - 1];
}
OS_TPrintf( "S_checksum:0x%x, A_checksum:0x%x, B_checksum;0x%x\n",
S_checksum_tmp,
VCW_HeaderChecksumToChecksum( vcw),
vcw->B_checksum);
return vcw->B_checksum;
}
/* Modifyされたかどうかを返す */
static BOOL VCW_IsModified( VCW* vcw)
{
return ( vcw->B_checksum != VCW_HeaderChecksumToChecksum( vcw));
}
/* Checksum をアップデートする */
static void VCW_UpdateChecksum( VCW* vcw)
{
u32 i;
u8* body_u8 = (u8*)vcw->body;
vcw->S_checksum = 0;
for( i=0; i<sizeof(VCW_BodyForCheck); ++i)
{
vcw->S_checksum += body_u8[i];
}
}
/* Checksum を取得する */
static u16 VCW_GetChecksum( VCW* vcw)
{
return vcw->S_checksum;
}
/* */
static void VCW_Finalize( VCW* vcw)
{
#pragma unused( vcw)
}

View File

@ -0,0 +1,262 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: lgy_VCW.h
Copyright (C)2009-2011 Nintendo Co., Ltd. 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 __LGY_VCW_H__
#define __LGY_VCW_H__
#include <twl.h>
#include <sysmenu.h>
#define UBI_PLAYERINFO_TUTORIALSEENFLAG_SIZE 3
#define UBI_PLAYERINFO_NAME_LENGTH 12
#define UBI_PLAYERINFO_UNLOCK_LETTERMASK_COUNT 40 //1 for each alphabet letter, including accented letters
#define UBI_PLAYERINFO_UNLOCK_LETTERMASK_SIZE (UBI_PLAYERINFO_UNLOCK_LETTERMASK_COUNT/4)
#define UBI_PLAYERINFO_DATAITEM_MAXCOUNT 2900
#define UBI_PLAYERINFO_DATAITEM_SAVE_MAXSIZE (UBI_PLAYERINFO_DATAITEM_MAXCOUNT/2)
#define UBI_PLAYERINFO_THEMEDATAITEM_MAXCOUNT 160
#define UBI_PLAYERINFO_THEMEDATAITEM_SAVE_MAXSIZE (UBI_PLAYERINFO_THEMEDATAITEM_MAXCOUNT/2)
// defines for MWC2
#define UBI_PLAYERINFO_TOP_SCORE_NUM 4
#define UBI_PLAYERINFO_LAST_GAME_SCORES_NUM 5
#define UBI_PLAYERINFO_SESSION_STARS 100 // 100 is temp for now
#define UBI_PLAYERINFO_CROSSWORD_COUNT 20
#define UBI_PLAYERINFO_CROSSWORD_NO_SCORE 0xF
#define UBI_PLAYERINFO_CROSSWORD_MIN_RANK 10
#define GRID_SIZE 11
enum E_GameIDs
{
UBI_PLAYERINFO_GAMES_MISMATCH_ID = 0,
UBI_PLAYERINFO_GAMES_NETWORDER_ID, // 1
UBI_PLAYERINFO_GAMES_QUOTES_ID, // 2
UBI_PLAYERINFO_GAMES_IDIOMS_ID, // 3
UBI_PLAYERINFO_GAMES_TRACE_ID, // 4
UBI_PLAYERINFO_GAMES_RACE_ID, // 5
UBI_PLAYERINFO_GAMES_WORDFALL_ID, // 6
UBI_PLAYERINFO_GAMES_LADDER_ID, // 7
UBI_PLAYERINFO_GAMES_CROSSWORD_ID, // 8
UBI_PLAYERINFO_GAMES_HIDDENWORD_ID,// 9
UBI_PLAYERINFO_GAMES_BLUFF_ID, // 10
UBI_PLAYERINFO_GAMES_HANGMAN_ID, // 11
UBI_PLAYERINFO_GAMES_MUMBLE_ID, // 12
UBI_PLAYERINFO_GAMES_UNLOCK_ID, // 13
UBI_PLAYERINFO_GAMES_NUM, // 14
UBI_PLAYERINFO_GAMES_NONE_ID
};
typedef struct VCW_SavegameHeader
{
u32 uniqueIdentifier;
u16 checkSum;
u8 m_status;
u8 padTemp;
}VCW_SavegameHeader;
struct ScoreInfo
{
u16 m_score; //represents either stars or points, whatever
u32 m_time; // could be u16
};
struct ActivePassiveData
{
u16 m_activeWords;
u16 m_passiveWords;
};
struct UnlockGameData
{
u16 m_availableGuesses;
u16 m_currentQuoteIndex;
u8 m_letterStateMask[UBI_PLAYERINFO_UNLOCK_LETTERMASK_SIZE];
u8 m_pad[2]; //for 32-bit alignment
};
struct UnlockData
{
u8 m_lockState;
u16 m_availableStars;
};
struct HiddenWordData
{
char gridLetters[11][11];
struct WordData
{
u16 m_posX : 4;
u16 m_posY : 4;
u16 m_length : 4;
u16 m_axis : 4;
}m_words[12];
// u8 wordsStartPos[12][2];
// u8 wordsLenght[12];
// u8 wordsAxis[12];
u8 amountOfWords;
u16 flagWordsFound; // The last bit (15) is used to show the presence of a hidden word save game.
u32 timeElapsed;
u8 hintsUsed;
};
// Used for dynamically generated crosswords
struct CrosswordData
{
u8 m_pregenGridId;
u8 m_helpUsed : 1;
u8 m_saveIsValid : 1;
u8 m_timerIndex : 6;
// Letter displayed in the grid cell, 1st bit is bool for Cheated ( or Not ).
char m_gridLetters[GRID_SIZE][GRID_SIZE]; // Upper Case Ascii value
// Add timer data
u32 m_elapsedTime; // In miliseconds
};
#define MAX_WORD_COUNT 30
struct DynamicCrosswordData
{
struct Word
{
u16 m_startPosX : 4;
u16 m_startPosY : 4;
u16 m_axis : 4;
u16 m_isSmallword : 4;
u16 m_wordId; // Id of the word in dictionary
};
u8 m_wordCount;
// Used for generated grids.
u16 m_words[MAX_WORD_COUNT];
};
struct VocabularyData
{
union StateBucket
{
struct
{
u8 m_state0 : 3; //word state (item 0)
u8 m_seen0 : 1; //seen flag (item 0)
u8 m_state1 : 3; //word state (item 1)
u8 m_seen1 : 1; //seen flag (item 1)
};
u8 m_wholeBucket;
}StateBucket;
u8 m_type;
u8 m_playerDl;
u8 m_selectionCount[4]; //LT_BasicCount
u32 m_newActiveCount;
u32 m_allTimeMaxActiveCount;
u8 m_lastAccuracy;
union StateBucket* m_itemStates;
};
struct MainVocabularyData
{
struct VocabularyData voc;
union StateBucket m_specificItemStates[UBI_PLAYERINFO_DATAITEM_SAVE_MAXSIZE]; //missing 2 for 32-bit alignment
};
struct ThemeVocabularyData
{
struct VocabularyData voc;
union StateBucket m_specificItemStates[UBI_PLAYERINFO_THEMEDATAITEM_SAVE_MAXSIZE]; //missing 2 for 32-bit alignment
};
typedef struct PlayerData
{
char m_name[UBI_PLAYERINFO_NAME_LENGTH+1]; // 13 (0x080x0x14)
u8 m_dataState; // 1 (0x15)
u8 m_musicOff; // 1 (0x16)
u8 m_useWarmups; // 1 (0x17)
u8 m_lefty; // 1 (0x18)
u16 m_numSessions; // 2 (0x190x1A)
u16 m_seenRealLifeChallenges; // 2 (0x1B0x1C)
f32 m_fReadingTimeMod; // 4 (0x1D
f32 m_fReactionTimeModQuick; // 4
f32 m_fReactionTimeModSegment; // 4
u8 m_sessionStars; // 1
u8 m_sessionUnlockTry; // 1
u8 m_personalProgressSeen; // 1
u32 m_gameTracker; // 4
u8 m_hsGamesPlayed; // 1
u8 m_themeViewed; // 1
u8 m_themeUnlocked; // 1
u8 m_gameIntroViewed[UBI_PLAYERINFO_GAMES_NUM]; // 14
u16 m_gameLastSessionPlayed[UBI_PLAYERINFO_GAMES_NUM]; // 28
struct ScoreInfo m_topScores[UBI_PLAYERINFO_GAMES_NUM][UBI_PLAYERINFO_TOP_SCORE_NUM]; //
struct ScoreInfo m_lastScores[UBI_PLAYERINFO_GAMES_NUM][UBI_PLAYERINFO_LAST_GAME_SCORES_NUM];
u8 m_crosswordRanks[UBI_PLAYERINFO_CROSSWORD_COUNT];
struct ActivePassiveData m_activePassiveTotals;
struct UnlockGameData m_unlockGameData;
struct UnlockData m_unlockData;
struct MainVocabularyData m_mainVocabularyData; //
// struct ThemeVocabularyData m_themeVocabularyData[DICT_THEME_MAX_COUNT]; //
struct HiddenWordData m_hiddenWordData; // 153 ()
struct CrosswordData m_crossWordData; // 133 ()
struct DynamicCrosswordData m_dynamicCrossWordData; // 65 (0xF37)
}
PlayerData;
typedef struct VCW_BodyForCheck
{
char m_name[UBI_PLAYERINFO_NAME_LENGTH+1]; // 13 (0x080x0x14)
u8 dummy[0xF38 - 8 - 13];
}
VCW_BodyForCheck;
//NN_COMPILER_ASSERT(0xF38 == sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck));
/**/
BOOL checkVCW( TitleProperty* tp, u32 ggid);
/* TWLランチャにも移植するので Cでオブジェクトを定義する */
typedef struct VCW
{
u8* buf;
u32 ggid;
VCW_SavegameHeader *header;
VCW_BodyForCheck *body;
u16 S_checksum;
u16 B_checksum;
}VCW;
//static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid);
//static bool VCW_IsFactoryOrBroken( VCW* vcw);
//static bool VCW_CheckRange( VCW* vcw);
//static u16 VCW_Modify( VCW* vcw);
//static bool VCW_IsModified( VCW* vcw);
//static void VCW_UpdateChecksum( VCW* vcw);
//static u16 VCW_GetChecksum( VCW* vcw);
//static void VCW_Finalize( VCW* vcw);
/* オブジェクトここまで */
#endif

View File

@ -24,6 +24,7 @@
#include "internal_api.h" #include "internal_api.h"
#include "fs_wram.h" #include "fs_wram.h"
#include <sysmenu/errorLog.h> #include <sysmenu/errorLog.h>
#include "SaveDataChecker/lgy_SaveDataChecker.h"
// define data----------------------------------------------------------------- // define data-----------------------------------------------------------------
@ -1816,7 +1817,19 @@ static BOOL SYSMi_AuthenticateTitleCore( TitleProperty *pBootTitle)
return SYSMi_AuthenticateTWLTitle( pBootTitle ); return SYSMi_AuthenticateTWLTitle( pBootTitle );
case LAUNCHER_BOOTTYPE_ROM: case LAUNCHER_BOOTTYPE_ROM:
OS_TPrintf( "Authenticate :TWL_ROM start.\n" ); OS_TPrintf( "Authenticate :TWL_ROM start.\n" );
return SYSMi_AuthenticateTWLTitle( pBootTitle ); if( SYSMi_AuthenticateTWLTitle( pBootTitle ))
{
if( CheckBackupData( pBootTitle)) // バックアップデータのチェック
{
return TRUE;
}
else
{
UTL_SetFatalError(FATAL_ERROR_BACKUP_DATA_CHECK_FAILED);
return FALSE;
}
}
return FALSE;
case LAUNCHER_BOOTTYPE_TEMP: case LAUNCHER_BOOTTYPE_TEMP:
OS_TPrintf( "Authenticate :TWL_TEMP start.\n" ); OS_TPrintf( "Authenticate :TWL_TEMP start.\n" );
if (!hs->permit_landing_tmp_jump) if (!hs->permit_landing_tmp_jump)

View File

@ -85,6 +85,7 @@ typedef enum FatalErrorCode {
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致 FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗フェーズ FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗フェーズ FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_BACKUP_DATA_CHECK_FAILED = 53, // バックアップデータの検証失敗
FATAL_ERROR_MAX = 53 FATAL_ERROR_MAX = 53
}FatalErrorCode; }FatalErrorCode;