Example #1
0
void nand_writesectors(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);
    DecryptPartition(&info);
    sdmmc_nand_writesectors(sector_no + partition / 0x200, numsectors, out);	//Stubbed, i don't wanna risk
}
Example #2
0
static inline int WriteNandSectors(u32 sector_no, u32 numsectors, u8 *in)
{
    if (emunand_header) {
        if (sector_no == 0) {
            int errorcode = sdmmc_sdcard_writesectors(emunand_header, 1, in);
            if (errorcode) return errorcode;
            sector_no = 1;
            numsectors--;
            in += 0x200;
        }
        return sdmmc_sdcard_writesectors(sector_no + emunand_offset, numsectors, in);
    } else return sdmmc_nand_writesectors(sector_no, numsectors, in);
}
static inline void installer(u32 a9lhBoot)
{
    if(!mountSD())
        shutdown(1, "Error: failed to mount the SD card");

    const char *path;
    u32 updatea9lh = 0;

    //If making a first install, we need the OTP
    if(!a9lhBoot)
    {
        //Read OTP
        path = "homebrew/3ds/ShadowNAND_Installer/otp.bin";
        if(fileRead((void *)OTP_OFFSET, path) != 256)
        {
            const u8 zeroes[256] = {0};
            if(memcmp((void *)OTP_FROM_MEM, zeroes, 256) == 0)
                shutdown(1, "Error: otp.bin doesn't exist and can't be dumped");

            fileWrite((void *)OTP_FROM_MEM, path, 256);
            memcpy((void *)OTP_OFFSET, (void *)OTP_FROM_MEM, 256);
        }
    }

    //Setup the key sector de/encryption with the SHA register or otp.bin
    setupKeyslot0x11(a9lhBoot, (void *)OTP_OFFSET);

    //Calculate the CTR for the 3DS partitions
    getNandCTR();

    //Get NAND FIRM0 and test that the CTR is correct
    readFirm0((u8 *)FIRM0_OFFSET, FIRM0_SIZE);
    if(memcmp((void *)FIRM0_OFFSET, "FIRM", 4) != 0)
        shutdown(1, "Error: failed to setup FIRM encryption");

    //If booting from A9LH or on N3DS, we can use the key sector from NAND
    if(a9lhBoot || console)
    {
		 updatea9lh = 1;
		 //Read decrypted key sector
         path = "homebrew/3ds/ShadowNAND_Installer/secret_sector.bin";
         if(fileRead((void *)SECTOR_OFFSET, path) != 0x200)
             shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size");
         if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash))
             shutdown(1, "Error: secret_sector.bin is invalid or corrupted");
    }

    if(!a9lhBoot || updatea9lh)
    {
        //Generate and encrypt a per-console A9LH key sector
        generateSector((u8 *)SECTOR_OFFSET, 0);

        //Read FIRM0
        path = "homebrew/3ds/ShadowNAND_Installer/firm0.bin";
        if(fileRead((void *)FIRM0_OFFSET, path) != FIRM0_SIZE)
            shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size");

        if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash))
            shutdown(1, "Error: firm0.bin is invalid or corrupted");
    }

    if(!a9lhBoot)
    {
        //Read FIRM1
        path = "homebrew/3ds/ShadowNAND_Installer/firm1.bin";
        if(fileRead((void *)FIRM1_OFFSET, path) != FIRM1_SIZE)
            shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size");

        if(!verifyHash((void *)FIRM1_OFFSET, FIRM1_SIZE, firm1Hash))
            shutdown(1, "Error: firm1.bin is invalid or corrupted");
    }

    //Inject stage1
    memset32((void *)STAGE1_OFFSET, 0, MAX_STAGE1_SIZE);
    path = "homebrew/3ds/ShadowNAND_Installer/payload_stage1.bin";
    u32 size = fileRead((void *)STAGE1_OFFSET, path);
    if(!size || size > MAX_STAGE1_SIZE)
        shutdown(1, "Error: payload_stage1.bin doesn't exist or\nexceeds max size");

    const u8 zeroes[688] = {0};
    if(memcmp(zeroes, (void *)STAGE1_OFFSET, 688) == 0)
        shutdown(1, "Error: the payload_stage1.bin you're attempting\nto install is not compatible");

    //Read stage2
    memset32((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE);
    path = "homebrew/3ds/ShadowNAND_Installer/payload_stage2.bin";
    size = fileRead((void *)STAGE2_OFFSET, path);
    if(!size || size > MAX_STAGE2_SIZE)
        shutdown(1, "Error: payload_stage2.bin doesn't exist or\nexceeds max size");

    //Read alt_stage2
    memset32((void *)ALTSTAGE2_OFFSET, 0, MAX_ALTSTAGE2_SIZE);
    path = "homebrew/3ds/ShadowNAND_Installer/payload_altstage2.bin";
    size = fileRead((void *)ALTSTAGE2_OFFSET, path);
    if(!size || size > MAX_ALTSTAGE2_SIZE)
        shutdown(1, "Error: payload_altstage2.bin doesn't exist or\nexceeds max size");

    posY = drawString("All checks passed, installing...", 10, posY + SPACING_Y, COLOR_WHITE);

    //Point of no return, install stuff in the safest order
    sdmmc_nand_writesectors(0x5A000, 0x20, (vu8 *)ALTSTAGE2_OFFSET);
    sdmmc_nand_writesectors(0x5C000, 0x20, (vu8 *)STAGE2_OFFSET);
    if(!a9lhBoot) writeFirm((u8 *)FIRM1_OFFSET, 1, FIRM1_SIZE);
    if(!a9lhBoot || updatea9lh) sdmmc_nand_writesectors(0x96, 1, (vu8 *)SECTOR_OFFSET);
    writeFirm((u8 *)FIRM0_OFFSET, 0, FIRM0_SIZE);

    shutdown(2, a9lhBoot ? "Update: success!" : "Full install: success!");
}