From f8993e198a8439ad3e6883414cc3c7cfb5cdd9d0 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 14 Sep 2015 21:52:04 +0800 Subject: [PATCH] ctrtool: Updated exheader validation and ncch spec/flag recognition --- ctrtool/ctrtool.vcxproj | 6 +- ctrtool/exheader.c | 211 ++++++++++++++++++++++------------------ ctrtool/exheader.h | 44 ++++++++- ctrtool/ncch.c | 21 ++-- ctrtool/ncch.h | 2 +- 5 files changed, 171 insertions(+), 113 deletions(-) diff --git a/ctrtool/ctrtool.vcxproj b/ctrtool/ctrtool.vcxproj index 75b7288..628d52f 100644 --- a/ctrtool/ctrtool.vcxproj +++ b/ctrtool/ctrtool.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -18,13 +18,13 @@ Application - v110 + v140 Unicode true Application - v110 + v140 Unicode diff --git a/ctrtool/exheader.c b/ctrtool/exheader.c index 6f064d9..92db1a6 100644 --- a/ctrtool/exheader.c +++ b/ctrtool/exheader.c @@ -126,6 +126,58 @@ int exheader_programid_valid(exheader_context* ctx) return 1; } +void exheader_deserialise_arm11localcaps_permissions(exheader_arm11systemlocalcaps_deserialised *caps, const exheader_arm11systemlocalcaps *arm11) +{ + int i; + + memset(caps, 0, sizeof(exheader_arm11systemlocalcaps_deserialised)); + + memcpy(caps->program_id, arm11->programid, 8); + caps->core_version = getle32(arm11->coreversion); + + caps->enable_l2_cache = (arm11->flag[0] >> 0) & 1; + caps->use_additional_cores = (arm11->flag[0] >> 1) & 1; + caps->new3ds_systemmode = (arm11->flag[1] >> 0) & 15; + + caps->ideal_processor = (arm11->flag[2] >> 0) & 3; + caps->affinity_mask = (arm11->flag[2] >> 2) & 3; + caps->old3ds_systemmode = (arm11->flag[2] >> 4) & 15; + + caps->priority = (s8)arm11->flag[3]; + + // storage info + if (arm11->storageinfo.otherattributes & 2) { + caps->extdata_id = 0; + for (i = 0; i < 3; i++) + caps->other_user_saveid[i] = 0; + caps->use_other_variation_savedata = 0; + + for (i = 0; i < 3; i++) + caps->accessible_saveid[i] = 0xfffff & (getle64(arm11->storageinfo.accessibleuniqueids) >> 20 * (2 - i)); + for (i = 0; i < 3; i++) + caps->accessible_saveid[i+3] = 0xfffff & (getle64(arm11->storageinfo.extsavedataid) >> 20 * (2 - i)); + } + else { + caps->extdata_id = getle64(arm11->storageinfo.extsavedataid); + for (i = 0; i < 3; i++) + caps->other_user_saveid[i] = 0xfffff & (getle64(arm11->storageinfo.accessibleuniqueids) >> 20 * (2 - i)); + caps->use_other_variation_savedata = (getle64(arm11->storageinfo.accessibleuniqueids) >> 60) & 1; + + for (i = 0; i < 6; i++) + caps->accessible_saveid[i] = 0; + } + + caps->system_saveid[0] = getle32(arm11->storageinfo.systemsavedataid); + caps->system_saveid[1] = getle32(arm11->storageinfo.systemsavedataid + 4); + caps->accessinfo = getle64(arm11->storageinfo.accessinfo) & ~((u64)0xff00000000000000); + + // Service Access Control + for (i = 0; i < 34; i++) + strncpy(caps->service_access_control[i], (char*)arm11->serviceaccesscontrol[i], 8); + + caps->resource_limit_category = arm11->resourcelimitcategory; +} + int exheader_process(exheader_context* ctx, u32 actions) { exheader_determine_key(ctx, actions); @@ -135,13 +187,13 @@ int exheader_process(exheader_context* ctx, u32 actions) if (ctx->header.codesetinfo.flags.flag & 1) ctx->compressedflag = 1; + exheader_deserialise_arm11localcaps_permissions(&ctx->system_local_caps, &ctx->header.arm11systemlocalcaps); + if (actions & VerifyFlag) exheader_verify(ctx); if (actions & InfoFlag) - { - exheader_print(ctx); - } + exheader_print(ctx); return 1; } @@ -397,11 +449,10 @@ void exheader_print_arm11accessinfo(exheader_context* ctx) { char str[100]; u64 i, bit; - u64 accessinfo = 0xffffffffffffff & getle64(ctx->header.arm11systemlocalcaps.storageinfo.accessinfo); for(i = 0; i < 56; i++) { bit = ((u64)1 << i); - if((accessinfo & bit) == bit) + if((ctx->system_local_caps.accessinfo & bit) == bit) fprintf(stdout, " > %s\n",exheader_print_accessinfobit((u32)i,str)); } } @@ -410,72 +461,21 @@ void exheader_print_arm11storageinfo(exheader_context* ctx) { u32 i; - // Storage Info - u32 systemsaveID[2]; - u64 extdataID; - u32 otherusersaveID[3]; - u32 accessiblesaveID[6]; - - u8 otherattibutes = ctx->header.arm11systemlocalcaps.storageinfo.otherattributes; - u8 accessOtherVariationSavedata = (getle64(ctx->header.arm11systemlocalcaps.storageinfo.accessibleuniqueids) & 0x1000000000000000) == 0x1000000000000000; - - systemsaveID[0] = getle32(ctx->header.arm11systemlocalcaps.storageinfo.systemsavedataid); - systemsaveID[1] = getle32(ctx->header.arm11systemlocalcaps.storageinfo.systemsavedataid+4); - - extdataID = getle64(ctx->header.arm11systemlocalcaps.storageinfo.extsavedataid); - - for(i = 0; i < 3; i++) - { - accessiblesaveID[i] = 0xfffff & (getle64(ctx->header.arm11systemlocalcaps.storageinfo.accessibleuniqueids) >> 20*(2-i)); - otherusersaveID[i] = 0xfffff & (getle64(ctx->header.arm11systemlocalcaps.storageinfo.accessibleuniqueids) >> 20*(2-i)); - } - - for(i = 0; i < 3; i++) - { - accessiblesaveID[i+3] = 0xfffff & (getle64(ctx->header.arm11systemlocalcaps.storageinfo.extsavedataid) >> 20*(2-i)); - } - - if(otherattibutes & 2) - { - extdataID = 0; - for(i = 0; i < 3; i++) - otherusersaveID[i] = 0; - } - else - { - for(i = 0; i < 6; i++) - accessiblesaveID[i] = 0; - } - - fprintf(stdout, "Ext savedata id: 0x%08"PRIx64"\n",extdataID); + fprintf(stdout, "Ext savedata id: 0x%"PRIx64"\n",ctx->system_local_caps.extdata_id); for(i = 0; i < 2; i++) - fprintf(stdout, "System savedata id %d: 0x%08x %s\n",i+1,systemsaveID[i],exheader_getvalidstring(ctx->validsystemsaveID[i])); + fprintf(stdout, "System savedata id %d: 0x%x %s\n",i+1, ctx->system_local_caps.system_saveid[i],exheader_getvalidstring(ctx->validsystemsaveID[i])); for(i = 0; i < 3; i++) - fprintf(stdout, "OtherUserSaveDataId%d: 0x%05x\n",i+1,otherusersaveID[i]); + fprintf(stdout, "OtherUserSaveDataId%d: 0x%x\n",i+1, ctx->system_local_caps.other_user_saveid[i]); fprintf(stdout, "Accessible Savedata Ids:\n"); for(i = 0; i < 6; i++) { - if(accessiblesaveID[i] != 0x00000) - fprintf(stdout, " > 0x%05x\n",accessiblesaveID[i]); + if(ctx->system_local_caps.accessible_saveid[i] != 0x00000) + fprintf(stdout, " > 0x%05x\n", ctx->system_local_caps.accessible_saveid[i]); } - fprintf(stdout, "Other Variation Saves: %s\n", accessOtherVariationSavedata ? "Accessible" : "Inaccessible"); - if(ctx->validaccessinfo == Unchecked) - memdump(stdout, "Access info: ", ctx->header.arm11systemlocalcaps.storageinfo.accessinfo, 7); - else if(ctx->validaccessinfo == Good) - memdump(stdout, "Access info (GOOD): ", ctx->header.arm11systemlocalcaps.storageinfo.accessinfo, 7); - else - memdump(stdout, "Access info (FAIL): ", ctx->header.arm11systemlocalcaps.storageinfo.accessinfo, 7); - exheader_print_arm11accessinfo(ctx); - - fprintf(stdout, "Other attributes: %02X", ctx->header.arm11systemlocalcaps.storageinfo.otherattributes); - /* - if(otherattibutes & 1) - fprintf(stdout," [no use romfs]"); - if(otherattibutes & 2) - fprintf(stdout," [use extended savedata access control]"); - */ - printf("\n"); + fprintf(stdout, "Other Variation Saves: %s\n", ctx->system_local_caps.use_other_variation_savedata ? "Accessible" : "Inaccessible"); + fprintf(stdout, "Access info: 0x%"PRIx64" %s\n", ctx->system_local_caps.accessinfo,exheader_getvalidstring(ctx->validaccessinfo)); + exheader_print_arm11accessinfo(ctx); } int exheader_signature_verify(exheader_context* ctx, rsakey2048* key) @@ -486,61 +486,78 @@ int exheader_signature_verify(exheader_context* ctx, rsakey2048* key) return ctr_rsa_verify_hash(ctx->header.accessdesc.signature, hash, key); } - void exheader_verify(exheader_context* ctx) { - unsigned int i; - u8 exheaderflag6[3]; - u8 descflag6[3]; + unsigned int i, j; + exheader_arm11systemlocalcaps_deserialised accessdesc; + + exheader_deserialise_arm11localcaps_permissions(&accessdesc, &ctx->header.accessdesc.arm11systemlocalcaps); ctx->validsystemsaveID[0] = Good; ctx->validsystemsaveID[1] = Good; ctx->validaccessinfo = Good; + ctx->validcoreversion = Good; ctx->validprogramid = Good; ctx->validpriority = Good; ctx->validaffinitymask = Good; ctx->valididealprocessor = Good; + ctx->validold3dssystemmode = Good; + ctx->validnew3dssystemmode = Good; + ctx->validenablel2cache = Good; + ctx->validuseadditionalcores = Good; + ctx->validservicecontrol = Good; for(i=0; i<8; i++) { - if (0 == (ctx->header.arm11systemlocalcaps.programid[i] & ~ctx->header.accessdesc.arm11systemlocalcaps.programid[i])) + if (ctx->system_local_caps.program_id[i] == accessdesc.program_id[i] || accessdesc.program_id[i] == 0xFF) continue; ctx->validprogramid = Fail; break; } - // Ideal Proccessor - exheaderflag6[0] = (ctx->header.arm11systemlocalcaps.flag>>0)&0x3; - descflag6[0] = (ctx->header.accessdesc.arm11systemlocalcaps.flag>>0)&0x3; - // Affinity Mask - exheaderflag6[1] = (ctx->header.arm11systemlocalcaps.flag>>2)&0x3; - descflag6[1] = (ctx->header.accessdesc.arm11systemlocalcaps.flag>>2)&0x3; - // System Mode - //exheaderflag6[2] = (ctx->header.arm11systemlocalcaps.flag>>4)&0xf; - //descflag6[2] = (ctx->header.accessdesc.arm11systemlocalcaps.flag>>4)&0xf; + if (ctx->system_local_caps.core_version != accessdesc.core_version) + ctx->validcoreversion = Fail; - if (ctx->header.accessdesc.arm11systemlocalcaps.priority > ctx->header.arm11systemlocalcaps.priority || ctx->header.arm11systemlocalcaps.priority > 127) + if (ctx->system_local_caps.priority < accessdesc.priority) ctx->validpriority = Fail; - if((1<system_local_caps.ideal_processor & accessdesc.ideal_processor) == 0) ctx->valididealprocessor = Fail; - if (exheaderflag6[1] & ~descflag6[1]) + if (ctx->system_local_caps.affinity_mask & ~accessdesc.affinity_mask) ctx->validaffinitymask = Fail; + if (ctx->system_local_caps.old3ds_systemmode > accessdesc.old3ds_systemmode) + ctx->validold3dssystemmode = Fail; + + if (ctx->system_local_caps.new3ds_systemmode > accessdesc.new3ds_systemmode) + ctx->validnew3dssystemmode = Fail; + // Storage Info Verify - if(0 != (getle32(ctx->header.arm11systemlocalcaps.storageinfo.systemsavedataid) & ~getle32(ctx->header.accessdesc.arm11systemlocalcaps.storageinfo.systemsavedataid))) + if(ctx->system_local_caps.system_saveid[0] & ~accessdesc.system_saveid[0]) ctx->validsystemsaveID[0] = Fail; - if(0 != (getle32(ctx->header.arm11systemlocalcaps.storageinfo.systemsavedataid+4) & ~getle32(ctx->header.accessdesc.arm11systemlocalcaps.storageinfo.systemsavedataid+4))) + if(ctx->system_local_caps.system_saveid[1] & ~accessdesc.system_saveid[1]) ctx->validsystemsaveID[1] = Fail; - for(i=0; i<7; i++) - { - if(0 == (ctx->header.arm11systemlocalcaps.storageinfo.accessinfo[i] & ~ctx->header.accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[i])) - continue; + + if (ctx->system_local_caps.accessinfo & ~accessdesc.accessinfo) ctx->validaccessinfo = Fail; - break; + + // Service Access Control + for (i = 0; i < 34; i++) { + if (strlen(ctx->system_local_caps.service_access_control[i]) == 0) + continue; + + for (j = 0; j < 34; j++) { + if (strcmp(ctx->system_local_caps.service_access_control[i], accessdesc.service_access_control[j]) == 0) + break; + } + + if (strcmp(ctx->system_local_caps.service_access_control[i], accessdesc.service_access_control[j]) == 0) + continue; + + ctx->validservicecontrol = Fail; } if (ctx->usersettings) @@ -609,21 +626,21 @@ void exheader_print(exheader_context* ctx) fprintf(stdout, "Program id: %016"PRIx64" %s\n", getle64(ctx->header.arm11systemlocalcaps.programid), exheader_getvalidstring(ctx->validprogramid)); fprintf(stdout, "Core version: 0x%X\n", getle32(ctx->header.arm11systemlocalcaps.coreversion)); - fprintf(stdout, "System mode: 0x%X\n", (ctx->header.arm11systemlocalcaps.flag>>4)&0xF); - fprintf(stdout, "Ideal processor: %d %s\n", (ctx->header.arm11systemlocalcaps.flag>>0)&0x3, exheader_getvalidstring(ctx->valididealprocessor)); - fprintf(stdout, "Affinity mask: %d %s\n", (ctx->header.arm11systemlocalcaps.flag>>2)&0x3, exheader_getvalidstring(ctx->validaffinitymask)); - fprintf(stdout, "Main thread priority: %d %s\n", ctx->header.arm11systemlocalcaps.priority, exheader_getvalidstring(ctx->validpriority)); + fprintf(stdout, "System mode: %d %s\n", ctx->system_local_caps.old3ds_systemmode, exheader_getvalidstring(ctx->validold3dssystemmode)); + fprintf(stdout, "System mode (New3DS): %d %s\n", ctx->system_local_caps.new3ds_systemmode, exheader_getvalidstring(ctx->validnew3dssystemmode)); + fprintf(stdout, "Ideal processor: %d %s\n", ctx->system_local_caps.ideal_processor, exheader_getvalidstring(ctx->valididealprocessor)); + fprintf(stdout, "Affinity mask: %d %s\n", ctx->system_local_caps.affinity_mask, exheader_getvalidstring(ctx->validaffinitymask)); + fprintf(stdout, "Main thread priority: %d %s\n", ctx->system_local_caps.priority, exheader_getvalidstring(ctx->validpriority)); // print resource limit descriptor too? currently mostly zeroes... exheader_print_arm11storageinfo(ctx); exheader_print_arm11kernelcapabilities(ctx); exheader_print_arm9accesscontrol(ctx); - - - for(i=0; i<0x20; i++) + fprintf(stdout, "Service access: %s\n", exheader_getvalidstring(ctx->validservicecontrol)); + for(i=0; i<34; i++) { - if (getle64(ctx->header.arm11systemlocalcaps.serviceaccesscontrol[i]) != 0x0000000000000000UL) - fprintf(stdout, "Service access: %.8s\n", ctx->header.arm11systemlocalcaps.serviceaccesscontrol[i]); + if (strlen(ctx->system_local_caps.service_access_control[i]) > 0) + fprintf(stdout, " > %s\n", ctx->system_local_caps.service_access_control[i]); } fprintf(stdout, "Reslimit category: %02X\n", ctx->header.arm11systemlocalcaps.resourcelimitcategory); } diff --git a/ctrtool/exheader.h b/ctrtool/exheader.h index 436a8d7..a4432c2 100644 --- a/ctrtool/exheader.h +++ b/ctrtool/exheader.h @@ -57,16 +57,41 @@ typedef struct { u8 programid[8]; u8 coreversion[4]; - u8 reserved0[2]; - u8 flag; - u8 priority; + u8 flag[4]; u8 resourcelimitdescriptor[0x10][2]; exheader_storageinfo storageinfo; - u8 serviceaccesscontrol[0x20][8]; - u8 reserved[0x1f]; + u8 serviceaccesscontrol[34][8]; + u8 reserved[0xf]; u8 resourcelimitcategory; } exheader_arm11systemlocalcaps; +typedef struct +{ + u8 program_id[8]; + u32 core_version; + + // flag + u8 enable_l2_cache; + u8 use_additional_cores; + u8 new3ds_systemmode; + u8 ideal_processor; + u8 affinity_mask; + u8 old3ds_systemmode; + s8 priority; + + // storageinfo + u64 extdata_id; + u32 other_user_saveid[3]; + u8 use_other_variation_savedata; + u32 accessible_saveid[3]; + u32 system_saveid[2]; + u64 accessinfo; + + + char service_access_control[34][10]; + u8 resource_limit_category; +} exheader_arm11systemlocalcaps_deserialised; + typedef struct { u8 descriptors[28][4]; @@ -115,6 +140,9 @@ typedef struct u32 offset; u32 size; exheader_header header; + + exheader_arm11systemlocalcaps_deserialised system_local_caps; + ctr_aes_context aes; ctr_rsa_context rsa; int compressedflag; @@ -123,8 +151,14 @@ typedef struct int validpriority; int validaffinitymask; int valididealprocessor; + int validold3dssystemmode; + int validnew3dssystemmode; + int validenablel2cache; + int validuseadditionalcores; + int validcoreversion; int validsystemsaveID[2]; int validaccessinfo; + int validservicecontrol; int validsignature; } exheader_context; diff --git a/ctrtool/ncch.c b/ctrtool/ncch.c index 4a781be..07f8755 100644 --- a/ctrtool/ncch.c +++ b/ctrtool/ncch.c @@ -540,6 +540,17 @@ static const char* contenttypetostring(unsigned char flags) case 2: return "Manual"; case 3: return "Child"; case 4: return "Trial"; + case 5: return "Extended System Update"; + default: return "Unknown"; + } +} + +static const char* contentplatformtostring(unsigned char platform) +{ + switch (platform) + { + case 1: return "CTR"; + case 2: return "SNAKE"; default: return "Unknown"; } } @@ -566,6 +577,7 @@ void ncch_print(ncch_context* ctx) fprintf(stdout, "Partition id: %016"PRIx64"\n", getle64(header->partitionid)); fprintf(stdout, "Maker code: %04x\n", getle16(header->makercode)); fprintf(stdout, "Version: %04x\n", getle16(header->version)); + fprintf(stdout, "Title seed check: %08x\n", getle32(header->seedcheck)); fprintf(stdout, "Program id: %016"PRIx64"\n", getle64(header->programid)); if(ctx->logohashcheck == Unchecked) memdump(stdout, "Logo hash: ", header->logohash, 0x20); @@ -587,16 +599,11 @@ void ncch_print(ncch_context* ctx) fprintf(stdout, " > Crypto key: None\n"); else if (header->flags[7] & 1) fprintf(stdout, " > Crypto key: %s\n", programid_is_system(header->programid)? "Fixed":"Zeros"); - else if (header->flags[3] & 1) - fprintf(stdout, " > Crypto key: Secure2\n"); - else if (header->flags[3] & 10) - fprintf(stdout, " > Crypto key: secure3 (New 3DS)\n"); else - fprintf(stdout, " > Crypto key: Secure\n"); + fprintf(stdout, " > Crypto key: Secure (%d)%s\n", header->flags[3], header->flags[7] & 32? " (KeyY seeded)" : ""); fprintf(stdout, " > Form type: %s\n", formtypetostring(header->flags[5])); fprintf(stdout, " > Content type: %s\n", contenttypetostring(header->flags[5])); - if (header->flags[4] & 1) - fprintf(stdout, " > Content platform: CTR\n"); + fprintf(stdout, " > Content platform: %s\n", contentplatformtostring(header->flags[4])); if (header->flags[7] & 2) fprintf(stdout, " > No RomFS mount\n"); diff --git a/ctrtool/ncch.h b/ctrtool/ncch.h index b6539e0..f453bb5 100644 --- a/ctrtool/ncch.h +++ b/ctrtool/ncch.h @@ -26,7 +26,7 @@ typedef struct u8 partitionid[8]; u8 makercode[2]; u8 version[2]; - u8 reserved0[4]; + u8 seedcheck[4]; u8 programid[8]; u8 reserved1[0x10]; u8 logohash[0x20];