Beispiel #1
0
u32 IdentifyImage(const char* path) {
    u8 header[0x200];
    FIL file;
    if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
        return 0;
    f_lseek(&file, 0);
    f_sync(&file);
    UINT fsize = f_size(&file);
    UINT bytes_read;
    if ((f_read(&file, header, 0x200, &bytes_read) != FR_OK) || (bytes_read != 0x200)) {
        f_close(&file);
        return 0;
    }
    f_close(&file);
    if ((getbe32(header + 0x100) == 0x4E435344) && (getbe64(header + 0x110) == (u64) 0x0104030301000000) &&
        (getbe64(header + 0x108) == (u64) 0) && (fsize >= 0x8FC8000)) {
        return IMG_NAND;
    } else if (getbe16(header + 0x1FE) == 0x55AA) { // migt be FAT or MBR
        if ((strncmp((char*) header + 0x36, "FAT12   ", 8) == 0) || (strncmp((char*) header + 0x36, "FAT16   ", 8) == 0) ||
            (strncmp((char*) header + 0x36, "FAT     ", 8) == 0) || (strncmp((char*) header + 0x52, "FAT32   ", 8) == 0)) {
            return IMG_FAT; // this is an actual FAT header
        } else if (((getle32(header + 0x1BE + 0x8) + getle32(header + 0x1BE + 0xC)) < (fsize / 0x200)) && // check file size
            (getle32(header + 0x1BE + 0x8) > 0) && (getle32(header + 0x1BE + 0xC) >= 0x800) && // check first partition sanity
            ((header[0x1BE + 0x4] == 0x1) || (header[0x1BE + 0x4] == 0x4) || (header[0x1BE + 0x4] == 0x6) || // filesystem type
             (header[0x1BE + 0x4] == 0xB) || (header[0x1BE + 0x4] == 0xC) || (header[0x1BE + 0x4] == 0xE))) {
            return IMG_FAT; // this might be an MBR -> give it the benefit of doubt
        }
    }
    return 0;
}
Beispiel #2
0
void cia_verify_contents(cia_context *ctx, u32 actions)
{
	u16 contentflags;
	ctr_tmd_body *body;
	ctr_tmd_contentchunk *chunk;
	u8 *verify_buf;
	u32 content_size=0;
	int i;

	// verify TMD content hashes, requires decryption ..
	body  = tmd_get_body(&ctx->tmd);
	chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS));

	fseek(ctx->file, ctx->offset + ctx->offsetcontent, SEEK_SET);
	for(i = 0; i < getbe16(body->contentcount); i++) 
	{
		content_size = getbe64(chunk->size) & 0xffffffff;

		contentflags = getbe16(chunk->type);

		verify_buf = malloc(content_size);
		fread(verify_buf, content_size, 1, ctx->file);

		if(contentflags & 1 && !(actions & PlainFlag)) // Decrypt if needed
		{
			ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff;
			ctx->iv[1] = getbe16(chunk->index) & 0xff;

			ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv);
		
			ctr_decrypt_cbc(&ctx->aes, verify_buf, verify_buf, content_size);
		}

		if (ctr_sha_256_verify(verify_buf, content_size, chunk->hash) == Good)
			ctx->tmd.content_hash_stat[i] = 1;
		else
			ctx->tmd.content_hash_stat[i] = 2;

		free(verify_buf);

		chunk++;
	}
Beispiel #3
0
void tmd_print(tmd_context* ctx)
{
	unsigned int type = getbe32(ctx->buffer);
	ctr_tmd_header_4096* header4096 = 0;
	ctr_tmd_header_2048* header2048 = 0;
	ctr_tmd_body* body = 0;
	unsigned int contentcount = 0;
	unsigned int savesize = 0;
	unsigned int titlever = 0;
	unsigned int i;

	if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1)
	{
		header2048 = (ctr_tmd_header_2048*)ctx->buffer;
	}
	else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1)
	{
		header4096 = (ctr_tmd_header_4096*)ctx->buffer;
	}
	else
	{
		return;
	}

	body = tmd_get_body(ctx);

	contentcount = getbe16(body->contentcount);
	savesize = getle32(body->savedatasize);
	titlever = getbe16(body->titleversion);
	
	fprintf(stdout, "\nTMD header:\n");
	fprintf(stdout, "Signature type:         %s\n", tmd_get_type_string(type));
	fprintf(stdout, "Issuer:                 %s\n", body->issuer);
	fprintf(stdout, "Version:                %d\n", body->version);
	fprintf(stdout, "CA CRL version:         %d\n", body->ca_crl_version);
	fprintf(stdout, "Signer CRL version:     %d\n", body->signer_crl_version);
	memdump(stdout, "System version:         ", body->systemversion, 8);
	memdump(stdout, "Title id:               ", body->titleid, 8);
	fprintf(stdout, "Title type:             %08x\n", getbe32(body->titletype));
	fprintf(stdout, "Group id:               %04x\n", getbe16(body->groupid));
	if(savesize < sizeKB)
		fprintf(stdout, "Save Size:              %08x\n", savesize);
	else if(savesize < sizeMB)
		fprintf(stdout, "Save Size:              %dKB (%08x)\n", savesize/sizeKB, savesize);
	else
		fprintf(stdout, "Save Size:              %dMB (%08x)\n", savesize/sizeMB, savesize);
	fprintf(stdout, "Access rights:          %08x\n", getbe32(body->accessrights));
	fprintf(stdout, "Title version:          %d.%d.%d (v%d)\n", (titlever >> 10) & 0x3F, (titlever >> 4) & 0x3F, titlever & 0xF, titlever);
	fprintf(stdout, "Content count:          %04x\n", getbe16(body->contentcount));
	fprintf(stdout, "Boot content:           %04x\n", getbe16(body->bootcontent));
	memdump(stdout, "Hash:                   ", body->hash, 32);

	fprintf(stdout, "\nTMD content info:\n");
	for(i = 0; i < TMD_MAX_CONTENTS; i++)
	{
		ctr_tmd_contentinfo* info = (ctr_tmd_contentinfo*)(body->contentinfo + sizeof(ctr_tmd_contentinfo)*i);

		if (getbe16(info->commandcount) == 0)
			continue;

		fprintf(stdout, "Content index:          %04x\n", getbe16(info->index));
		fprintf(stdout, "Command count:          %04x\n", getbe16(info->commandcount));
		memdump(stdout, "Unknown:                ", info->unk, 32);
	}
	fprintf(stdout, "\nTMD contents:\n");
	for(i = 0; i < contentcount; i++)
	{
		ctr_tmd_contentchunk* chunk = (ctr_tmd_contentchunk*)(body->contentinfo + 36*64 + i*48);
		unsigned short type = getbe16(chunk->type);

		fprintf(stdout, "Content id:             %08x\n", getbe32(chunk->id));
		fprintf(stdout, "Content index:          %04x\n", getbe16(chunk->index));
		fprintf(stdout, "Content type:           %04x", getbe16(chunk->type));
		if (type)
		{
			fprintf(stdout, " ");
			if (type & 1)
				fprintf(stdout, "[encrypted]");
			if (type & 2)
				fprintf(stdout, "[disc]");
			if (type & 4)
				fprintf(stdout, "[cfm]");
			if (type & 0x4000)
				fprintf(stdout, "[optional]");
			if (type & 0x8000)
				fprintf(stdout, "[shared]");
		}
		fprintf(stdout, "\n");
		fprintf(stdout, "Content size:           %016"PRIx64"\n", getbe64(chunk->size));

		switch(ctx->content_hash_stat[i]) {
			case 1:  memdump(stdout, "Content hash [OK]:      ", chunk->hash, 32); break;
			case 2:  memdump(stdout, "Content hash [FAIL]:    ", chunk->hash, 32); break;
			default: memdump(stdout, "Content hash:           ", chunk->hash, 32); break; 
		}

		fprintf(stdout, "\n");
	}
}
Beispiel #4
0
void cia_save(cia_context* ctx, u32 type, u32 flags)
{
	u32 offset;
	u32 size;
	u16 contentflags;
	u8 docrypto;
	filepath* path = 0;
	ctr_tmd_body *body;
	ctr_tmd_contentchunk *chunk;
	int i;
	char tmpname[255];

	switch(type)
	{
		case CIATYPE_CERTS:
			offset = ctx->offsetcerts;
			size = ctx->sizecert;
			path = settings_get_certs_path(ctx->usersettings);
		break;

		case CIATYPE_TIK:
			offset = ctx->offsettik;
			size = ctx->sizetik;
			path = settings_get_tik_path(ctx->usersettings);
		break;

		case CIATYPE_TMD:
			offset = ctx->offsettmd;
			size = ctx->sizetmd;
			path = settings_get_tmd_path(ctx->usersettings);
		break;
		
		case CIATYPE_CONTENT:
			offset = ctx->offsetcontent;
			size = ctx->sizecontent;
			path = settings_get_content_path(ctx->usersettings);
			
		break;

		case CIATYPE_META:
			offset = ctx->offsetmeta;
			size = ctx->sizemeta;
			path = settings_get_meta_path(ctx->usersettings);;
		break;

		default:
			fprintf(stderr, "Error, unknown CIA type specified\n");
			return;	
		break;
	}

	if (path == 0 || path->valid == 0)
		return;

	switch(type)
	{
		case CIATYPE_CERTS: fprintf(stdout, "Saving certs to %s\n", path->pathname); break;
		case CIATYPE_TIK: fprintf(stdout, "Saving tik to %s\n", path->pathname); break;
		case CIATYPE_TMD: fprintf(stdout, "Saving tmd to %s\n", path->pathname); break;
		case CIATYPE_CONTENT:

			body  = tmd_get_body(&ctx->tmd);
			chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS));

			for(i = 0; i < getbe16(body->contentcount); i++) {
				sprintf(tmpname, "%s.%04x.%08x", path->pathname, getbe16(chunk->index), getbe32(chunk->id));
				fprintf(stdout, "Saving content #%04x to %s\n", getbe16(chunk->index), tmpname);
				
				contentflags = getbe16(chunk->type);
				docrypto = contentflags & 1 && !(flags & PlainFlag);

				if(docrypto) // Decrypt if needed
				{
					ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff;
					ctx->iv[1] = getbe16(chunk->index) & 0xff;

					ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv);
				}

				cia_save_blob(ctx, tmpname, offset, getbe64(chunk->size) & 0xffffffff, docrypto);

				offset += getbe64(chunk->size) & 0xffffffff;
				chunk++;
			}

			memset(ctx->iv, 0, 16);

			return;
		break;

		case CIATYPE_META: fprintf(stdout, "Saving meta to %s\n", path->pathname); break;
	}

	cia_save_blob(ctx, path->pathname, offset, size, 0);
}