Skip to content

Commit

Permalink
Took over improvements from D9
Browse files Browse the repository at this point in the history
  • Loading branch information
d0k3 committed Feb 25, 2017
1 parent 8753c3a commit c389977
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 54 deletions.
2 changes: 1 addition & 1 deletion source/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#define BUFFER_MAX_SIZE ((u32) (1 * 1024 * 1024))

// info / log file name
#define VERSION_NAME "Hourglass9 v1.40"
#define VERSION_NAME "Hourglass9 v1.45"
#define LOG_FILE "Hourglass9.log"

// hacky handling of D9 game dir stuff
Expand Down
50 changes: 30 additions & 20 deletions source/decryptor/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ u32 GetSdCtr(u8* ctr, const char* path)
u32 plen = 0;
// poor man's UTF-8 -> UTF-16
for (u32 i = 0; i < 128; i++) {
hashstr[2*i] = path[i];
u8 symbol = path[i];
if ((symbol >= 'A') && (symbol <= 'Z')) symbol += ('a' - 'A');
hashstr[2*i] = symbol;
hashstr[2*i+1] = 0;
if (path[i] == 0) {
if (symbol == 0) {
plen = i;
break;
}
Expand Down Expand Up @@ -1489,6 +1491,7 @@ u32 ConvertSdToCia(u32 param)
if (DebugCheckCancel())
return 1;
}
ShowProgress(0, 0);
}

if (!tik_legit)
Expand Down Expand Up @@ -1540,12 +1543,13 @@ u32 ConvertSdToCia(u32 param)
u32 c = 0;
u32 next_offset = stub_size;
u32 content_count = getbe16(tmd->content_count);
bool dlc = (tid_high == 0x0004008C);
for (c = 0; c < content_count; c++) {
u32 id = getbe32(content_list[c].id);
u32 size = (u32) getbe64(content_list[c].size);
u32 offset = next_offset;
next_offset = offset + size;
snprintf(filename, 16, "/%08lx.app", id);
snprintf(filename, 32, (dlc) ? "/00000000/%08lx.app" : "/%08lx.app", id);
Debug("Injecting content id %08lX (%lu kB)...", id, size / 1024);
if (!FileOpen(titlepath)) {
Debug("Content not found");
Expand Down Expand Up @@ -1954,6 +1958,7 @@ u32 DumpCtrGameCart(u32 param)

// output some info
Debug("Product ID: %.16s", ncch->productcode);
Debug("Product version: %02u", ((u8*)ncsd)[0x312]);
Debug("Cartridge data size: %lluMB", cart_size / 0x100000);
Debug("Cartridge used size: %lluMB", data_size / 0x100000);
if (data_size > cart_size) {
Expand All @@ -1977,7 +1982,8 @@ u32 DumpCtrGameCart(u32 param)
dump_size = (param & CD_TRIM) ? data_size : cart_size;
Debug("Cartridge dump size: %lluMB", dump_size / 0x100000);
if ((dump_size == 0x100000000) && (data_size < dump_size)) {
dump_size -= 0x200; // silently remove the last sector for 4GB ROMs
Debug("Warning: 4GB rom, ignoring last byte");
dump_size--; // remove the last byte for 4GB carts
} else if (dump_size >= 0x100000000) { // should not happen
Debug("Error: Too big for the FAT32 file system");
if (!(param & CD_TRIM))
Expand All @@ -1994,8 +2000,13 @@ u32 DumpCtrGameCart(u32 param)

// create file, write CIA / NCSD header
Debug("");
snprintf(filename, 64, "/%s%s%.16s%s.%s", GetGameDir() ? GetGameDir() : "", GetGameDir() ? "/" : "",
ncch->productcode, (param & CD_DECRYPT) ? "-dec" : "", (param & CD_MAKECIA) ? "cia" : "3ds");
snprintf(filename, 64, "/%s%s%.16s_%02u%s.%s",
GetGameDir() ? GetGameDir() : "",
GetGameDir() ? "/" : "",
ncch->productcode,
((u8*)ncsd)[0x312], // version
(param & CD_DECRYPT) ? "-dec" : "",
(param & CD_MAKECIA) ? "cia" : "3ds");
if (!FileCreate(filename, true)) {
Debug("Could not create output file on SD");
return 1;
Expand Down Expand Up @@ -2135,7 +2146,6 @@ u32 DumpTwlGameCart(u32 param)
u8* dsibuff = BUFFER_ADDRESS;
u8* buff = BUFFER_ADDRESS+0x8000;
u64 offset = 0x8000;
char name[16];
u32 arm9iromOffset = -1;
int isDSi = 0;

Expand All @@ -2148,16 +2158,16 @@ u32 DumpTwlGameCart(u32 param)
return 1;
}

memset (name, 0x00, sizeof (name));
memcpy (name, &buff[0x00], 12);
Debug("Product name: %s", name);

memset (name, 0x00, sizeof (name));
memcpy (name, &buff[0x0C], 4 + 2);
Debug("Product ID: %s", name);
// Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi)
isDSi = (buff[0x12] != 0x00);
Debug("Product name: %.12s", (char*) &buff[0x00]);
Debug("Product ID: %.6s", (char*) &buff[0x0C]);
Debug("Product version: %02u", buff[0x1E]);

cart_size = (128 * 1024) << buff[0x14];
data_size = *((u32*)&buff[0x80]);;
// NTR used data size field does not include TWL-specific data.
// Use the TWL field.
data_size = (isDSi) ? *((u32*)&buff[0x210]) : *((u32*)&buff[0x80]);
dump_size = (param & CD_TRIM) ? data_size : cart_size;
Debug("Cartridge data size: %lluMB", cart_size / 0x100000);
Debug("Cartridge used size: %lluMB", data_size / 0x100000);
Expand All @@ -2174,7 +2184,10 @@ u32 DumpTwlGameCart(u32 param)
}

Debug("");
snprintf(filename, 64, "/%s%s%s.nds", GetGameDir() ? GetGameDir() : "", GetGameDir() ? "/" : "", name);
snprintf(filename, 64, "/%s%s%.6s_%02u.nds",
GetGameDir() ? GetGameDir() : "",
GetGameDir() ? "/" : "",
(const char*)&buff[0x0C], buff[0x1E]);

if (!DebugFileCreate(filename, true))
return 1;
Expand All @@ -2183,10 +2196,7 @@ u32 DumpTwlGameCart(u32 param)
return 1;
}

// Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi)
if (buff[0x12] != 0x00) {
isDSi = 1;

if (isDSi) {
// initialize cartridge
Cart_Init();
//Cart_GetID();
Expand Down
2 changes: 1 addition & 1 deletion source/decryptor/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ typedef struct {
u8 sector_zero_offset[0x4];
u8 partition_flags[8];
u8 partitionId_table[8][8];
u8 reserved[0x40];
u8 reserved[0x30];
} __attribute__((packed, aligned(16))) NcsdHeader;

typedef struct {
Expand Down
21 changes: 14 additions & 7 deletions source/decryptor/nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
#define NAND_HDR_O3DS 1
#define NAND_HDR_N3DS 2

// these offsets are used by Multi EmuNAND Creator / CakesFW
#define EMUNAND_MULTI_SECTORS ((getMMCDevice(0)->total_size > 0x200000) ? 0x400000 : 0x200000)

// minimum sizes for O3DS / N3DS NAND
// see: http://3dbrew.org/wiki/Flash_Filesystem
#define NAND_MIN_SIZE ((GetUnitPlatform() == PLATFORM_3DS) ? 0x3AF00000 : 0x4D800000)
Expand Down Expand Up @@ -74,12 +71,21 @@ static u32 emunand_header = 0;
static u32 emunand_offset = 0;


u32 GetEmuNandMultiSectors(void)
{
u8* buffer = BUFFER_ADDRESS;
u32 compact_sectors = align(1 + (NAND_MIN_SIZE / NAND_SECTOR_SIZE), 0x2000);
u32 legacy_sectors = (getMMCDevice(0)->total_size > 0x200000) ? 0x400000 : 0x200000;
sdmmc_sdcard_readsectors(compact_sectors + 1, 1, buffer);
return (IS_NAND_HEADER(buffer)) ? compact_sectors : legacy_sectors;
}

u32 CheckEmuNand(void)
{
u8* buffer = BUFFER_ADDRESS;
u32 nand_size_sectors = getMMCDevice(0)->total_size;
u32 nand_size_sectors_min = NAND_MIN_SIZE / NAND_SECTOR_SIZE;
u32 multi_sectors = EMUNAND_MULTI_SECTORS;
u32 multi_sectors = GetEmuNandMultiSectors();
u32 ret = EMUNAND_NOT_READY;

// check the MBR for presence of a hidden partition
Expand Down Expand Up @@ -116,11 +122,12 @@ u32 SetNand(bool set_emunand, bool force_emunand)

for (emunand_count = 0; (emunand_state >> (2 * emunand_count)) & 0x3; emunand_count++);
if (emunand_count > 1) { // multiple EmuNANDs -> use selector
u32 multi_sectors = GetEmuNandMultiSectors();
u32 emunand_no = 0;
DebugColor(COLOR_ASK, "Use arrow keys and <A> to choose EmuNAND");
while (true) {
u32 emunandn_state = (emunand_state >> (2 * emunand_no)) & 0x3;
offset_sector = emunand_no * EMUNAND_MULTI_SECTORS;
offset_sector = emunand_no * multi_sectors;
DebugColor(COLOR_SELECT, "\rEmuNAND #%u: %s", emunand_no, (emunandn_state == EMUNAND_READY) ? "EmuNAND ready" : (emunandn_state == EMUNAND_GATEWAY) ? "GW EmuNAND" : "RedNAND");
// user input routine
u32 pad_state = InputWait();
Expand Down Expand Up @@ -418,7 +425,7 @@ u32 OutputFileNameSelector(char* filename, const char* basename, char* extension
snprintf(bases[3], 63, "%s%s" , (emunand_header) ? "emu" : "sys", bases[0]);

u32 fn_id = (emunand_header) ? 1 : 0;
u32 fn_num = (emunand_header) ? (emunand_offset / EMUNAND_MULTI_SECTORS) : 0;
u32 fn_num = 0;
bool exists = false;
char extstr[16] = { 0 };
if (extension)
Expand Down Expand Up @@ -703,7 +710,7 @@ u32 DumpNand(u32 param)
}
sha_update(buffer, NAND_SECTOR_SIZE * read_sectors);
}

if (FileGetSize() < NAND_MIN_SIZE) result = 1; // very improbable
ShowProgress(0, 0);
FileClose();

Expand Down
28 changes: 17 additions & 11 deletions source/decryptor/nandfat.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,16 +401,21 @@ u32 GetRegion(void)

u32 GetSerial(char* serial)
{
PartitionInfo* p_info = GetPartitionInfo(P_CTRNAND);
u8 secureinfo[0x200];
u32 offset;
u32 size;

if ((SeekFileInNand(&offset, &size, "RW SYS SECURE~? ", p_info) != 0) ||
(DecryptNandToMem(secureinfo, offset, size, p_info) != 0))
return 1;

snprintf(serial, 16, "%.15s", (char*) (secureinfo + 0x102));
static char serial_store[16] = { 0 };
if (!(*serial_store)) {
PartitionInfo* p_info = GetPartitionInfo(P_CTRNAND);
u8 secureinfo[0x200];
u32 offset;
u32 size;

if ((SeekFileInNand(&offset, &size, "RW SYS SECURE~? ", p_info) == 0) &&
(DecryptNandToMem(secureinfo, offset, size, p_info) == 0)) {
snprintf(serial_store, 16, "%.15s", (char*) (secureinfo + 0x102));
} else {
snprintf(serial_store, 16, "UNKNOWN");
}
}
memcpy(serial, serial_store, 16);
return 0;
}

Expand Down Expand Up @@ -476,7 +481,8 @@ u32 FixNandCmac(u32 param) {
return 1;
} else if (sscanf(f_info->path, "DATA ???????????SYSDATA %08llX 00000000 ", &id) == 1) { // system save
Debug("CMAC id: %08llX", id);
SetupMovableKeyY(true, 0x30, NULL);
if (SetupMovableKeyY(true, 0x30, NULL) != 0)
return 1;
memcpy(temp + 0x00, "CTR-SYS0", 8);
memcpy(temp + 0x08, &id, 8);
memcpy(temp + 0x10, data + 0x100, 0x100);
Expand Down
3 changes: 3 additions & 0 deletions source/decryptor/selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ u32 SystemInfo(u32 param)
u8* nandcid = (u8*) 0x20316000 + 0x400;
u8* sdcid = (u8*) 0x20316000 + 0x410;
u8* twlcustid = (u8*) 0x01FFB808;
u8* mfg_date = (u8*) 0x01FFB81A;

// Get NAND / SD CID
sdmmc_get_cid(1, (uint32_t*) nandcid);
Expand Down Expand Up @@ -227,6 +228,8 @@ u32 SystemInfo(u32 param)
// NAND stuff output here
Debug("NAND type / size: %s %s / %lluMB", (isDevkit) ? "Devkit" : "Retail", (isN3ds) ? "N3DS" : "O3DS", nand_size / 0x100000);
Debug("Serial / region: %.15s / %s", (char*) serial, (*region < 7) ? regionstr[*region] : regionstr[7]);
Debug("Manufacturing date: %u/%02u/%02u", *(mfg_date) + 1900, *(mfg_date + 1), *(mfg_date + 2));
// the next 3 bytes are hours, minutes, seconds but those were ommitted due to being superfluous info
Debug("NAND CID: %08X%08X%08X%08X", getbe32(nandcid+0), getbe32(nandcid+4), getbe32(nandcid+8), getbe32(nandcid+12));
Debug("TWL customer ID: %08X%08X", getbe32(twlcustid+0), getbe32(twlcustid+4));
Debug("SysNAND SD path <id0> / <id1>:");
Expand Down
12 changes: 6 additions & 6 deletions source/decryptor/transfer.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ u32 NandTransfer(u32 param) {
if (!(param & N_NANDWRITE))
return 1;

// check free space
if (!DebugCheckFreeSpace(128 * 1024 * 1024)) {
Debug("You need at least 128MB free for this operation");
return 1;
}

// deeper check for a9lh
if (!(param & N_EMUNAND) && !a9lh) {
Debug("A9LH not detected, checking FIRM0...");
Expand Down Expand Up @@ -95,6 +89,12 @@ u32 NandTransfer(u32 param) {
return 1;
}

// check free space
if (!DebugCheckFreeSpace(128 * 1024 * 1024)) {
Debug("You need 128MB free to continue this operation");
return 1;
}

Debug("");
Debug("Step #1: .SHA verification of CTRNAND image...");
if (param & TF_FORCED) {
Expand Down
5 changes: 3 additions & 2 deletions source/decryptor/xorpad.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,11 @@ u32 NcchPadgen(u32 param)
}

for (u32 i = 0; i < info->n_entries; i++) {
PadInfo padInfo = {.setKeyY = 1, .size_mb = info->entries[i].size_mb, .mode = AES_CNT_CTRNAND_MODE};
PadInfo padInfo = {.setKeyY = 1, .size_mb = 0, .size_b = info->entries[i].size_b, .mode = AES_CNT_CTRNAND_MODE};
memcpy(padInfo.ctr, info->entries[i].ctr, 16);
memcpy(padInfo.filename, info->entries[i].filename, 112);
Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
if (!padInfo.size_b) padInfo.size_b = info->entries[i].size_mb * 1024 * 1024;
Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_b / (1024*1024));

// workaround to still be able to process old ncchinfo.bin
if ((info->entries[i].ncchFlag7 == 0x01) && info->entries[i].ncchFlag3)
Expand Down
2 changes: 1 addition & 1 deletion source/decryptor/xorpad.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef struct {
u8 ctr[16];
u8 keyY[16];
u32 size_mb;
u8 reserved[4];
u32 size_b; // this is only used if it is non-zero
u32 ncchFlag7;
u32 ncchFlag3;
u64 titleId;
Expand Down
3 changes: 1 addition & 2 deletions source/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define FONT_WIDTH_EXT 8
#endif

#define RGB(r,g,b) (r<<24|b<<16|g<<8|r)
#define RGB(r,g,b) (b<<16|g<<8|r)

#define COLOR_BLACK RGB(0x00, 0x00, 0x00)
#define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF)
Expand Down Expand Up @@ -65,7 +65,6 @@
#define ScreenWidth(x) (((x) == (TOP_SCREEN) ? 400 : 320))
#define IsCharPartOfWord(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'Z'))


void ClearScreen(unsigned char *screen, int width, int color);
void ClearScreenFull(bool clear_top, bool clear_bottom);

Expand Down
6 changes: 3 additions & 3 deletions source/gamecart/secure_ntr.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void NTR_DecryptSecureArea (u32 aGameCode, u32* pCardHash, int nCardHash, u32* p
u32 NTR_GetIDSafe (u32 flags, const u8* command, u32 Delay)
{
u32 data = 0;
Delay = ((Delay & 0x3fff) * 1000) / 0x83;
Delay = 2* (((Delay & 0x3fff) * 1000) / 0x83);
ioDelay (Delay);
cardWriteCommand(command);
REG_NTRCARDROMCNT = flags | NTRCARD_BLK_SIZE(7);
Expand All @@ -201,7 +201,7 @@ u32 NTR_GetIDSafe (u32 flags, const u8* command, u32 Delay)

void NTR_CmdSecure (u32 flags, void* buffer, u32 length, u8* pcmd, u32 Delay)
{
Delay = ((Delay & 0x3fff) * 1000) / 0x83;
Delay = 2 * (((Delay & 0x3fff) * 1000) / 0x83);
ioDelay (Delay);
cardPolledTransfer (flags, buffer, length, pcmd);
}
Expand Down Expand Up @@ -311,7 +311,7 @@ bool NTR_Secure_Init (u8* header, u32 CartID, int iCardDevice)
}
else
{
Debug("Invalid secure area (%08X %08X)", secureArea[0], secureArea[1]);
//Debug("Invalid secure area (%08X %08X)", secureArea[0], secureArea[1]);
//dragon quest 5 has invalid secure area. really.
//return false;
}
Expand Down

0 comments on commit c389977

Please sign in to comment.