GodMode9/arm9/source/utils/ctrtransfer.c

106 lines
4.9 KiB
C

#include "ctrtransfer.h"
#include "nandcmac.h"
#include "fs.h"
#include "essentials.h"
#include "ui.h"
/*static const u8 twl_mbr[0x42] = { // encrypted version inside the NCSD NAND header (@0x1BE)
0x00, 0x04, 0x18, 0x00, 0x06, 0x01, 0xA0, 0x3F, 0x97, 0x00, 0x00, 0x00, 0xA9, 0x7D, 0x04, 0x00,
0x00, 0x04, 0x8E, 0x40, 0x06, 0x01, 0xA0, 0xC3, 0x8D, 0x80, 0x04, 0x00, 0xB3, 0x05, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0xAA
};*/
static const u8 ctr_mbr_o3ds[0x42] = { // found at the beginning of the CTRNAND partition (O3DS)
0x00, 0x05, 0x2B, 0x00, 0x06, 0x02, 0x42, 0x80, 0x65, 0x01, 0x00, 0x00, 0x1B, 0x9F, 0x17, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0xAA
};
static const u8 ctr_mbr_n3ds[0x42] = { // found at the beginning of the CTRNAND partition (N3DS)
0x00, 0x05, 0x1D, 0x00, 0x06, 0x02, 0x82, 0x17, 0x57, 0x01, 0x00, 0x00, 0x69, 0xE9, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0xAA
};
u32 CheckTransferableMbr(void* data) { // strict checks, custom partitions not allowed
u8* mbr = (u8*) data;
if (memcmp(mbr + (0x200 - sizeof(ctr_mbr_o3ds)), ctr_mbr_o3ds, sizeof(ctr_mbr_o3ds)) == 0)
return 0; // is transferable, O3DS type
else if (memcmp(mbr + (0x200 - sizeof(ctr_mbr_n3ds)), ctr_mbr_n3ds, sizeof(ctr_mbr_n3ds)) == 0)
return 0; // is transferable, N3DS type
return 1;
}
u32 TransferCtrNandImage(const char* path_img, const char* drv) {
if (!CheckWritePermissions(drv)) return 1;
// backup current mount path, mount new path
char path_store[256] = { 0 };
char* path_bak = NULL;
strncpy(path_store, GetMountPath(), 256);
if (*path_store) path_bak = path_store;
if (!InitImgFS(path_img)) {
InitImgFS(path_bak);
return 1;
}
// CTRNAND preparations
SecureInfo* secnfo_img = (SecureInfo*) TEMP_BUFFER;
SecureInfo* secnfo_loc = (SecureInfo*) (TEMP_BUFFER + 0x200);
char* path_secnfo_a = (char*) (TEMP_BUFFER + 0x400);
char* path_secnfo_b = (char*) (TEMP_BUFFER + 0x420);
char* path_secnfo_c = (char*) (TEMP_BUFFER + 0x440);
char* path_tickdb = (char*) (TEMP_BUFFER + 0x460);
char* path_tickdb_bak = (char*) (TEMP_BUFFER + 0x480);
snprintf(path_secnfo_a, 32, "%s/rw/sys/SecureInfo_A", drv);
snprintf(path_secnfo_b, 32, "%s/rw/sys/SecureInfo_B", drv);
snprintf(path_secnfo_c, 32, "%s/rw/sys/SecureInfo_C", drv);
snprintf(path_tickdb, 32, "%s/dbs/ticket.db", drv);
snprintf(path_tickdb_bak, 32, "%s/dbs/ticket.bak", drv);
// special handling for out of region images (create SecureInfo_C)
PathDelete(path_secnfo_c); // not required when transfering back to original region
if (((FileGetData("7:/rw/sys/SecureInfo_A", (u8*) secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) ||
(FileGetData("7:/rw/sys/SecureInfo_B", (u8*) secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) &&
((FileGetData(path_secnfo_a, (u8*) secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) ||
(FileGetData(path_secnfo_b, (u8*) secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) &&
(secnfo_img->region != secnfo_loc->region)) {
secnfo_loc->region = secnfo_img->region;
FileSetData(path_secnfo_c, (u8*) secnfo_loc, sizeof(SecureInfo), 0, true);
}
// make a backup of ticket.db
PathDelete(path_tickdb_bak);
PathRename(path_tickdb, "ticket.bak");
// actual transfer - db files / titles
const char* dbnames[] = { "ticket.db", "certs.db", "title.db", "import.db", "tmp_t.db", "tmp_i.db" };
char path_to[32];
char path_from[32];
char path_dbs[32];
u32 flags = OVERWRITE_ALL;
snprintf(path_dbs, 32, "%s/dbs", drv);
for (u32 i = 0; i < sizeof(dbnames) / sizeof(char*); i++) {
snprintf(path_to, 32, "%s/dbs/%s", drv, dbnames[i]);
snprintf(path_from, 32, "7:/dbs/%s", dbnames[i]);
PathDelete(path_to);
PathCopy(path_dbs, path_from, &flags);
FixFileCmac(path_to);
}
ShowString("Cleaning up titles, please wait...");
snprintf(path_to, 32, "%s/title", drv);
snprintf(path_from, 32, "7:/title");
PathDelete(path_to);
PathCopy(drv, path_from, &flags);
InitImgFS(path_bak);
return 0;
}