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

iPod Touch 2G #5

Open
wants to merge 9 commits into
base: ipod_touch_2g
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "decryptor"]
path = decryptor
url = https://github.com/zoe-vb/8900decryptor
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Compile with:

`gcc generate_nor.c aes.c -o generate_nor -I/usr/local/Cellar/[email protected]/1.1.1l/include -L/usr/local/Cellar/[email protected]/1.1.1l/lib -lssl -lcrypto`
# Preparing a NOR file for iPod Touch 2G
### This process is different to the iPod Touch 1G because we now have LLB support! <br>
Copy all the files from Firmware/all_flash/all_flash.n72ap.production into the data folder <br>
Rename the files to look as below <br>
`recoverymode.img3, applelogo.img3, batterylow0.img3, batterylow1.img3, dtree.img3 (originally DeviceTree.n72ap), glyphcharging.img3, glyphplugin.img3, needservice.img3, iboot.img3 and llb.img3` <br>
Delete the other files that aren't mentioned <br>
Now due to the fact that A: Apple made the NOR contain encrypted img3 files and B: We have LLB now anyway which decrypts the images, we no longer have to worry about decrypting <i>most</i> of them. <br>
The only image that needs decrpyting is the LLB image. To do this please use the fork of xpwn found in the `main` branch and follow the instructions to build it in the `README` for said branch <br>
Run `xpwntool llb.img3 llb_out.img3 -k 27732a6bbfb14a07250a2e4682bf3cba -iv ce97a7c82ef864675ed3680597ec2aef` <br>
Now compile `generate_nor` as described in the `main` branch. And run `./generate_nor` <br>
This leaves you with a NOR image.
Binary file removed data/DeviceTree.n45ap
Binary file not shown.
Binary file removed data/applelogo
Binary file not shown.
Binary file removed data/batterycharging
Binary file not shown.
Binary file removed data/batterylow0
Binary file not shown.
Binary file removed data/batterylow1
Binary file not shown.
Binary file removed data/needservice
Binary file not shown.
Binary file removed data/recoverymode
Binary file not shown.
174 changes: 106 additions & 68 deletions generate_nor.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
#include <stdlib.h>
#include <sys/types.h>
#include <stdint.h>
#include <math.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include "aes.h"

#define NOR_SIZE 1024 * 1024
#define NOR_BLOCK_SIZE 0x40
#define NOR_BLOCK_SIZE 64 // 64 bytes
#define NOR_SYSCFG_HEADER_OFFSET 0x4000
#define NOR_IMG_HEADER_OFFSET 0x8400
#define NOR_IMG_SECTION_OFFSET 1040 // in blocks
#define NOR_IMG_HEADER_OFFSET 0x200
#define NOR_IMG_SECTION_OFFSET 0x0 // in blocks

#define NUM_SYSCFG_ENTRIES 4

Expand All @@ -29,6 +31,8 @@ static const uint8_t Img2HashPadding[] = { 0xAD, 0x2E, 0xE3, 0x8D, 0x2D, 0x9B,
static uint32_t crc32_table[256];
static int crc32_table_computed = 0;

#define key_uid ((uint8_t[]){0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF})

typedef struct nor_header {
uint32_t fourcc;
uint32_t block_size;
Expand Down Expand Up @@ -60,6 +64,12 @@ typedef struct Img2Header {
uint8_t hash[0x20];
} Img2Header;

typedef struct Img3Header {
uint32_t magic;
uint32_t size;
uint32_t dataSize;
} Img3Header;

typedef struct SyscfgHeader {
uint32_t shMagic;
uint32_t shSize;
Expand All @@ -74,10 +84,13 @@ typedef struct SyscfgEntry {
char seData[16];
} SyscfgEntry;

SyscfgEntry syscfg_entries[NUM_SYSCFG_ENTRIES] = { {'Mod#', "MA623" },
SyscfgEntry syscfg_entries[NUM_SYSCFG_ENTRIES] = { {'Mod#', "MB528" },
{'Regn', "B/LL" },
{'SrNm', "ABCDEFG" },
{'Batt', "690476146348"}};
{'SrNm', "1A8478BH203" },
{'Batt', "690476146348"},
//{'WMac', "00:23:32:6E:AA:10"},
//{'BMac', "00:23:32:6B:38:E2"}
};

typedef struct chrp_nvram_header {
uint8_t sig;
Expand Down Expand Up @@ -218,8 +231,8 @@ static void calculate_img2_hash(Img2Header *header, uint8_t* hash) {
aes_img2verify_encrypt(hash, 32, NULL);
}

void add_img2(void *nor, char *filename, int *cur_block_ind) {
printf("Adding IMG2 %s\n", filename);
void add_img3(void *nor, char *filename, int *cur_block_ind) {
printf("Adding IMG3 %s\n", filename);
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
Expand All @@ -228,41 +241,58 @@ void add_img2(void *nor, char *filename, int *cur_block_ind) {
char *imgdata = malloc(fsize);
fread(imgdata, 1, fsize, f);
fclose(f);

// modify header
printf("Raw IMG2 length (in bytes): %ld\n", fsize);
int img_length_in_blocks = (fsize / NOR_BLOCK_SIZE) + 5;
Img2Header *img_header = (Img2Header *)imgdata;
img_header->length_in_blocks = img_length_in_blocks;
img_header->flags2 |= (1 << 24); // this bit needs to be set to indicate a trusted write
img_header->flags2 |= (1 << 1); // this bit needs to be set to indicate that the content is encrypted
printf("--- IMG2 info ---\n");
printf("Data length: %d (padded: %d)\n", img_header->dataLen, img_header->dataLenPadded);
printf("Flags: 0x%0x8\n", img_header->flags2);
int img_length_in_blocks = ceil((float)fsize / (float)NOR_BLOCK_SIZE);
printf("Raw IMG3 length (in bytes): %ld, in blocks: %ld\n", fsize, img_length_in_blocks);
Img3Header *img_header = (Img3Header *)imgdata;
printf("--- IMG3 info ---\n");
printf("Data length: %d (padded: %d)\n", img_header->size, img_header->dataSize);
printf("\n");

uint32_t *databuf = malloc(img_header->dataLenPadded);
memcpy((void *)databuf, imgdata + sizeof(Img2Header), img_header->dataLenPadded);

// calculate data hash
calculate_img2_data_hash(databuf, img_header->dataLenPadded, img_header->data_hash);

// calculate CRC32 code of header
img_header->header_checksum = crc32((uint8_t *)img_header, 0x64);
if(img_header->flags2 & (1 << 30))
{
printf("Extension found with size %d and options 0x%0x8\n", img_header->next_size, img_header->extension_options);
uint8_t *buf = malloc(img_header->next_size);
memcpy(buf, (uint8_t*)img_header + 0x6c, img_header->next_size);
img_header->extension_checksum = crc32(buf, img_header->next_size);
img_header->size = img_length_in_blocks * NOR_BLOCK_SIZE; // the images should be aligned to a block

// If we're adding the iBoot image, we have to encrypt the signed hash
if(strcmp(filename, "data/iboot.img3") == 0) {
printf("Encrypting hash...\n");
unsigned char derivedSeed[16] = {0xdb, 0x1f, 0x5b, 0x33, 0x60, 0x6c, 0x5f, 0x1c, 0x19, 0x34, 0xaa, 0x66, 0x58, 0x9c, 0x06, 0x61};
unsigned char derivedKey[16];

/* derive the key */
AES_KEY encryptKey, decryptKey;
AES_set_decrypt_key(key_uid, sizeof(key_uid) * 8, &encryptKey);
uint8_t ivec[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
AES_cbc_encrypt(derivedSeed, derivedKey, 16, &encryptKey, &ivec, AES_DECRYPT);

printf("Derived key: 0x");
for(int i = 0; i < 16; i++) { printf("%02x", derivedKey[i]); }
printf("\n");

printf("Plaintext hash: 0x");
for(int i = 0; i < 128; i++) { printf("%02x", ((uint8_t *)imgdata)[168108 + i]); }
printf("\n");

// encrypt the signature using the derived key
AES_set_encrypt_key(derivedKey, sizeof(key_uid) * 8, &encryptKey);
uint8_t ivec2[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
uint8_t res[128];
AES_cbc_encrypt(&imgdata[168108], &imgdata[168108], 0x80, &encryptKey, &ivec2, AES_ENCRYPT);

printf("Encrypted hash: 0x");
for(int i = 0; i < 128; i++) { printf("%02x", ((uint8_t *)imgdata)[168108 + i]); }
printf("\n");

// // decrypt again
// AES_set_decrypt_key(derivedKey, sizeof(key_uid) * 8, &decryptKey);
// uint8_t res2[128];
// uint8_t ivec3[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
// AES_cbc_encrypt(&imgdata[168108], &imgdata[168108], 0x80, &decryptKey, &ivec3, AES_DECRYPT);

// printf("Decrypted hash: 0x");
// for(int i = 0; i < 128; i++) { printf("%02x", ((uint8_t *)imgdata)[168108 + i]); }
// printf("\n");
}

// calculate header hash
uint8_t header_hash[0x20];
calculate_img2_hash(img_header, header_hash);

memcpy(&img_header->hash, &header_hash, 0x20);

// copy image
uint32_t img_section_offset = NOR_IMG_SECTION_OFFSET * NOR_BLOCK_SIZE;
uint32_t addr_offset = img_section_offset + *cur_block_ind * NOR_BLOCK_SIZE;
printf("Copying image to address 0x%08x\n", addr_offset);
Expand All @@ -271,25 +301,33 @@ void add_img2(void *nor, char *filename, int *cur_block_ind) {
printf("\n");
}

void setup_img2_partition(void *nor) {
void setup_nor_partition(void *nor) {
// prepare the header
nor_header *header = malloc(sizeof(nor_header));
header->fourcc = 0x494d4732; // 2GMI
header->block_size = NOR_BLOCK_SIZE;
header->img_section_offset = NOR_IMG_SECTION_OFFSET;
header->img_section_len = 512 * 1024; // TODO hard-coded
header->checksum = crc32((uint8_t *)header, 0x30);
memcpy(nor + NOR_IMG_HEADER_OFFSET, header, sizeof(nor_header));
header->img_section_blk_location = NOR_IMG_HEADER_OFFSET;

// add IMG2 images
int cur_block_ind = 0; // the current block index, counted from the img2 partition start
add_img2(nor, "data/DeviceTree.n45ap", &cur_block_ind);
add_img2(nor, "data/batterycharging", &cur_block_ind);
add_img2(nor, "data/applelogo", &cur_block_ind);
add_img2(nor, "data/needservice", &cur_block_ind);
add_img2(nor, "data/batterylow0", &cur_block_ind);
add_img2(nor, "data/batterylow1", &cur_block_ind);
add_img2(nor, "data/recoverymode", &cur_block_ind);
// add IMG3 images
int cur_block_ind = NOR_IMG_HEADER_OFFSET; // the current block index, counted from the img2 partition start
add_img3(nor, "data/llb.img3", &cur_block_ind);
add_img3(nor, "data/iboot.img3", &cur_block_ind);
add_img3(nor, "data/dtree.img3", &cur_block_ind);
add_img3(nor, "data/applelogo.img3", &cur_block_ind);
add_img3(nor, "data/needservice.img3", &cur_block_ind);
add_img3(nor, "data/batterylow0.img3", &cur_block_ind);
add_img3(nor, "data/batterylow1.img3", &cur_block_ind);
//add_img3(nor, 'data/batterycharging0.img3", &cur_block_ind);
//add_img3(nor, 'data/batterycharging1.img3", &cur_block_ind);
//add_img3(nor, 'data/batteryfull.img3", &cur_block_ind);
add_img3(nor, "data/recoverymode.img3", &cur_block_ind);
add_img3(nor, "data/glyphcharging.img3", &cur_block_ind);
add_img3(nor, "data/glyphplugin.img3", &cur_block_ind);

header->img_section_len = cur_block_ind; // TODO hard-coded
header->checksum = crc32((uint8_t *)header, 0x30);
memcpy(nor, header, sizeof(nor_header));
}

int main(int argc, char *argv[]) {
Expand All @@ -300,21 +338,21 @@ int main(int argc, char *argv[]) {
void *nor = malloc(NOR_SIZE);
memset(nor, 0x0, NOR_SIZE);

setup_img2_partition(nor);

// prepare syscfg
SyscfgHeader *syscfg_header = malloc(sizeof(SyscfgHeader));
syscfg_header->shMagic = 'SCfg';
syscfg_header->maxSize = 0x2000;
syscfg_header->version = 0x00010001;
syscfg_header->shSize = 200;
syscfg_header->keyCount = NUM_SYSCFG_ENTRIES;
memcpy(nor + NOR_SYSCFG_HEADER_OFFSET, syscfg_header, sizeof(SyscfgHeader));

// write syscfg entries
for(int index = 0; index < NUM_SYSCFG_ENTRIES; index++) {
memcpy(nor + NOR_SYSCFG_HEADER_OFFSET + sizeof(SyscfgHeader) + sizeof(SyscfgEntry) * index, &syscfg_entries[index], sizeof(SyscfgEntry));
}
setup_nor_partition(nor);

// // prepare syscfg
// SyscfgHeader *syscfg_header = malloc(sizeof(SyscfgHeader));
// syscfg_header->shMagic = 'SCfg';
// syscfg_header->maxSize = 0x2000;
// syscfg_header->version = 0x00010001;
// syscfg_header->shSize = 200;
// syscfg_header->keyCount = NUM_SYSCFG_ENTRIES;
// memcpy(nor + NOR_SYSCFG_HEADER_OFFSET, syscfg_header, sizeof(SyscfgHeader));

// // write syscfg entries
// for(int index = 0; index < NUM_SYSCFG_ENTRIES; index++) {
// memcpy(nor + NOR_SYSCFG_HEADER_OFFSET + sizeof(SyscfgHeader) + sizeof(SyscfgEntry) * index, &syscfg_entries[index], sizeof(SyscfgEntry));
// }

// prepare NVRAM
printf("Preparing NVRAM...\n");
Expand All @@ -330,7 +368,7 @@ int main(int argc, char *argv[]) {

// create "common" partition with env variables
chrp_nvram_header *partition_header = (chrp_nvram_header *)(nvram_data + sizeof(apple_nvram_header));
char *env = "boot-args=debug=0x8 kextlog=0xfff cpus=1 rd=disk0s1 serial=1 io=0xffff8fff";
char *env = "debug-uarts=3";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that the boot args in the NOR are useless for the IT2G so I think this line can be removed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that can be removed. I have noticed however that boot-args="" appears in the actual NOR of the device. (It is empty however)

memcpy(partition_header->data, env, strlen(env) + 1);
partition_header->sig = 0x70;
partition_header->len = 0x80;
Expand Down