From 551a48149f9c0ee4600beef822cbc6c41062597b Mon Sep 17 00:00:00 2001 From: d0k3 Date: Mon, 21 Aug 2017 19:56:30 +0200 Subject: [PATCH] Scripting: add fixcmac command fixes #175 check HelloScript.gm9 for how it's done --- HelloScript.gm9 | 6 ++++++ source/filesys/fsscript.c | 9 ++++++++- source/nand/nandcmac.c | 40 +++++++++++++++++++++++++++++++++++++-- source/nand/nandcmac.h | 1 + 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/HelloScript.gm9 b/HelloScript.gm9 index ff4fd6b..0e538e1 100644 --- a/HelloScript.gm9 +++ b/HelloScript.gm9 @@ -128,6 +128,12 @@ set ERRORMSG "SHA check failed (this was expected)" sha -o $[RENPATH] $[TESTPATH].sha set ERRORMSG "" +# 'fixcmac' COMMAND +# Use this to fix the CMACs for a file or a whole folder (recursively) +# This will count as success if a file does not contain a CMAC +# More info on CMACs: http://3dbrew.org/wiki/Savegames#AES_CMAC_header +# fixcmac 1:/data + # 'verify' COMMAND # Certain file formats (NAND, NCCH, NCSD, CIA, FIRM, ...) can also be verified. Use 'verify' to do so. # verify -o s:/firm0.bin # As drive letters are case sensitive, this would fail diff --git a/source/filesys/fsscript.c b/source/filesys/fsscript.c index f50eb24..a0bf653 100644 --- a/source/filesys/fsscript.c +++ b/source/filesys/fsscript.c @@ -2,6 +2,7 @@ #include "fsutil.h" #include "fsinit.h" #include "fsperm.h" +#include "nandcmac.h" #include "nandutil.h" #include "gameutil.h" #include "keydbutil.h" @@ -46,6 +47,7 @@ typedef enum { CMD_ID_DECRYPT, CMD_ID_ENCRYPT, CMD_ID_BUILDCIA, + CMD_ID_BOOT, CMD_ID_REBOOT, CMD_ID_POWEROFF } cmd_id; @@ -78,11 +80,12 @@ Gm9ScriptCmd cmd_list[] = { { CMD_ID_FIND , "find" , 2, 0 }, { CMD_ID_FINDNOT , "findnot" , 2, 0 }, { CMD_ID_SHA , "sha" , 2, 0 }, - // { CMD_ID_FIXCMAC , "fixcmac" , 1, 0 }, // not supported yet + { CMD_ID_FIXCMAC , "fixcmac" , 1, 0 }, { CMD_ID_VERIFY , "verify" , 1, 0 }, { CMD_ID_DECRYPT , "decrypt" , 1, 0 }, { CMD_ID_ENCRYPT , "encrypt" , 1, 0 }, { CMD_ID_BUILDCIA, "buildcia", 1, _FLG('l') }, + // { CMD_ID_BOOT , "boot" , 1, 0 }, // not supported yet { CMD_ID_REBOOT , "reboot" , 0, 0 }, { CMD_ID_POWEROFF, "poweroff", 0, 0 } }; @@ -445,6 +448,10 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { ret = (memcmp(sha256_fil, sha256_cmp, 0x20) == 0); if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha does not match"); } + } else if (id == CMD_ID_FIXCMAC) { + ShowString("Fixing CMACs..."); + ret = (RecursiveFixFileCmac(argv[0]) == 0); + if (err_str) snprintf(err_str, _ERR_STR_LEN, "fixcmac failed"); } else if (id == CMD_ID_VERIFY) { u32 filetype = IdentifyFileType(argv[0]); if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0); diff --git a/source/nand/nandcmac.c b/source/nand/nandcmac.c index 7197c89..119ee82 100644 --- a/source/nand/nandcmac.c +++ b/source/nand/nandcmac.c @@ -6,14 +6,14 @@ #include "vff.h" // CMAC types, see: -// https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header +// https://3dbrew.org/wiki/Savegames#AES_CMAC_header // https://3dbrew.org/wiki/Nand/private/movable.sed // https://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame #define CMAC_EXTDATA_SD 1 #define CMAC_EXTDATA_SYS 2 #define CMAC_SAVEDATA_SYS 3 #define CMAC_SAVE_GAMECARD 4 -#define CMAC_SAVEGAME 5 // this is not calclated into a CMAC +#define CMAC_SAVEGAME 5 // this is not calculated into a CMAC #define CMAC_SAVEDATA_SD 6 #define CMAC_TITLEDB_SYS 7 #define CMAC_TITLEDB_SD 8 @@ -233,3 +233,39 @@ u32 FixFileCmac(const char* path) { u8 ccmac[16]; return ((CalculateFileCmac(path, ccmac) == 0) && (WriteFileCmac(path, ccmac) == 0)) ? 0 : 1; } + +u32 RecursiveFixFileCmacWorker(char* path) { + FILINFO fno; + + if (fvx_stat(path, &fno) != FR_OK) return 1; // path does not exist + if (fno.fattrib & AM_DIR) { // process folder contents + DIR pdir; + char* fname = path + strnlen(path, 255); + if (fvx_opendir(&pdir, path) != FR_OK) return 1; + *(fname++) = '/'; + + while (f_readdir(&pdir, &fno) == FR_OK) { + if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) + continue; // filter out virtual entries + strncpy(fname, fno.fname, path + 255 - fname); + if (fno.fname[0] == 0) { + break; + } else if (fno.fattrib & AM_DIR) { // directory, recurse through it + if (RecursiveFixFileCmacWorker(path) != 0) return 1; + } else if (CheckCmacPath(path) == 0) { // file, try to fix the CMAC + if (FixFileCmac(path) != 0) return 1; + } + } + f_closedir(&pdir); + *(--fname) = '\0'; + } else if (CheckCmacPath(path) == 0) + return FixFileCmac(path); + + return 0; +} + +u32 RecursiveFixFileCmac(const char* path) { + char lpath[256] = { 0 }; + strncpy(lpath, path, 255); + return RecursiveFixFileCmacWorker(lpath); +} diff --git a/source/nand/nandcmac.h b/source/nand/nandcmac.h index 9a92cae..bf83c00 100644 --- a/source/nand/nandcmac.h +++ b/source/nand/nandcmac.h @@ -8,3 +8,4 @@ u32 WriteFileCmac(const char* path, u8* cmac); u32 CalculateFileCmac(const char* path, u8* cmac); u32 CheckFileCmac(const char* path); u32 FixFileCmac(const char* path); +u32 RecursiveFixFileCmac(const char* path);