int elf_ProcessHeader(elf_context *elf) { const elf_hdr *hdr = (const elf_hdr*)elf->file; /* Check conditions for valid CTR ELF */ if (u8_to_u32(hdr->magic, BE) != ELF_MAGIC) return NOT_ELF_FILE; if (hdr->bitFormat != elf_32_bit) return NOT_CTR_ARM_ELF; if (hdr->endianness != elf_little_endian) return NOT_CTR_ARM_ELF; if (u8_to_u16(hdr->targetArchitecture, LE) != elf_arm) return NOT_CTR_ARM_ELF; if (u8_to_u16(hdr->type, LE) != elf_executeable) return NON_EXECUTABLE_ELF; elf->phdrOffset = u8_to_u32(hdr->programHeaderTableOffset, LE); elf->segmentNum = u8_to_u16(hdr->programHeaderEntryCount, LE); elf->segments = calloc(elf->segmentNum, sizeof(elf_segment)); if (!elf->segments) { fprintf(stderr, "[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } elf->shdrOffset = u8_to_u32(hdr->sectionHeaderTableOffset, LE); elf->shdrNameIndex = u8_to_u16(hdr->sectionHeaderNameEntryIndex, LE); elf->sectionNum = u8_to_u16(hdr->sectionHeaderEntryCount, LE); elf->sections = calloc(elf->sectionNum, sizeof(elf_section)); if (!elf->sections) { fprintf(stderr, "[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } return 0; }
static int check (const uint8_t *input, size_t input_length, const uint16_t *expected, size_t expected_length) { size_t length; uint16_t *result; /* Test return conventions with resultbuf == NULL. */ result = u8_to_u16 (input, input_length, NULL, &length); if (!(result != NULL)) return 1; if (!(length == expected_length)) return 2; if (!(u16_cmp (result, expected, expected_length) == 0)) return 3; free (result); /* Test return conventions with resultbuf too small. */ if (expected_length > 0) { uint16_t *preallocated; length = expected_length - 1; preallocated = (uint16_t *) malloc (length * sizeof (uint16_t)); result = u8_to_u16 (input, input_length, preallocated, &length); if (!(result != NULL)) return 4; if (!(result != preallocated)) return 5; if (!(length == expected_length)) return 6; if (!(u16_cmp (result, expected, expected_length) == 0)) return 7; free (result); free (preallocated); } /* Test return conventions with resultbuf large enough. */ { uint16_t *preallocated; length = expected_length; preallocated = (uint16_t *) malloc (length * sizeof (uint16_t)); result = u8_to_u16 (input, input_length, preallocated, &length); if (!(result != NULL)) return 8; if (!(preallocated == NULL || result == preallocated)) return 9; if (!(length == expected_length)) return 10; if (!(u16_cmp (result, expected, expected_length) == 0)) return 11; free (preallocated); } return 0; }
void GetCUPVersion(/*char *FW_STRING, */CARD_INFO_HEADER *card_info) { u8 MAJOR = 0; u8 MINOR = 0; u8 BUILD = 0; char REGION_CHAR = ' '; u16 CVer_ver = u8_to_u16(card_info->cver_title_version,LE); u32 CVer_UID = u8_to_u32(card_info->cver_title_id,LE); switch(CVer_UID){ case EUR_UPDATE : REGION_CHAR = 'E'; break; case JPN_UPDATE : REGION_CHAR = 'J'; break; case USA_UPDATE : REGION_CHAR = 'U'; break; case CHN_UPDATE : REGION_CHAR = 'C'; break; case KOR_UPDATE : REGION_CHAR = 'K'; break; case TWN_UPDATE : REGION_CHAR = 'T'; break; } switch(CVer_ver){ case 3088 : MAJOR = 3; MINOR = 0; BUILD = 0; break; default ://This tends to work most of the time, use above for manual overrides MAJOR = (CVer_ver & 0x7f00) >> 10; MINOR = (CVer_ver & 0x3f0) >> 4; //BUILD = CVer_ver & 0xf; break; } printf(" CUP Version: %d.%d.%d%c\n",MAJOR,MINOR,BUILD,REGION_CHAR); }
void GetMin3DSFW(char *FW_STRING, CARD_INFO_HEADER *card_info) { u8 MAJOR = 0; u8 MINOR = 0; u8 BUILD = 0; char REGION_CHAR = 'X'; u16 CVer_ver = u8_to_u16(card_info->cver_title_version,LE); u32 CVer_UID = u8_to_u32(card_info->cver_title_id,LE); switch(CVer_UID){ case EUR_ROM : REGION_CHAR = 'E'; break; case JPN_ROM : REGION_CHAR = 'J'; break; case USA_ROM : REGION_CHAR = 'U'; break; case CHN_ROM : REGION_CHAR = 'C'; break; case KOR_ROM : REGION_CHAR = 'K'; break; case TWN_ROM : REGION_CHAR = 'T'; break; } switch(CVer_ver){ case 3088 : MAJOR = 3; MINOR = 0; BUILD = 0; break; default : MAJOR = CVer_ver/1024; MINOR = (CVer_ver - 1024*(CVer_ver/1024))/0x10; break;//This tends to work 98% of the time, use above for manual overides } sprintf(FW_STRING,"%d.%d.%d-X%c",MAJOR,MINOR,BUILD,REGION_CHAR); }
void PrintNCSDHeaderData(NCSD_STRUCT *ctx, NCSD_HEADER *header, CARD_INFO_HEADER *card_info, DEV_CARD_INFO_HEADER *dev_card_info) { printf("[+] CCI Image Details\n"); u8 CardDevice = header->partition_flags[MEDIA_CARD_DEVICE_OLD] + header->partition_flags[MEDIA_CARD_DEVICE]; switch (header->partition_flags[MEDIA_TYPE_INDEX]){ case INNER_DEVICE: printf(" Media Type: INTERNAL_DEVICE\n"); break; case CARD1: printf(" Media Type: CARD1\n"); break; case CARD2: printf(" Media Type: CARD2\n > Writable Region:\n - Offset: 0x%llx\n - Size: 0x%llx (%lld MB)\n",ctx->WRITABLE_ADDRESS,ctx->CARD2_MAX_SAVEDATA_SIZE,(ctx->CARD2_MAX_SAVEDATA_SIZE/MB)); break; case EXTENDED_DEVICE: printf(" Media Type: EXTENDED_DEVICE\n"); break; } GetCHIPFullSize(ctx->MEDIA_SIZE,ctx->type); GetCCIDataSize(ctx->CCI_IMAGE_SIZE,ctx->type); GetCCIFileStatus(ctx->CCI_FILE_SIZE,ctx->CCI_FILE_STATUS,ctx->type); switch (CardDevice){ case CARD_DEVICE_NOR_FLASH: printf(" Additional Device: EEPROM\n"); break; case CARD_DEVICE_NONE: printf(" Additional Device: None\n"); break; case CARD_DEVICE_BT: printf(" Additional Device: BT\n"); break; } printf(" Partition Count: %d\n",ctx->partition_count); if(u8_to_u64(card_info->cver_title_id,LE) && u8_to_u16(card_info->cver_title_version,LE)){ //printf("CVer Title ID: %016llx\n",u8_to_u64(card_info->cver_title_id,LE)); //printf("CVer Title Ver: v%d\n",u8_to_u16(card_info->cver_title_version,LE)); GetCUPVersion(card_info); } if(!header->partition_flags[MEDIA_6X_SAVE_CRYPTO] && !header->partition_flags[MEDIA_CARD_DEVICE] && !header->partition_flags[MEDIA_CARD_DEVICE_OLD]){ printf(" Save Crypto: Repeating CTR Fail\n"); } else if(!header->partition_flags[MEDIA_6X_SAVE_CRYPTO] && (header->partition_flags[MEDIA_CARD_DEVICE] || header->partition_flags[MEDIA_CARD_DEVICE_OLD])){ printf(" Save Crypto: 2.2.0 KeyY Method\n"); } else if(header->partition_flags[MEDIA_6X_SAVE_CRYPTO] == 1 && !header->partition_flags[MEDIA_CARD_DEVICE_OLD]){ if(!header->partition_flags[MEDIA_CARD_DEVICE]){ printf(" Save Crypto: 2.2.0 KeyY Method\n"); } else if(header->partition_flags[MEDIA_CARD_DEVICE]){ printf(" Save Crypto: 6.0.0 KeyY Method\n"); } } printf("[+] CXI Partition\n"); printf(" Product Code: %.16s\n",card_info->partition_0_header.product_code); printf(" Company Code: %.2s\n",card_info->partition_0_header.maker_code); u32 UniqueID = u8_to_u32(&card_info->partition_0_header.program_id[1],LE)&0xffffff; printf(" Unique ID: %05x\n",UniqueID); printf(" Build Type: %s\n",ctx->BUILD_TYPE? "Debug or Development" : "Release"); printf(" SDK Version: %d.%d.%d %s\n",ctx->SDK_VER[0],ctx->SDK_VER[1],ctx->SDK_VER[2],ctx->SDK_PATCH); if(ctx->FW_VER[0] || ctx->FW_VER[1]) printf(" Req. Kernel Version: %d.%d-%d\n",ctx->FW_VER[0],ctx->FW_VER[1],ctx->FW_VER[2]); printf("[+] CFA Partitions\n"); for(int i = 1; i < 8; i++){ if(i == 1) printf(" E-Manual: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else if(i == 2) printf(" DLP Child: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else if(i == 7) printf(" Update Data: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else{ if(ctx->partition_data[i].active) printf(" CFA %d: %s\n",i,ctx->partition_data[i].active? "Yes" : "No"); } } }
int GetNcchInfo(ncch_info *info, ncch_hdr *hdr) { clrmem(info, sizeof(ncch_info)); info->titleId = u8_to_u64(hdr->titleId,LE); info->programId = u8_to_u64(hdr->programId,LE); u32 block_size = GetNcchBlockSize(hdr); info->formatVersion = u8_to_u16(hdr->formatVersion,LE); if(!IsCfa(hdr)){ info->exhdrOffset = sizeof(ncch_hdr); info->exhdrSize = u8_to_u32(hdr->exhdrSize,LE); info->acexOffset = (info->exhdrOffset + info->exhdrSize); info->acexSize = sizeof(access_descriptor); info->plainRegionOffset = (u64)(u8_to_u32(hdr->plainRegionOffset,LE)*block_size); info->plainRegionSize = (u64)(u8_to_u32(hdr->plainRegionSize,LE)*block_size); } info->logoOffset = (u64)(u8_to_u32(hdr->logoOffset,LE)*block_size); info->logoSize = (u64)(u8_to_u32(hdr->logoSize,LE)*block_size); info->exefsOffset = (u64)(u8_to_u32(hdr->exefsOffset,LE)*block_size); info->exefsSize = (u64)(u8_to_u32(hdr->exefsSize,LE)*block_size); info->exefsHashDataSize = (u64)(u8_to_u32(hdr->exefsHashSize,LE)*block_size); info->romfsOffset = (u64) (u8_to_u32(hdr->romfsOffset,LE)*block_size); info->romfsSize = (u64) (u8_to_u32(hdr->romfsSize,LE)*block_size); info->romfsHashDataSize = (u64)(u8_to_u32(hdr->romfsHashSize,LE)*block_size); return 0; }
int main () { /* Empty string. */ ASSERT (check (NULL, 0, NULL, 0) == 0); /* Simple string. */ { /* "Grüß Gott. Здравствуйте! x=(-b±sqrt(b²-4ac))/(2a) 日本語,中文,한글" */ static const uint8_t input[] = { 'G', 'r', 0xC3, 0xBC, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.', ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1, 0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB9, 0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1, 's', 'q', 'r', 't', '(', 'b', 0xC2, 0xB2, '-', '4', 'a', 'c', ')', ')', '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',', 0xED, 0x95, 0x9C, 0xEA, 0xB8, 0x80, '\n' }; static const uint16_t expected[] = { 'G', 'r', 0x00FC, 0x00DF, ' ', 'G', 'o', 't', 't', '.', ' ', 0x0417, 0x0434, 0x0440, 0x0430, 0x0432, 0x0441, 0x0442, 0x0432, 0x0443, 0x0439, 0x0442, 0x0435, '!', ' ', 'x', '=', '(', '-', 'b', 0x00B1, 's', 'q', 'r', 't', '(', 'b', 0x00B2, '-', '4', 'a', 'c', ')', ')', '/', '(', '2', 'a', ')', ' ', ' ', 0x65E5, 0x672C, 0x8A9E, ',', 0x4E2D, 0x6587, ',', 0xD55C, 0xAE00, '\n' }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); } /* String with characters outside the BMP. */ { static const uint8_t input[] = { '-', '(', 0xF0, 0x9D, 0x94, 0x9E, 0xC3, 0x97, 0xF0, 0x9D, 0x94, 0x9F, ')', '=', 0xF0, 0x9D, 0x94, 0x9F, 0xC3, 0x97, 0xF0, 0x9D, 0x94, 0x9E }; static const uint16_t expected[] = { '-', '(', 0xD835, 0xDD1E, 0x00D7, 0xD835, 0xDD1F, ')', '=', 0xD835, 0xDD1F, 0x00D7, 0xD835, 0xDD1E }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); } /* Invalid input. */ { static const uint8_t input[] = { 'x', 0xC2, 0xC3, 'y' }; #if 0 /* Currently invalid input is rejected, not accommodated. */ static const uint16_t expected[] = { 'x', 0xFFFD, 0xFFFD, 'y' }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); #else size_t length; uint16_t *result; uint16_t preallocated[10]; /* Test return conventions with resultbuf == NULL. */ result = u8_to_u16 (input, SIZEOF (input), NULL, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); /* Test return conventions with resultbuf too small. */ length = 1; result = u8_to_u16 (input, SIZEOF (input), preallocated, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); /* Test return conventions with resultbuf large enough. */ length = SIZEOF (preallocated); result = u8_to_u16 (input, SIZEOF (input), preallocated, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); #endif } return 0; }
static inline u16 dispatch_t204(t204 a205, u8 a206) { return u8_to_u16(a206); }
void PrintNCSDData(NCSD_STRUCT *ctx, NCSD_HEADER *header, CARD_INFO_HEADER *card_info, DEV_CARD_INFO_HEADER *dev_card_info) { if(ctx->valid != True){ printf("[!] NCSD Corrupt\n"); return; } printf("[+] NCSD\n"); switch(ctx->sig_valid){ case Good : memdump(stdout,"Signature(Good): ",ctx->signature,0x100); break; case Fail : memdump(stdout,"Signature(Fail): ",ctx->signature,0x100); break; case NotChecked: memdump(stdout,"Signature: ",ctx->signature,0x100); break; } switch(ctx->type){ case retail : printf("Target: Retail/Production\n"); printf("CVer Title ID: %016llx\n",u8_to_u64(card_info->cver_title_id,LE)); printf("CVer Title Ver: v%d\n",u8_to_u16(card_info->cver_title_version,LE)); char *FW_STRING = malloc(10); memset(FW_STRING,0,10); GetMin3DSFW(FW_STRING,card_info); printf("Min 3DS Firm: %s\n",FW_STRING); _free(FW_STRING); break; case dev_internal_SDK : printf("Target: Debug/Development\n"); printf("SDK Type: Nintendo Internal SDK\n"); memdump(stdout,"Title Key: ",dev_card_info->TitleKey,0x10); break; case dev_external_SDK : printf("Target: Debug/Development\n"); printf("SDK Type: Nintendo 3RD Party SDK\n"); memdump(stdout,"Title Key: ",dev_card_info->TitleKey,0x10); break; } if(ctx->rom_size >= GB){ printf("ROM Cart Size: %lld GB",ctx->rom_size/GB); printf(" (%lld Gbit)\n",(ctx->rom_size/GB)*8); } else{ printf("ROM Cart Size: %lld MB",ctx->rom_size/MB); u32 tmp = (ctx->rom_size/MB)*8; if(tmp >= 1024) printf(" (%d Gbit)\n",tmp/1024); else printf(" (%d Mbit)\n",tmp); } if(ctx->used_rom_size >= MB){ printf("ROM Used Size: %lld MB",ctx->used_rom_size/MB); printf(" (0x%llx bytes)\n",ctx->used_rom_size); } else if(ctx->used_rom_size >= KB){ printf("ROM Used Size: %lld KB",ctx->used_rom_size/KB); printf(" (0x%llx bytes)\n",ctx->used_rom_size); } printf("NCSD Title ID: %016llx\n",u8_to_u64(header->title_id,LE)); memdump(stdout,"ExHeader Hash: ",header->exheader_hash,0x20); printf("AddHeader Size: 0x%x\n",u8_to_u32(header->additional_header_size,LE)); printf("Sector 0 Offset: 0x%x\n",u8_to_u32(header->sector_zero_offset,LE)); memdump(stdout,"Flags: ",header->partition_flags,8); printf("\n"); for(int i = 0; i < 8; i++){ if(ctx->partition_data[i].active == True){ printf("Partition %d\n",i); printf(" Title ID: %016llx\n",ctx->partition_data[i].title_id); printf(" Content Type: "); switch(ctx->partition_data[i].content_type){ case _unknown : printf("Unknown\n"); break; case CXI : printf("Application\n"); break; case CFA_Manual : printf("Electronic Manual\n"); break; case CFA_DLPChild : printf("Download Play Child\n"); break; case CFA_Update : printf("Software Update Partition\n"); break; } printf(" FS Type: %x\n",ctx->partition_data[i].fs_type); printf(" Crypto Type: %x\n",ctx->partition_data[i].crypto_type); printf(" Offset: 0x%x\n",ctx->partition_data[i].offset); printf(" Size: 0x%x\n",ctx->partition_data[i].size); printf("\n"); } } }