Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ctrtool: Updated exheader validation and ncch spec/flag recognition #1

Merged
merged 6 commits into from
Sep 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ctrtool/ctrtool.vcxproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
Expand All @@ -18,13 +18,13 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
Expand Down
213 changes: 115 additions & 98 deletions ctrtool/exheader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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));
}
}
Expand All @@ -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)
Expand All @@ -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->header.accessdesc.arm11systemlocalcaps.priority > ctx->header.arm11systemlocalcaps.priority || ctx->header.arm11systemlocalcaps.priority > 127)
if (ctx->system_local_caps.core_version != accessdesc.core_version)
ctx->validcoreversion = Fail;

if (ctx->system_local_caps.priority < accessdesc.priority)
ctx->validpriority = Fail;

if((1<<exheaderflag6[0] & descflag6[0]) == 0)
if((1<<ctx->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)
Expand Down Expand Up @@ -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);
}
44 changes: 39 additions & 5 deletions ctrtool/exheader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down
Loading