diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..3364ec1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "decryptor"]
+ path = decryptor
+ url = https://github.com/zoe-vb/8900decryptor
diff --git a/README.md b/README.md
index 4e1961f..c3ef94d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
-Compile with:
-
-`gcc generate_nor.c aes.c -o generate_nor -I/usr/local/Cellar/openssl@1.1/1.1.1l/include -L/usr/local/Cellar/openssl@1.1/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!
+Copy all the files from Firmware/all_flash/all_flash.n72ap.production into the data folder
+Rename the files to look as below
+`recoverymode.img3, applelogo.img3, batterylow0.img3, batterylow1.img3, dtree.img3 (originally DeviceTree.n72ap), glyphcharging.img3, glyphplugin.img3, needservice.img3, iboot.img3 and llb.img3`
+Delete the other files that aren't mentioned
+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
+Now compile `generate_nor` as described in the `main` branch. And run `./generate_nor`
+This leaves you with a NOR image.
diff --git a/data/DeviceTree.n45ap b/data/DeviceTree.n45ap
deleted file mode 100755
index 47e8e81..0000000
Binary files a/data/DeviceTree.n45ap and /dev/null differ
diff --git a/data/applelogo b/data/applelogo
deleted file mode 100755
index 0269957..0000000
Binary files a/data/applelogo and /dev/null differ
diff --git a/data/batterycharging b/data/batterycharging
deleted file mode 100755
index 1d06560..0000000
Binary files a/data/batterycharging and /dev/null differ
diff --git a/data/batterylow0 b/data/batterylow0
deleted file mode 100755
index b2e0385..0000000
Binary files a/data/batterylow0 and /dev/null differ
diff --git a/data/batterylow1 b/data/batterylow1
deleted file mode 100755
index e88e63f..0000000
Binary files a/data/batterylow1 and /dev/null differ
diff --git a/data/needservice b/data/needservice
deleted file mode 100755
index f6087f6..0000000
Binary files a/data/needservice and /dev/null differ
diff --git a/data/recoverymode b/data/recoverymode
deleted file mode 100755
index ff6b2d9..0000000
Binary files a/data/recoverymode and /dev/null differ
diff --git a/generate_nor.c b/generate_nor.c
index 7a1b840..c551203 100755
--- a/generate_nor.c
+++ b/generate_nor.c
@@ -3,14 +3,16 @@
#include
#include
#include
+#include
+#include
#include
#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
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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[]) {
@@ -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");
@@ -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";
memcpy(partition_header->data, env, strlen(env) + 1);
partition_header->sig = 0x70;
partition_header->len = 0x80;