TwlIPL/build/tests/FakeRomHeader/main.c
nishikawa_takeshi dc09a441b7 ROMヘッダ偽装:MROM->1TROM変更のMROM判定をやめる。問答無用に1TROMに変換。
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2475 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2008-09-10 10:20:05 +00:00

480 lines
14 KiB
C

/*---------------------------------------------------------------------------*
Project: TwlFirmware - tools - mastering
File: mastering.c
Copyright 2003 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.
$Date:: #$
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strcasecmp()
#include <getopt.h> // getopt()
#include <sys/stat.h> // stat()
#include <stdarg.h>
#include <conio.h>
#include <twl/types.h>
#include <twl/os/common/format_rom.h>
#include <acsign/include/acsign.h>
#include "revision.h"
#include "keys.h"
#define CARD_LATENCY_MASK 0x083f1fff
#define CARD_MROM_GAME_LATENCY 0x00010017
#define CARD_MROM_SECURE_HW_LATENCY 0x001808f8
#define CARD_MROM_SECURE_SW_LATENCY 0x051e
#define CARD_1TROM_GAME_LATENCY 0x00010657
#define CARD_1TROM_SECURE_HW_LATENCY 0x081808f8
#define CARD_1TROM_SECURE_SW_LATENCY 0x0d7e
/*---------------------------------------------------------------------------*
宣言 & 定数
*---------------------------------------------------------------------------*/
// -- 内部パラメータ
// CRC (makerom.TWL/misc.cとmakerom.TWL/format_rom_private.hからコピペ)
#define CRC16_INIT_VALUE (0xffff)
#define CALC_CRC16_SIZE (0x15e)
// ファイルコピー用バッファ
#define BUFSIZE (16*1024)
static u8 buf[ BUFSIZE ];
// -- Context
typedef struct _SContext
{
// オプション
BOOL bPlatform;
BOOL bSignFlag;
BOOL bDevFlag;
BOOL bVerFlag;
int verNum;
BOOL bMROM;
FILE *ifp;
FILE *ofp;
}
SContext;
// -- internal function
static BOOL iMain( SContext *pContext );
u16 CalcCRC16(u16 start, u8 *data, int size);
BOOL SignRomHeader( ROM_Header *prh );
static void SetRomSpeedByIndex(ROM_Header * header, tRomSpeedType idx);
/*---------------------------------------------------------------------------*
グローバル変数
*---------------------------------------------------------------------------*/
BOOL DebugMode = FALSE;
/*---------------------------------------------------------------------------*
おおもとの本体
*---------------------------------------------------------------------------*/
void usage()
{
printf( "-----------------------------------------------------------------------------\n" );
printf( "Usage: fakeRomHeader.exe input_file output_file\n" );
printf( " input_file : a ROM data file (generated by makerom.TWL).\n" );
printf( " output_file : a destination file.\n" );
printf( "\nOption:\n" );
printf( "-h : print help only.\n" );
printf( "-p : write invalid platform code in a ROM Header.\n" );
printf( "-s : negate flag for the signature in a ROM Header.\n" );
printf( "-d : negate a new developer encrypt flag, and assert an old one.\n" );
printf( "-v NUM: change ROM version in a ROM Header.\n" );
printf( "-m : [Only NTR limited ROM] Rom speed type replace 1TROM from MROM\n" );
printf( "-----------------------------------------------------------------------------\n" );
}
int main(int argc, char *argv[])
{
SContext context;
char *pSrc, *pDst;
int opt;
extern char *optarg;
extern int optind, opterr;
struct stat st;
BOOL bResult;
printf( "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" );
printf( " fakeRomHeader [%s-%s]\n", SDK_REVISION, IPL_REVISION );
printf( "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" );
// context の初期化
memset( &context, 0, sizeof(SContext) );
// オプション
while( (opt = getopt(argc, argv, "hpsdmv:")) >= 0 )
{
switch( opt )
{
case 'h':
usage();
return 0;
break;
case 'p':
context.bPlatform = TRUE;
break;
case 's':
context.bSignFlag = TRUE;
break;
case 'd':
context.bDevFlag = TRUE;
break;
case 'v':
context.bVerFlag = TRUE;
context.verNum = atoi(optarg);
break;
case 'm':
context.bMROM = TRUE;
break;
default: // オプション引数が指定されていないときにも実行される
usage();
fprintf( stdout, "error: illegal option\n" );
exit(1);
break;
}
}
argc = argc - optind;
argv = argv + optind;
// 引数処理
if( argc != 2 )
{
usage();
printf( "error arguments\n" );
exit(1);
}
else
{
pSrc = argv[0];
pDst = argv[1];
}
printf( "input_file: %s\n", pSrc );
printf( "output_file: %s\n", pDst );
printf( "\n" );
// 入力ファイルと出力ファイル名が同じならダメ
if( (strlen(pSrc) == strlen(pDst)) && (memcmp(pSrc, pDst, strlen(pSrc)) == 0) )
{
printf( "The name of output_file must be different from the one of input_file\n" );
exit(1);
}
// 出力ファイルが存在するとき上書きするかどうかを確認する
if( stat( pDst, &st )==0 )
{
char ans;
printf( "The %s already exists. Overwrite it? (y or n) ", pDst );
//fscanf( stdin, "%c", &ans );
ans = (char)getch(); // リターンキーなし
printf( "%c\n", ans ); // getch では入力が表示されないので自分で表示する必要あり
printf( "\n" );
if( !(ans=='y') && !(ans=='Y') )
{
printf( "mastering is aborted.\n" );
exit(1);
}
}
// ファイルを開く
context.ifp = fopen(pSrc, "rb");
context.ofp = fopen(pDst, "wb+");
if( !(context.ifp) || !(context.ofp) )
{
printf( "fopen failed.\n" );
bResult = FALSE;
goto FINALIZE;
}
// 本処理
bResult = iMain( &context );
// 終了処理
FINALIZE:
if( !bResult )
{
printf( "\n" );
printf( "error.\n" );
}
else
{
printf( "\n" );
printf( "succeeded.\n" );
}
if( context.ifp ) fclose(context.ifp); // 資源の解放
if( context.ofp ) fclose(context.ofp);
if( (!bResult) && (stat( pDst, &st ) == 0) )
{
unlink( pDst ); // 出力ファイルを削除する
}
return 0;
}
/*---------------------------------------------------------------------------*
ROMヘッダの偽装
*---------------------------------------------------------------------------*/
static BOOL iMain( SContext *pContext )
{
ROM_Header rh;
int size;
// ROMヘッダをリード
fseek( pContext->ifp, 0, SEEK_SET );
if( sizeof(ROM_Header) != fread( &rh, 1, sizeof(ROM_Header), pContext->ifp ) )
{
printf( "fread failed in reading ROM Header\n" );
return FALSE;
}
// ROMヘッダをいじる
{
if( pContext->bPlatform )
{
printf( "platform_code: 0x%02x -> 0x01\n", rh.s.platform_code );
rh.s.platform_code = 0x01;
}
if( pContext->bSignFlag )
{
printf( "enable_signature: 0x%02x -> 0x00\n", rh.s.enable_signature );
rh.s.enable_signature = 0x0;
}
if( pContext->bDevFlag )
{
printf( "old dev. encrypt: 0x%02x -> 0x01x\n", rh.s.developer_encrypt_old );
printf( "new dev. encrypt: 0x%02x -> 0x00x\n", rh.s.exFlags.developer_encrypt );
rh.s.developer_encrypt_old = 0x1;
rh.s.exFlags.developer_encrypt = 0x0;
}
if( pContext->bVerFlag )
{
printf( "ROM version: 0x%02x -> 0x%02x\n", rh.s.rom_version, pContext->verNum );
rh.s.rom_version = pContext->verNum;
}
if( pContext->bMROM )
{
if( rh.s.platform_code != 0x00 )
{
printf( "ERROR: This option is only for NTR Limited." );
return FALSE;
}
//if( (rh.s.game_cmd_param & CARD_LATENCY_MASK) != CARD_MROM_GAME_LATENCY )
//{
// printf( "ERROR: This option is only for MROM Setting" );
// return FALSE;
//}
SetRomSpeedByIndex( &rh, ONETROM );
printf( "ROM Speed Type: **** -> 1TROM\n" );
}
}
// ヘッダCRC計算
rh.s.header_crc16 = CalcCRC16( CRC16_INIT_VALUE, (u8*)&rh, CALC_CRC16_SIZE );
// 署名
if( !(pContext->bMROM) ) // NTR専用オプションのときは署名しない
{
if( !SignRomHeader( &rh ) )
{
return FALSE;
}
}
// ファイルをコピる
fseek( pContext->ifp, 0, SEEK_END );
size = ftell( pContext->ifp );
fseek( pContext->ifp, 0, SEEK_SET );
fseek( pContext->ofp, 0, SEEK_SET );
while( size > 0 )
{
int len = (BUFSIZE < size)?BUFSIZE:size;
if( len != fread( buf, 1, len, pContext->ifp ) )
{
printf( "fread failed in a copying file\n" );
return FALSE;
}
if( len != fwrite( buf, 1, len, pContext->ofp ) )
{
printf( "fwrite failed in a copying file\n" );
return FALSE;
}
size -= len;
}
// ROMヘッダを上書き
fseek( pContext->ofp, 0, SEEK_SET );
if( sizeof(ROM_Header) != fwrite( &rh, 1, sizeof(ROM_Header), pContext->ofp ) )
{
printf( "fwrite failed in a copying file\n" );
return FALSE;
}
return TRUE;
}
/*---------------------------------------------------------------------------*
CRCの計算
*---------------------------------------------------------------------------*/
static u16 crc16_table[16] = {
0x0000, 0xCC01, 0xD801, 0x1400,
0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401,
0x5000, 0x9C01, 0x8801, 0x4400
};
u16 CalcCRC16(u16 start, u8 *data, int size)
{
u16 r1;
u16 total = start;
while (size-- > 0)
{
// 下位4bit
r1 = crc16_table[total & 0xf];
total = (total >> 4) & 0x0fff;
total = total ^ r1 ^ crc16_table[*data & 0xf];
// 上位4bit
r1 = crc16_table[total & 0xf];
total = (total >> 4) & 0x0fff;
total = total ^ r1 ^ crc16_table[(*data >> 4) & 0xf];
data++;
}
return total;
}
/*---------------------------------------------------------------------------*
ROMヘッダの署名
*---------------------------------------------------------------------------*/
BOOL SignRomHeader( ROM_Header *prh )
{
SignatureData signSrc; // 署名のもととなるダイジェスト値
u8 signDst[ RSA_KEY_LENGTH ]; // 署名の格納先Tmpバッファ
u8 decryptBlock[ RSA_KEY_LENGTH ]; // 署名を解除後ブロックバッファ
BOOL result;
int pos;
// ROMヘッダのダイジェストを算出(先頭から証明書領域の直前までが対象)
ACSign_DigestUnit(
signSrc.digest,
prh,
(u32)&(prh->certificate) - (u32)prh // this->pRomHeader はマネージヒープ上にあるので実アドレスを取得できない
);
#ifdef KEY_USER
printf( "Signature Key: USER\n" );
#endif
#ifdef KEY_SYSTEM
printf( "Signature Key: SYSTEM\n" );
#endif
#ifdef KEY_SECURE
printf( "Signature Key: SECURE\n" );
#endif
#ifdef KEY_LAUNCHER
printf( "Signature Key: LAUNCHER\n" );
#endif
// ダイジェストに署名をかける
result = ACSign_Encrypto( signDst, g_devPrivKey_DER, &signSrc, sizeof(SignatureData) );
if( !result )
{
printf( "ACSign_Encrypto encryption failed.\n" );
return FALSE;
}
// 署名を解除してダイジェストと一致するかベリファイする
result = ACSign_Decrypto( decryptBlock, g_devPubKey_DER, signDst, RSA_KEY_LENGTH );
for( pos=0; pos < RSA_KEY_LENGTH; pos++ )
{
if( decryptBlock[pos] == 0x0 ) // 解除後ブロックから実データをサーチ
break;
}
if( !result || (memcmp( &signSrc, &(decryptBlock[pos+1]), sizeof(SignatureData) ) != 0) )
{
printf( "Verification a signature failed.\n" );
return FALSE;
}
// ROMヘッダに署名を上書き
memcpy( prh->signature, signDst, RSA_KEY_LENGTH );
return TRUE;
} // ECSrlResult RCSrl::signRomHeader(void)
/*---------------------------------------------------------------------------*
ROM Speed Typeの設定
*---------------------------------------------------------------------------*/
static ROM_LT romSpeedTypeLatencyTable[] = {
{CARD_1TROM_GAME_LATENCY, CARD_1TROM_SECURE_HW_LATENCY, CARD_1TROM_SECURE_SW_LATENCY},
{CARD_MROM_GAME_LATENCY, CARD_MROM_SECURE_HW_LATENCY, CARD_MROM_SECURE_SW_LATENCY},
};
static void SetRomSpeedByIndex(ROM_Header * header, tRomSpeedType idx)
{
ROM_LT *l = &romSpeedTypeLatencyTable[idx];
header->s.game_cmd_param &= ~CARD_LATENCY_MASK;
header->s.game_cmd_param |= l->game_latency;
header->s.secure_cmd_param &= ~CARD_LATENCY_MASK;
header->s.secure_cmd_param |= l->secure_hw_latency;
header->s.secure_cmd_latency = l->secure_sw_latency;
}
// end of file