Exemple #1
0
void ProcessExeFS(PartitionInfo* info){ //We expect Exefs to take just a block. Why? No exefs right now reached 8MB.
	if(info->keyslot == 0x2C){
		DecryptPartition(info);
	}else if(info->keyslot == 0x25){  //The new keyX is a bit tricky, 'couse only .code is encrypted with it
		PartitionInfo myInfo;
		memcpy((void*)&myInfo, (void*)info, sizeof(PartitionInfo));
		u8 OriginalCTR[16]; memcpy(OriginalCTR, info->ctr, 16);
		myInfo.keyslot = 0x2C; myInfo.size = 0x200;
		DecryptPartition(&myInfo); add_ctr(myInfo.ctr, 0x200 / 16);
		if(myInfo.buffer[0] == '.' && myInfo.buffer[1] == 'c' && myInfo.buffer[2] == 'o' && myInfo.buffer[3] == 'd' && myInfo.buffer[4] == 'e'){
			//The 7.xKey encrypted .code partition
			u32 codeSize = *((unsigned int*)(myInfo.buffer + 0x0C));
			u32 nextSection = *((unsigned int*)(myInfo.buffer + 0x18)) + 0x200;
			myInfo.buffer += 0x200; myInfo.size = codeSize; myInfo.keyslot = 0x25;
			DecryptPartition(&myInfo);
			//The rest is normally encrypted
			memcpy((void*)&myInfo, (void*)info, sizeof(PartitionInfo));
			myInfo.buffer += nextSection; myInfo.size -= nextSection; myInfo.keyslot = 0x2C;
			myInfo.ctr = OriginalCTR;
			add_ctr(myInfo.ctr, nextSection/16);
			DecryptPartition(&myInfo);
		}else{
			myInfo.size = info->size-0x200;
			myInfo.buffer += 0x200;
			DecryptPartition(&myInfo);
		}
	}
}
Exemple #2
0
void nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out, unsigned int partition) {
    PartitionInfo info;
    u8 myCtr[16];
    for (int i = 0; i < 16; i++) {
        myCtr[i] = NANDCTR[i];
    }
    info.ctr = myCtr;
    info.buffer = out;
    info.size = numsectors * 0x200;
    info.keyY = NULL;
    add_ctr(info.ctr, partition / 16);
    switch (partition) {
    case TWLN	  :
        info.keyslot = 0x3;
        break;
    case TWLP	  :
        info.keyslot = 0x3;
        break;
    case AGB_SAVE :
        info.keyslot = 0x7;
        break;
    case FIRM0    :
        info.keyslot = 0x6;
        break;
    case FIRM1    :
        info.keyslot = 0x6;
        break;
    case CTRNAND  :
        info.keyslot = 0x4;
        break;
    }
    add_ctr(info.ctr, sector_no * 0x20);
    sdmmc_nand_readsectors(sector_no + partition / 0x200, numsectors, out);
    DecryptPartition(&info);
}
Exemple #3
0
u32 CryptBuffer(CryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;
    u32 mode = info->mode;

    if (info->setKeyY) {
        u8 keyY[16] __attribute__((aligned(32)));
        memcpy(keyY, info->keyY, 16);
        setup_aeskeyY(info->keyslot, keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        if (((mode & (0x7 << 27)) != AES_ECB_DECRYPT_MODE) && ((mode & (0x7 << 27)) != AES_ECB_ENCRYPT_MODE))
            set_ctr(ctr);
        if ((mode & (0x7 << 27)) == AES_CBC_DECRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        aes_decrypt((void*) buffer, (void*) buffer, 1, mode);
        if ((mode & (0x7 << 27)) == AES_CBC_ENCRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        else if ((mode & (0x7 << 27)) == AES_CTR_MODE)
            add_ctr(ctr, 0x1);
    }

    memcpy(info->ctr, ctr, 16);
    
    return 0;
}
Exemple #4
0
void emunand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out, unsigned int partition) {
	PartitionInfo info;
	uint8_t myCtr[16];
	if (partition == CTRNAND && getMpInfo() == MPINFO_KTR) partition = KTR_CTRNAND; //SWITCH TO KTR_CTRNAND IF ON N3DS
	for (int i = 0; i < 16; i++) { myCtr[i] = NANDCTR[i]; }
	info.ctr = myCtr; info.buffer = out; info.size = numsectors * 0x200; info.keyY = NULL;
	add_ctr(info.ctr, partition / 16);
	switch (partition) {
	case TWLN: info.keyslot = 0x3; break;
	case TWLP: info.keyslot = 0x3; break;
	case AGB_SAVE: info.keyslot = 0x7; break;
	case FIRM0: info.keyslot = 0x6; break;
	case FIRM1: info.keyslot = 0x6; break;
	case CTRNAND: info.keyslot = 0x4; break;
	case KTR_CTRNAND: info.keyslot = 0x5; break;
	}
	add_ctr(info.ctr, sector_no * 0x20);
	DecryptPartition(&info);
	sdmmc_sdcard_writesectors(sector_no + partition / 0x200, numsectors, out);	//Stubbed, i don't wanna risk
}
Exemple #5
0
u32 DecryptPartition(PartitionInfo* info){
	size_t bytesWritten;
	if (info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	u8 ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->ctr, 16);

	u32 size_bytes = info->size;
	for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
		u32 j;
		for (j = 0; (j < BLOCK_SIZE) && (i + j < size_bytes); j += 16) {
			set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)info->buffer + j, (void*)info->buffer + j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}
	}
	return 0;
}
Exemple #6
0
u32 DecryptPartition(PartitionInfo* info){
    size_t bytesWritten;
	if(info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u32 size_bytes = info->size;
    for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
        u32 j;
        for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
            set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)info->buffer+j, (void*)info->buffer+j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
			TryScreenShot(); //Putting it here allows us to take screenshots at any decryption point, since everyting loops in this
        }
    }
    return 0;
}
void BD_Factory::add_gaol(double f_RES) {
	Array<const ExprNode> new_args(sip.n_arg+sip.p_arg);
	int I=0;
	int J=0;
	for (int K=0; K<sip.n_arg+sip.p_arg; K++) {
		if (!sip.is_param[K]) new_args.set_ref(K,new_vars[I++]);
		else
			// necessary for applying goal function but ignored at the end
			// (there is no parameter in the goal function):
			new_args.set_ref(K,ExprConstant::new_(sip.p_domain[J++],true));
	}
	const ExprNode* goal_node=&((*sip.sys.goal)(new_args));

	if (problem==ORA) {
		const ExprConstant& f_RES_node=ExprConstant::new_scalar(f_RES);
		goal_node = &((*goal_node) - f_RES);
		add_ctr(ExprCtr(*goal_node,LEQ));

		const ExprNode& minus_eta=-new_vars[sip.n_arg];
		add_goal(minus_eta);
		delete &minus_eta;
	} else {
		add_goal(*goal_node);
	}

	// cleanup
	for (int K=0; K<sip.n_arg+sip.p_arg; K++) {
		if (sip.is_param[K]) {
			if (!new_args[K].fathers.is_empty())
				ibex_error("parameters in the objective");
			delete &new_args[K];
		}
	}

	cleanup(*goal_node,false);

	f_ctrs_copy.clone.clean();
}
Exemple #8
0
u32 DecryptBuffer(DecryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;

    if (info->setKeyY) {
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
        aes_decrypt((void*) buffer, (void*) buffer, ctr, 1, AES_CTR_MODE);
        add_ctr(ctr, 0x1);
    }

    memcpy(info->CTR, ctr, 16);

    return 0;
}
void BD_Factory::add_discretized_ctr(double eps_g) {

	std::vector<double>* samples;
	switch (problem) {
	case LBD : samples = sip.LBD_samples; break;
	case UBD : samples = sip.UBD_samples; break;
	case ORA : samples = sip.ORA_samples; break;
	}

	// For each constraint (even non-quantified)
	for (int c=0; c<sip.sys.nb_ctr; c++) {
		//cout << "Constraint: " << sip.sys.ctrs[c] << endl;

		// build an initial set of (all) parameters values.
		// (includes those not involved in the constraint but these
		//  values will be ignored anyway)
		Vector p_box(sip.p);

		for (int j=0; j<sip.p; j++)
			p_box[j]=samples[j].front();

		// push this initial combination in a list
		list<Vector> p_boxes;
		//cout << "  add p_box:" << p_box << endl;
		p_boxes.push_back(p_box);

		// We then create all combinations of LBD/UBD_samples for the parameters
		// involved in the constraint c, via a recursive Cartesian product
		// with all previously existing combinations.
		for (int j=0; j<sip.p; j++) {
			//cout << "  param n°" << j << "=" << sip.varset.param(j);
			if (sip.sys.ctrs[c].f.used(sip.varset.param(j))) {
				//cout << " **used**" << endl;
				// for each box already inside the list...
				for (list<Vector>::iterator it2=p_boxes.begin(); it2!=p_boxes.end(); it2=p_boxes.erase(it2)) {
					p_box=*it2;
					// ... we instantiate the domain of the parameter to each of its current
					// sampled values
					for (vector<double>::iterator it=samples[j].begin(); it!=samples[j].end(); it++) {
						p_box[j]=*it;
						p_boxes.push_front(p_box); // pushed at the beginning -> no impact for the enclosing loop
						//cout << "  add p_box:" << p_box << endl;
					}
				}
			} else {
				//cout << " (unused)" << endl;
			}
		}

		// all the constraints generated with constraint n°c
		// (stored in an array for cleanup)
		Array<const ExprNode> exprs_ctr(p_boxes.size());
		int i=0;

		// We generate one constraint for each p_box
		for (list<Vector>::iterator it=p_boxes.begin(); it!=p_boxes.end(); it++) {

			// transform the "flat" box into a list of domains
			// (which is necessary for composition of functions expression)
			load(sip.p_domain, *it);

			Array<const ExprNode> new_args(sip.n_arg+sip.p_arg);
			int I=0;
			int J=0;
			for (int K=0; K<sip.n_arg+sip.p_arg; K++) {
				if (!sip.is_param[K])
					// a variable x in the original system is a variable in
					// the LBD/UBD problem
					new_args.set_ref(K,new_vars[I++]);
				else
					// a parameter becomes a constant
					// (note: can have a reference because the expression is copied afterward)
					new_args.set_ref(K,ExprConstant::new_(sip.p_domain[J++],true));
			}
			const ExprNode* expr_ctr_tmp=&sip.sys.ctrs[c].f(new_args);

			if (problem==UBD) {
				// In the UBD problem, shift the constraint with eps_g
				const ExprConstant& eps_node=ExprConstant::new_scalar(sip.sys.ctrs[c].op==LEQ ? eps_g : -eps_g);
				expr_ctr_tmp = & (*expr_ctr_tmp + eps_node);
			} else if (problem==ORA) {
				// in the ORA problem, shift the constraint with eta
				const ExprNode& eta=new_vars[sip.n_arg];
				const ExprNode& eta_node=sip.sys.ctrs[c].op==LEQ ? eta : -eta;
				expr_ctr_tmp = & (*expr_ctr_tmp + eta_node);
			}

			// cleanup the constants created which
			// do not appear in the constraint expression
			for (int K=0; K<sip.n_arg+sip.p_arg; K++) {
				if (sip.is_param[K] && new_args[K].fathers.is_empty()) delete &new_args[K];
			}

			const ExprNode& expr_ctr=expr_ctr_tmp->simplify();

			ExprCtr ctr(expr_ctr, sip.sys.ctrs[c].op);
			//cout << "  generated constraint:" << ctr << endl;
			add_ctr(ctr);

			exprs_ctr.set_ref(i++,expr_ctr);

		}

		cleanup(exprs_ctr,false);
		f_ctrs_copy.clone.clean();

		//cout << endl;
	}
}
Exemple #10
0
u32 NandPadgen()
{
    u8* ctrStart = FindNandCtr();
    if (ctrStart == NULL)
        return 1;

    u8 ctr[16] = {0x0};
    u32 i = 0;
    for(i = 0; i < 16; i++)
        ctr[i] = *(ctrStart + (15 - i)); //The CTR is stored backwards in memory.

    add_ctr(ctr, 0xB93000); //The CTR stored in memory would theoretically be for NAND block 0, so we need to increment it some.

    u32 keyslot = 0x0;
    u32 nand_size = 0;
    switch (GetUnitPlatform()) {
        case PLATFORM_3DS:
            keyslot = 0x4;
            nand_size = 758;
            break;
        case PLATFORM_N3DS:
            keyslot = 0x5;
            nand_size = 1055;
            break;
    }

    Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
    Debug("Filename: nand.fat16.xorpad");

    PadInfo padInfo = {.keyslot = keyslot, .setKeyY = 0, .size_mb = nand_size , .filename = "/nand.fat16.xorpad"};
    memcpy(padInfo.CTR, ctr, 16);

    u32 result = CreatePad(&padInfo);
    if(result == 0) {
        Debug("Done!");
        return 0;
    } else {
        return 1;
    }
}

u32 CreatePad(PadInfo *info)
{
    static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};
    u8* buffer = BUFFER_ADDRESS;
    u32 result = 0;
    
    if (!FileCreate(info->filename, true)) // No DebugFileCreate() here - messages are already given
        return 1;

    if(info->setKeyY)
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u32 size_bytes = info->size_mb * 1024*1024;
    for (u32 i = 0; i < size_bytes; i += BUFFER_MAX_SIZE) {
        u32 curr_block_size = min(BUFFER_MAX_SIZE, size_bytes - i);

        for (u32 j = 0; j < curr_block_size; j+= 16) {
            set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)zero_buf, (void*)buffer + j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
        }

        ShowProgress(i, size_bytes);

        if (!DebugFileWrite((void*)buffer, curr_block_size, i)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandDumper() {
    u8* buffer = BUFFER_ADDRESS;
    u32 nand_size = (GetUnitPlatform() == PLATFORM_3DS) ? 0x3AF00000 : 0x4D800000;
    u32 result = 0;

    Debug("Dumping System NAND. Size (MB): %u", nand_size / (1024 * 1024));

    if (!DebugFileCreate("/NAND.bin", true))
        return 1;

    u32 n_sectors = nand_size / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(i, SECTORS_PER_READ, buffer);
        if(!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandPartitionsDumper() {
    u32 ctrnand_offset;
    u32 ctrnand_size;
    u32 keyslot;

    switch (GetUnitPlatform()) {
    case PLATFORM_3DS:
        ctrnand_offset = 0x0B95CA00;
        ctrnand_size = 0x2F3E3600;
        keyslot = 0x4;
        break;
    case PLATFORM_N3DS:
        ctrnand_offset = 0x0B95AE00;
        ctrnand_size = 0x41D2D200;
        keyslot = 0x5;
        break;
    }

    // see: http://3dbrew.org/wiki/Flash_Filesystem
    Debug("Dumping firm0.bin: %s!", DumpPartition("firm0.bin", 0x0B130000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping firm1.bin: %s!", DumpPartition("firm1.bin", 0x0B530000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping ctrnand.bin: %s!", DumpPartition("ctrnand.bin", ctrnand_offset, ctrnand_size, keyslot) == 0 ? "succeeded" : "failed");

    return 0;
}
Exemple #11
0
u32 SdPadgen()
{
    u32 result;

    SdInfo *info = (SdInfo*)0x20316000;

    u8 movable_seed[0x120] = {0};

    // Load console 0x34 keyY from movable.sed if present on SD card
    if (DebugFileOpen("/movable.sed")) {
        if (!DebugFileRead(&movable_seed, 0x120, 0)) {
            FileClose();
            return 1;
        }
        FileClose();
        if (memcmp(movable_seed, "SEED", 4) != 0) {
            Debug("movable.sed is too corrupt!");
            return 1;
        }
        setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
        use_aeskey(0x34);
    }

    if (!DebugFileOpen("/SDinfo.bin"))
        return 1;
    if (!DebugFileRead(info, 4, 0)) {
        FileClose();
        return 1;
    }

    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Too many/few entries!");
        return 1;
    }

    Debug("Number of entries: %i", info->n_entries);

    if (!DebugFileRead(info->entries, info->n_entries * sizeof(SdInfoEntry), 4)) {
        FileClose();
        return 1;
    }
    FileClose();

    for(u32 i = 0; i < info->n_entries; i++) {
        Debug ("Creating pad number: %i. Size (MB): %i", i+1, info->entries[i].size_mb);

        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
        memcpy(padInfo.CTR, info->entries[i].CTR, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);

        result = CreatePad(&padInfo);
        if (!result)
            Debug("Done!");
        else
            return 1;
    }

    return 0;
}

static u8* FindNandCtr()
{
    static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
    static const u8* version_ctrs[] = {
        (u8*)0x080D7CAC,
        (u8*)0x080D858C,
        (u8*)0x080D748C,
        (u8*)0x080D740C,
        (u8*)0x080D74CC,
        (u8*)0x080D794C
    };
    static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);

    for (u32 i = 0; i < version_ctrs_len; i++) {
        if (*(u32*)version_ctrs[i] == 0x5C980) {
            Debug("System version %s", versions[i]);
            return (u8*)(version_ctrs[i] + 0x30);
        }
    }

    // If value not in previous list start memory scanning (test range)
    for (u8* c = (u8*)0x080D8FFF; c > (u8*)0x08000000; c--) {
        if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
            Debug("CTR Start 0x%08X", c + 0x30);
            return c + 0x30;
        }
    }

    return NULL;
}

u32 DumpPartition(char* filename, u32 offset, u32 size, u32 keyslot) {
    DecryptBufferInfo info;
    u8* buffer = BUFFER_ADDRESS;
    u8* ctrStart = FindNandCtr();
    u32 result = 0;

    Debug("Dumping System NAND Partition. Size (MB): %u", size / (1024 * 1024));
    Debug("Filename: %s", filename);

    if (ctrStart == NULL)
        return 1;

    info.keyslot = keyslot;
    info.setKeyY = 0;
    info.size = SECTORS_PER_READ * NAND_SECTOR_SIZE;
    info.buffer = buffer;
    for (u32 i = 0; i < 16; i++) {
        info.CTR[i] = *(ctrStart + (0xF - i)); // The CTR is stored backwards in memory.
    }

    add_ctr(info.CTR, offset / 0x10);

    if (!DebugFileCreate(filename, true))
        return 1;

    u32 n_sectors = size / NAND_SECTOR_SIZE;
    u32 start_sector = offset / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(start_sector + i, SECTORS_PER_READ, buffer);
        DecryptBuffer(&info);
        if (!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}
Exemple #12
0
u32 SdPadgen(u32 param)
{
    (void) (param); // param is unused here
    SdInfo *info = (SdInfo*) 0x20316000;

    // setup AES key from SD
    SetupSdKeyY0x34(false, NULL);
    
    if (!DebugFileOpen("SDinfo.bin"))
        return 1;
    if (!DebugFileRead(info, 4, 0)) {
        FileClose();
        return 1;
    }
    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        FileClose();
        Debug("Bad number of entries!");
        return 1;
    }
    if (!DebugFileRead(info->entries, info->n_entries * sizeof(SdInfoEntry), 4)) {
        FileClose();
        return 1;
    }
    FileClose();
    
    Debug("Number of entries: %i", info->n_entries);
    for(u32 i = 0; i < info->n_entries; i++) {
        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb, .mode = AES_CNT_CTRNAND_MODE};
        memcpy(padInfo.ctr, info->entries[i].ctr, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);
        Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 SdPadgenDirect(u32 param)
{
    (void) (param); // param is unused here
    SdInfo *info = (SdInfo*) 0x20316000;
    char basepath[256];
    u8 movable_keyY[16];
    
    if (SetupSdKeyY0x34(true, movable_keyY) != 0)
        return 1; // movable.sed has to be present in NAND
    
    Debug("");
    if (SdFolderSelector(basepath, movable_keyY) != 0)
        return 1;
    Debug("");
    if (SdInfoGen(info, basepath) != 0)
        return 1;
    if (!info->n_entries) {
        Debug("Nothing found in folder");
        return 1;
    }
    
    Debug("Number of entries: %i", info->n_entries);
    for(u32 i = 0; i < info->n_entries; i++) {
        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb, .mode = AES_CNT_CTRNAND_MODE};
        memcpy(padInfo.ctr, info->entries[i].ctr, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);
        Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 AnyPadgen(u32 param)
{
    (void) (param); // param is unused here
    AnyPadInfo *info = (AnyPadInfo*) 0x20316000;
    
    // get header
    if ((FileGetData("anypad.bin", info, 16, 0) != 16) || !info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Corrupt or not existing: anypad.bin");
        return 1;
    }
    
    // get data
    u32 data_size = info->n_entries * sizeof(AnyPadInfoEntry);
    if (FileGetData("anypad.bin", (u8*) info + 16, data_size, 16) != data_size) {
        Debug("File is missing data: anypad.bin");
        return 1;
    }
    
    Debug("Processing anypad.bin...");
    Debug("Number of entries: %i", info->n_entries);
    for (u32 i = 0; i < info->n_entries; i++) { // this translates all entries to a standard padInfo struct
        AnyPadInfoEntry* entry = &(info->entries[i]);
        PadInfo padInfo = {.keyslot = entry->keyslot, .setKeyY = 0, .size_mb = 0, .size_b = entry->size_b, .mode = entry->mode};
        memcpy(padInfo.filename, entry->filename, 80);
        memcpy(padInfo.ctr, entry->ctr, 16);
        // process keys
        if (entry->setNormalKey)
            setup_aeskey(entry->keyslot, entry->normalKey);
        if (entry->setKeyX)
            setup_aeskeyX(entry->keyslot, entry->keyX);
        if (entry->setKeyY)
            setup_aeskeyY(entry->keyslot, entry->keyY);
        use_aeskey(entry->keyslot);
        // process flags
        if (entry->flags & (AP_USE_NAND_CTR|AP_USE_SD_CTR)) {
            u32 ctr_add = getbe32(padInfo.ctr + 12);
            u8 shasum[32];
            u8 cid[16];
            sdmmc_get_cid((entry->flags & AP_USE_NAND_CTR) ? 1 : 0, (uint32_t*) cid);
            if (entry->mode == AES_CNT_TWLNAND_MODE) {
                sha_quick(shasum, cid, 16, SHA1_MODE);
                for (u32 i = 0; i < 16; i++)
                    padInfo.ctr[i] = shasum[15-i];
            } else {
                sha_quick(shasum, cid, 16, SHA256_MODE);
                memcpy(padInfo.ctr, shasum, 16);
            }
            add_ctr(padInfo.ctr, ctr_add);
        }
        // create the pad
        Debug ("%2i: %s (%ikB)", i, entry->filename, entry->size_b / 1024);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 CtrNandPadgen(u32 param)
{
    char* filename = (param & PG_FORCESLOT4) ? "nand.fat16.slot0x04.xorpad" : "nand.fat16.xorpad";
    u32 keyslot;
    u32 nand_size;

    // legacy sizes & offset, to work with Python 3DSFAT16Tool
    if (GetUnitPlatform() == PLATFORM_3DS) {
        if (param & PG_FORCESLOT4) {
            Debug("This is a N3DS only feature");
            return 1;
        }
        keyslot = 0x4;
        nand_size = 758;
    } else {
        keyslot = (param & PG_FORCESLOT4) ? 0x4 : 0x5;
        nand_size = 1055;
    }

    Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
    Debug("Filename: %s", filename);

    PadInfo padInfo = {
        .keyslot = keyslot,
        .setKeyY = 0,
        .size_mb = nand_size,
        .mode = AES_CNT_CTRNAND_MODE
    };
    strncpy(padInfo.filename, filename, 64);
    if(GetNandCtr(padInfo.ctr, 0xB930000) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 TwlNandPadgen(u32 param)
{
    (void) (param); // param is unused here
    PartitionInfo* twln_info = GetPartitionInfo(P_TWLN);
    u32 size_mb = (twln_info->size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating TWLN FAT16 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: twlnand.fat16.xorpad");

    PadInfo padInfo = {
        .keyslot = twln_info->keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "twlnand.fat16.xorpad",
        .mode = AES_CNT_TWLNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, twln_info->offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 Firm0Firm1Padgen(u32 param)
{
    (void) (param); // param is unused here
    PartitionInfo* firm0_info = GetPartitionInfo(P_FIRM0);
    PartitionInfo* firm1_info = GetPartitionInfo(P_FIRM1);
    u32 size_mb = (firm0_info->size + firm1_info->size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating FIRM0FIRM1 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: firm0firm1.xorpad");

    PadInfo padInfo = {
        .keyslot = firm0_info->keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "firm0firm1.xorpad",
        .mode = AES_CNT_CTRNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, firm0_info->offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}
Exemple #13
0
int ProcessCTR(char* path){
	PartitionInfo myInfo;
	File myFile;
	char myString[256];  //In case it is needed...
	if(FileOpen(&myFile, path, 0)){
		ConsoleInit();
		ConsoleAddText(TITLE);
		unsigned int ncch_base = 0x100;
		unsigned char magic[] = { 0, 0, 0, 0, 0};
		FileRead(&myFile, magic, 4, ncch_base);
		if(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'S' && magic[3] == 'D'){
			ncch_base = 0x4000;
			FileRead(&myFile, magic, 4, ncch_base+0x100);
			if(!(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'C' && magic[3] == 'H')){
				FileClose(&myFile);
				return 2;
			}
		}else if(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'C' && magic[3] == 'H'){
			ncch_base = 0x0;
		}else{
			FileClose(&myFile);
			return 2;
		}
		ctr_ncchheader NCCH; unsigned int mediaunitsize = 0x200;
		FileRead(&myFile, &NCCH, 0x200, ncch_base);

		//ConsoleAddText(path);
		ConsoleAddText(NCCH.productcode);
		unsigned int NEWCRYPTO = 0, CRYPTO = 1;
		if(NCCH.flags[3] != 0) NEWCRYPTO = 1;
		if(NCCH.flags[7] & 4) CRYPTO = 0;
		if(NEWCRYPTO){
			ConsoleAddText("\nCryptoType : 7.X Key security");
		}else if(CRYPTO){
			ConsoleAddText("\nCryptoType : Secure");
		}else{
			ConsoleAddText("\nCryptoType : None");
			ConsoleAddText("Decryption completed!");
			FileClose(&myFile);
			ConsoleShow();
			return 3;
		}

		ConsoleShow();
		u8 CTR[16];
		if(getle32(NCCH.extendedheadersize) > 0){
			ConsoleAddText("Decrypting ExHeader..."); ConsoleShow();
			ncch_get_counter(NCCH, CTR, 1);
			FileRead(&myFile, BUFFER_ADDR, 0x800, ncch_base + 0x200);
			myInfo.buffer = BUFFER_ADDR;
			myInfo.size = 0x800;
			myInfo.keyslot = 0x2C;
			myInfo.ctr = CTR;
			myInfo.keyY = NCCH.signature;
			DecryptPartition(&myInfo);
			FileWrite(&myFile, BUFFER_ADDR, 0x800, ncch_base + 0x200);
		}
		if(getle32(NCCH.exefssize) > 0){
			ConsoleAddText("Decrypting ExeFS..."); ConsoleShow();
			ncch_get_counter(NCCH, CTR, 2);
			myInfo.buffer = BUFFER_ADDR;
			myInfo.keyslot = NEWCRYPTO ? 0x25 : 0x2C;
			myInfo.ctr = CTR;
			myInfo.keyY = NCCH.signature;

			size_t bytesRead = FileRead(&myFile, BUFFER_ADDR, getle32(NCCH.exefssize) * mediaunitsize, ncch_base + getle32(NCCH.exefsoffset) * mediaunitsize);
			myInfo.size = bytesRead;
			ProcessExeFS(&myInfo); //Explanation at function definition
			FileWrite(&myFile, BUFFER_ADDR, getle32(NCCH.exefssize) * mediaunitsize, ncch_base + getle32(NCCH.exefsoffset) * mediaunitsize);
		}
		if(getle32(NCCH.romfssize) > 0){
			ConsoleAddText("Decrypting RomFS..."); ConsoleShow();
			ncch_get_counter(NCCH, CTR, 3);
			myInfo.buffer = BUFFER_ADDR;
			myInfo.keyslot = NEWCRYPTO ? 0x25 : 0x2C;
			myInfo.ctr = CTR;
			myInfo.keyY = NCCH.signature;
			for(int i = 0; i < getle32(NCCH.romfssize) * mediaunitsize / BLOCK_SIZE; i++){
				sprintf(myString, "%i%%", (int)((i*BLOCK_SIZE)/(getle32(NCCH.romfssize) * mediaunitsize/ 100)));
				int x, y; ConsoleGetXY(&x, &y); y += CHAR_WIDTH * 4; x += CHAR_WIDTH*22;
				DrawString(TOP_SCREEN, myString, x, y, ConsoleGetTextColor(),  ConsoleGetBackgroundColor());
				size_t bytesRead = FileRead(&myFile, BUFFER_ADDR, BLOCK_SIZE, ncch_base + getle32(NCCH.romfsoffset) * mediaunitsize + i*BLOCK_SIZE);
				myInfo.size = bytesRead;
				DecryptPartition(&myInfo);
				add_ctr(myInfo.ctr, bytesRead/16);
				FileWrite(&myFile, BUFFER_ADDR, BLOCK_SIZE, ncch_base + getle32(NCCH.romfsoffset) * mediaunitsize + i*BLOCK_SIZE);
			}
		}
		NCCH.flags[7] |= 4; //Disable encryption
		NCCH.flags[3] = 0;  //Disable 7.XKey usage
		FileWrite(&myFile, &NCCH, 0x200, ncch_base);
		if(ncch_base == 0x4000) FileWrite(&myFile, ((u8*)&NCCH) + 0x100, 0x100, 0x1100);   //Only for NCSD
		FileClose(&myFile);
		ConsoleAddText("Decryption completed!"); ConsoleShow();
		return 0;
	}else return 1;
}
Exemple #14
0
u32 CtrNandPadgen(u32 param)
{
    u32 keyslot;
    u32 nand_size;

    // legacy sizes & offset, to work with 3DSFAT16Tool
    if (GetUnitPlatform() == PLATFORM_3DS) {
        keyslot = 0x4;
        nand_size = 758;
    } else {
        keyslot = 0x5;
        nand_size = 1055;
    }

    Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
    Debug("Filename: nand.fat16.xorpad");

    PadInfo padInfo = {
        .keyslot = keyslot,
        .setKeyY = 0,
        .size_mb = nand_size,
        .filename = "nand.fat16.xorpad",
        .mode = AES_CNT_CTRNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, 0xB930000) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 TwlNandPadgen(u32 param)
{
    u32 size_mb = (partitions[0].size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating TWLN FAT16 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: twlnand.fat16.xorpad");

    PadInfo padInfo = {
        .keyslot = partitions[0].keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "twlnand.fat16.xorpad",
        .mode = AES_CNT_TWLNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, partitions[0].offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 Firm0Firm1Padgen(u32 param)
{
    u32 size_mb = (partitions[3].size + partitions[4].size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating FIRM0FIRM1 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: firm0firm1.xorpad");

    PadInfo padInfo = {
        .keyslot = partitions[3].keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "firm0firm1.xorpad",
        .mode = AES_CNT_CTRNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, partitions[3].offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 GetNandCtr(u8* ctr, u32 offset)
{
    static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
    static const u8* version_ctrs[] = {
        (u8*)0x080D7CAC,
        (u8*)0x080D858C,
        (u8*)0x080D748C,
        (u8*)0x080D740C,
        (u8*)0x080D74CC,
        (u8*)0x080D794C
    };
    static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);
    static u8* ctr_start = NULL;

    if (ctr_start == NULL) {
        for (u32 i = 0; i < version_ctrs_len; i++) {
            if (*(u32*)version_ctrs[i] == 0x5C980) {
                Debug("System version %s", versions[i]);
                ctr_start = (u8*) version_ctrs[i] + 0x30;
            }
        }

        // If value not in previous list start memory scanning (test range)
        if (ctr_start == NULL) {
            for (u8* c = (u8*) 0x080D8FFF; c > (u8*) 0x08000000; c--) {
                if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
                    ctr_start = c + 0x30;
                    Debug("CTR start 0x%08X", ctr_start);
                    break;
                }
            }
        }

        if (ctr_start == NULL) {
            Debug("CTR start not found!");
            return 1;
        }
    }

    // the ctr is stored backwards in memory
    if (offset >= 0x0B100000) { // CTRNAND/AGBSAVE region
        for (u32 i = 0; i < 16; i++)
            ctr[i] = *(ctr_start + (0xF - i));
    } else { // TWL region
        for (u32 i = 0; i < 16; i++)
            ctr[i] = *(ctr_start + 0x88 + (0xF - i));
    }

    // increment counter
    add_ctr(ctr, offset / 0x10);

    return 0;
}

u32 DecryptNandToMem(u8* buffer, u32 offset, u32 size, PartitionInfo* partition)
{
    CryptBufferInfo info = {.keyslot = partition->keyslot, .setKeyY = 0, .size = size, .buffer = buffer, .mode = partition->mode};
    if(GetNandCtr(info.ctr, offset) != 0)
        return 1;

    u32 n_sectors = (size + NAND_SECTOR_SIZE - 1) / NAND_SECTOR_SIZE;
    u32 start_sector = offset / NAND_SECTOR_SIZE;
    ReadNandSectors(start_sector, n_sectors, buffer);
    CryptBuffer(&info);

    return 0;
}

u32 DecryptNandToFile(const char* filename, u32 offset, u32 size, PartitionInfo* partition)
{
    u8* buffer = BUFFER_ADDRESS;
    u32 result = 0;

    if (!DebugFileCreate(filename, true))
        return 1;

    for (u32 i = 0; i < size; i += NAND_SECTOR_SIZE * SECTORS_PER_READ) {
        u32 read_bytes = min(NAND_SECTOR_SIZE * SECTORS_PER_READ, (size - i));
        ShowProgress(i, size);
        DecryptNandToMem(buffer, offset + i, read_bytes, partition);
        if(!DebugFileWrite(buffer, read_bytes, i)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}
static inline void ctr_advance_ctr(ctr_crypto_interface *io, uint8_t *buffer, size_t buffer_size, size_t block, uint8_t *ctr)
{
	add_ctr(ctr, block);
}
Exemple #16
0
uint32_t NcchPadgen()
{
	uint32_t result;
	File pf;
	NcchInfo *info = (NcchInfo*)0x20316000;

	const char *filename = "/ncchinfo.bin";
	wchar_t wfilename[14];
	mbstowcs(wfilename, filename, 14);
	if (!FileOpen(&pf, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	FileRead(&pf, info, 16, 0);

	if (info->ncch_info_version != 0xF0000003) {
        	print(strings[STR_WRONG], filename+1, strings[STR_VERSION]);
		return 0;
	}
	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 0;
	}
	FileRead(&pf, info->entries, info->n_entries * sizeof(NcchInfoEntry), 16);
	FileClose(&pf);

	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();
	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.setKeyY = 1, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.keyY, info->entries[i].keyY, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 112);

		if(info->entries[i].uses7xCrypto)
			padInfo.keyslot = 0x25;
		else
			padInfo.keyslot = 0x2C;

		result = CreatePad(&padInfo, i);
		if (result) return 1;
	}

	return 0;
}

uint32_t SdPadgen()
{
	size_t bytesRead;
	uint32_t result;
	File fp;
	SdInfo *info = (SdInfo*)0x20316000;

	uint8_t movable_seed[0x120] = {0};
	const char *filename = "/movable.sed";
	wchar_t wfilename[13];
	mbstowcs(wfilename, filename, 13);
	// Load console 0x34 keyY from movable.sed if present on SD card
	if (FileOpen(&fp, filename, 0)) {
		bytesRead = FileRead(&fp, &movable_seed, 0x120, 0);
		FileClose(&fp);
		if (bytesRead != 0x120) {
			print(strings[STR_WRONG], filename+1, strings[STR_SIZE]);
			return 1;
		}
		if (memcmp(movable_seed, "SEED", 4) != 0) {
			print(strings[STR_WRONG], filename+1, strings[STR_CONTENT]);
			return 1;
		}
		setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
		use_aeskey(0x34);
	}

	filename = "/SDinfo.bin";
	if (!FileOpen(&fp, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	bytesRead = FileRead(&fp, info, 4, 0);

	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 1;
	}

       	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();

	bytesRead = FileRead(&fp, info->entries, info->n_entries * sizeof(SdInfoEntry), 4);
	FileClose(&fp);

	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 180);

		result = CreatePad(&padInfo, i);
		if (result)
			return 1;
	}

	return 0;
}

static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};

uint32_t CreatePad(PadInfo *info, int index)
{
	File pf;
	#define BUFFER_ADDR ((volatile uint8_t*)0x21000000)
	#define BLOCK_SIZE  (4*1024*1024)

	if (!FileOpen(&pf, info->filename, 1))
		return 1;

	if(info->setKeyY != 0)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	uint8_t ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->CTR, 16);

	uint32_t size_bytes = info->size_mb*1024*1024;
	uint32_t size_100 = size_bytes/100;
	uint32_t seekpos = 0;
	for (uint32_t i = 0; i < size_bytes; i += BLOCK_SIZE) {
		uint32_t j;
		for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
			set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)zero_buf, (void*)BUFFER_ADDR+j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}

		print(strings[STR_GENERATING], strings[STR_PAD]);
		print(L"%i : %i%%", index, (i+j)/size_100);
		ConsolePrevLine();
		ConsolePrevLine();
		ConsoleShow();
		FileWrite(&pf, (void*)BUFFER_ADDR, j, seekpos);
		seekpos += j;
	}

	FileClose(&pf);
	return 0;
}