/*---------------------------------------------------------------------------* Project: Horizon File: main.cpp Copyright (C)2009 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "demo.h" #include "../../body/ver.h" #include "../../../common/sleep.h" #include "../../../common/common.h" #include "../../../common/shfnt.h" #include "test_data.h" #define INF_FILE "sdmc:/csm_inf.txt" #define KEY_LENGTH 2048 #define LIST_FILE "sdmc:/csm_list.txt" #define SIGN_FILE "sdmc:/csm_sign.dat" extern "C" { extern u8* PUBLIC_KEY_BEGIN[]; extern u8* PUBLIC_KEY_END[]; const void* PUBLIC_KEY = PUBLIC_KEY_BEGIN; } demo::RenderSystemDrawing s_RenderSystem; nn::fnd::ExpHeap appHeap; uptr heapForGx; void ErrorStop(char *s); void ErrorPOff(char *s); const size_t ROMFS_BUFFER_SIZE = 64*1024;//ROMマウント用 const size_t READ_BUFFER_SIZE = 64*1024; #define SDK_SER_LEN nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN namespace { u8* readBuf; u8* romfsBuf; } nn::Result result; bool ImportFile(nn::fs::MediaType mediaType, wchar_t* filename) { //nn::Result result; nn::fs::FileOutputStream* stream; result = nn::am::BeginImportProgram(&stream, mediaType); if (result.IsSuccess()) { //NN_LOG("Importing: %ls...", filename); nn::fs::FileInputStream in(filename); while(s32 read = in.Read(readBuf, READ_BUFFER_SIZE)) { stream->Write(readBuf, read); } result = nn::am::EndImportProgram(stream); } return result.IsSuccess(); } #define LIST_MAX 4000 #define LIST_LENGTH (LIST_MAX * (nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN+1)) u8 s_list[LIST_MAX][nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN+1];//シリアルリスト u8 sign[256];//署名 u8 serialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN+1]; //本体シリアル取得 int GettedSerLen; bool GetSerial(){ nn::cfg::CTR::init::Initialize(); nn::cfg::CTR::system::Initialize(); result = nn::cfg::CTR::system::GetSerialNo(serialNo); nn::cfg::CTR::system::Finalize(); nn::cfg::CTR::init::Finalize(); serialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN] = 0; GettedSerLen = strlen((char*)serialNo); return result.IsSuccess(); } //#define setColor(r,g,b,a) s_RenderSystem.SetColor(r,g,b,a) void setColor(f32 r,f32 g,f32 b,f32 a){ shf_SetColor(r,g,b,a);} //#define setText(x,y,s) s_RenderSystem.DrawText(x,y,s) void drawText(u16 x,u16 y,char *s){ shf_DrawText_0( x,y,s);} //上はASCIIのみ対応したTextWriterへのラッパ //日本語表示の場合、WideTextWriterを使う(要sft_側の関数追加) nn::hid::PadReader *hpr; //入力待ち nn::hid::PadStatus padStatus; u32 WaitKey(u32 mask) { while(1){ hpr->ReadLatest(&padStatus); if(padStatus.trigger & mask)return padStatus.trigger; CheckSysBreak(); int i = nn::ndm::GetDaemonStatus( nn::ndm::DN_CEC ); if (i !=3 )NN_LOG("DN_CEC %d\n",i); i = nn::ndm::GetDaemonStatus( nn::ndm::DN_BOSS ); if (i !=3 )NN_LOG("DN_BOSS %d\n",i); i = nn::ndm::GetDaemonStatus( nn::ndm::DN_NIM ); if (i !=3 )NN_LOG("DN_NIM %d\n",i); i = nn::ndm::GetDaemonStatus( nn::ndm::DN_FRIENDS ); if (i !=3 )NN_LOG("DN_FRIENDS %d\n",i); } } //終了 void endfunc() { appHeap.Free(reinterpret_cast(readBuf)); appHeap.Free(reinterpret_cast(romfsBuf)); nn::hid::Finalize(); SharedFontFinalize(); nngxWaitVSync(NN_GX_DISPLAY_BOTH);//SDK2.0以降では不要? s_RenderSystem.Finalize(); } //署名検証 bool VeriRsa(u8* src,size_t sz,u8* sig) { nn::crypto::RsaKey key; //nn::crypto::Initialize(); nn::ps::CTR::Initialize(); result = key.InitializePublicKey(PUBLIC_KEY_BEGIN,KEY_LENGTH); if (result.IsSuccess()) { result = nn::ps::CTR::VerifyRsaSha256(src,sz,sig,key); } //nn::crypto::Finalize(); nn::ps::CTR::Finalize(); return result.IsSuccess(); } //エラー void ErrorCommon(char *s,char *ss) { char str[128]; nn::am::FinalizeForLocalImporter(); nn::fs::Unmount("sdmc:"); nn::fs::Unmount("rom:"); NN_LOG(s); NN_LOG(" result = %d\n",result.GetDescription()); shf_SetScale(0.7,0.7); setColor(1.0, 0.0, 0.0,1.0); strcpy(str,"Error: "); strcat(str,s); drawText(10,100,str); drawText(10,140,ss); } void ErrorStop(char *s) { ErrorCommon(s,"Push Home Button & end"); s_RenderSystem.SwapBuffers(); WaitKey(0); } void ErrorPoff(char *s) { ErrorCommon(s,"Push Power Button & Power Off"); drawText(10,160,"Home Button is invalid"); s_RenderSystem.SwapBuffers(); WaitKey(0); } //改行後の位置を返す、0=見つからなかった int CrLf(int n,int max) { u8 d; while(n < max) { d = readBuf[n]; if (d==0x0a)return n+1;//LF if (d==0x0d)//CR { if (n == max-1)return 0;//終端 n++; if (readBuf[n]==0x0a)return n+1;//CR+LF ErrorStop("list broken");//CRのみは異常、署名時にファイル壊れてた? } n++; } return 0; } nn::fs::FileInputStream fi; //ファイルリード s32 FileRead(char* fname) { s32 size; result = fi.TryInitialize(fname); if (result.IsFailure()){//open error //NN_LOG("desc= %d\n",result.GetDescription()); return 0; } result = fi.TryRead(&size,readBuf,READ_BUFFER_SIZE); fi.Finalize(); if (result.IsFailure()){ //NN_LOG("desc= %d\n",result.GetDescription()); return 0; } return size; } char ver[16]; char seri[32]; void nnMain( void ) { //nn::Result result; bool flg_applove=false; bool flg_test=false; int i,j,n; s32 fsize; extern bool prohibitHome;// HOME ボタン禁止 nn::os::Initialize(); nn::fs::Initialize(); //DEA-SUPにて推奨のフリーズ暫定対策:無線デーモンを停止 (2011.3.1 現在) //ただし、スリープ時の"いつのまに通信"は止まらない //無線は使わないので本体横スイッチ切っとくのが確実 nn::ndm::Initialize(); result = nn::ndm::SuspendScheduler(); NN_LOG("%d",result.GetDescription()); //中断処理の準備 InitSysBreak((uptr)endfunc); // グラフィックスライブラリの初期化は、以降で行わなければならない // 他、アプリケーションの初期化処理 nn::hid::Initialize(); nn::hid::PadReader padReader; hpr = &padReader; //result = nn::ns::CTR::InitializeForShell(); //if (result.IsSuccess()) result = nn::am::InitializeForLocalImporter(); nn::applet::DisableSleep();//スリープ非対応 // ヒープの確保 appHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR); const u32 s_GxHeapSize = 0x800000; // RenderSystem の準備 heapForGx = reinterpret_cast(appHeap.Allocate(s_GxHeapSize)); s_RenderSystem.Initialize(heapForGx, s_GxHeapSize); SharedFontInit(); // 共有フォントの種類を取得 //nn::pl::SharedFontType sftype = nn::pl::GetSharedFontType(); // スリープ要求に対する返答を有効にする // また、蓋の状態チェックを行い蓋が閉じられているならスリープ要求が発生する // nn::applet::EnableSleep(true); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); // s_RenderSystem.SetFontSize(12); shf_SetScale(0.8,0.6); setColor(1.0,1.0,1.0,1.0); drawText(20,20,"CTR Card Savedata Mover Setup"); s_RenderSystem.SwapBuffers(); shf_SetScale(0.5,0.5); sprintf(ver,"version %.2f",VERSION); drawText(250,40,ver); shf_SetScale(0.7,0.7); if (result.IsFailure())ErrorStop("Initialize");//初期化に失敗 if (READ_BUFFER_SIZE < LIST_LENGTH)ErrorStop("buffer size");//バッファサイズのチェック //ファイルバッファ //カゲマイ上のSDリード速度比較実験で32アラインが良かったので、おまじない //回数もサイズも少ないので気にする必要ないかも if (READ_BUFFER_SIZE > appHeap.GetTotalFreeSize())ErrorStop("memory alloc"); readBuf = reinterpret_cast(appHeap.Allocate(READ_BUFFER_SIZE,32)); if (ROMFS_BUFFER_SIZE > appHeap.GetTotalFreeSize())ErrorStop("memory alloc"); romfsBuf = reinterpret_cast(appHeap.Allocate(ROMFS_BUFFER_SIZE,32)); //シリアルチェック if( GetSerial() == false)ErrorStop("Get Serial");//本体シリの取得に失敗 result = nn::fs::MountSdmc();//ダイレクトでマウント..マスタリング時にワーニング if (result.IsFailure())ErrorStop("Mount SD"); fsize = FileRead(INF_FILE);//設定ファイルがあるか if((fsize < 1024) && (fsize > 0))//サイズチェック,増えても1Kは超えない {//不具合調査時に状況にあわせて現場で作成&変更を想定したオプション //通常は不要なので無しでも動くようしとく n = 0; while(n < fsize) { if (readBuf[n] == '-'){ if (n == fsize-1)break;//終端 n++; switch (readBuf[n]){ case 'p':// -p .. 本体シリアル表示 strcpy(seri,"s/n: "); strcat(seri,(char *)serialNo); shf_SetScale(0.5,0.5); drawText(10,40,(char*)seri); shf_SetScale(0.7,0.7); break; case 't':// -t .. テストメニュー有効 flg_test = true; break; } } n++; } } //シリアル表示(オプション)後にチェック //デバッガ=15,実機=11 if (GettedSerLen < 11)ErrorStop("invalid Serial"); fsize = FileRead(SIGN_FILE);//署名リード if(fsize != 256)ErrorStop("sign file");//鍵のbit長は2046固定 memcpy(sign,readBuf,256);//readBuf -> sign fsize = FileRead(LIST_FILE);//リストリード if((fsize > LIST_LENGTH ) || (fsize == 0))ErrorStop("list file"); nn::fs::Unmount("sdmc:"); //検証後はSDから読まないでメモリバッファ上のデータを使う: 差替え対策 if (VeriRsa(readBuf,fsize,sign) == false)ErrorStop("sign verify"); //署名検証OK int list_ct = 0; n=0; while(n < fsize)//リスト作成 { if (readBuf[n] == '#')//コメント行を無視、ワイド文字非対応 { i = CrLf(n,fsize);//コメントの次行 if (i == 0)break;//ファイル終わりまで改行が見つからない }else { //改行さがし if ((fsize-n) > (SDK_SER_LEN+2)) {//シリアルは改行つける i = CrLf(n,n+SDK_SER_LEN+2); if (i == 0)ErrorStop("list broken");//改行が見つからない }else{ i = CrLf(n,fsize); if (i ==0)i = fsize;//改行以外でファイル終 } if ((i-n) > GettedSerLen)//シリアルをリスト化 { j = 0; while(n=LIST_MAX)ErrorStop("List too Long"); } } if ((fsize-i) < GettedSerLen)break;//ファイル終 n=i;//ポインタを改行の次へ } //プログラムミス、コードバグ対策 //値が小さいと判定が緩くなるが、動作確認時にスルーしそうなので //念の為チェック if (GettedSerLen < 11)ErrorStop("invalid Serial"); //本体シリアルがリストにあるかチェック n =0; while(n