int images_verify(Image* image) { uint8_t hash[0x40]; int retVal = 0; if(image == NULL) { return 1; } mtd_t *dev = images_device(); if(!dev) { return 1; } mtd_prepare(dev); if(!image->hashMatch) retVal |= 1 << 2; void* data = malloc(image->padded); mtd_read(dev, data, image->offset + sizeof(Img2Header), image->padded); calculateDataHash(data, image->padded, hash); free(data); if(memcmp(hash, image->dataHash, 0x40) != 0) retVal |= 1 << 3; mtd_finish(dev); return retVal; }
void images_write(Image* image, void* data, unsigned int length, int encrypt) { bufferPrintf("images_write(%x, %x, %x)\r\n", image, data, length); if(image == NULL) return; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); uint32_t padded = length; if((length & 0xF) != 0) { padded = (padded & ~0xF) + 0x10; } if(image->next != NULL && (image->offset + sizeof(Img2Header) + padded) >= image->next->offset) { bufferPrintf("**ABORTED** requested length greater than available space.\r\n"); return; } uint32_t totalLen = sizeof(Img2Header) + padded; uint8_t* writeBuffer = (uint8_t*) malloc(totalLen); mtd_read(dev, writeBuffer, image->offset, sizeof(Img2Header)); memcpy(writeBuffer + sizeof(Img2Header), data, length); if(encrypt) aes_838_encrypt(writeBuffer + sizeof(Img2Header), padded, NULL); Img2Header* header = (Img2Header*) writeBuffer; header->dataLen = length; header->dataLenPadded = padded; calculateDataHash(writeBuffer + sizeof(Img2Header), padded, header->dataHash); uint32_t checksum = 0; crc32(&checksum, writeBuffer, 0x64); header->header_checksum = checksum; calculateHash(header, header->hash); bufferPrintf("mtd_write(0x%p, %x, %x, %x)\r\n", dev, writeBuffer, image->offset, totalLen); mtd_write(dev, writeBuffer, image->offset, totalLen); bufferPrintf("mtd_write(0x%p, %x, %x, %x) done\r\n", dev, writeBuffer, image->offset, totalLen); free(writeBuffer); mtd_finish(dev); images_release(); images_setup(); }
void images_from_template(Image* image, uint32_t type, int index, void* dataBuffer, unsigned int len, int encrypt) { if(image == NULL) return; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); uint32_t offset = MaxOffset + (SegmentSize - (MaxOffset % SegmentSize)); uint32_t padded = len; if((len & 0xF) != 0) { padded = (padded & ~0xF) + 0x10; } uint32_t totalLen = sizeof(Img2Header) + padded; uint8_t* buffer = (uint8_t*) malloc(totalLen); mtd_read(dev, buffer, image->offset, sizeof(Img2Header)); Img2Header* header = (Img2Header*) buffer; header->imageType = type; if(index >= 0) header->index = index; header->dataLen = len; header->dataLenPadded = padded; memcpy(buffer + sizeof(Img2Header), dataBuffer, len); if(encrypt) aes_838_encrypt(buffer + sizeof(Img2Header), padded, NULL); calculateDataHash(buffer + sizeof(Img2Header), image->padded, header->dataHash); uint32_t checksum = 0; crc32(&checksum, buffer, 0x64); header->header_checksum = checksum; calculateHash(header, header->hash); mtd_write(dev, buffer, offset, totalLen); free(buffer); mtd_finish(dev); images_release(); images_setup(); }
int syscfg_setup() { int i; SCfgEntry curEntry; uint32_t cursor; mtd_t *dev = syscfg_device(); if(!dev) return -1; mtd_prepare(dev); mtd_read(dev, &header, SCFG_LOCATION, sizeof(header)); if(header.magic != SCFG_MAGIC) { mtd_finish(dev); bufferPrintf("syscfg: cannot find readable syscfg partition!\r\n"); return -1; } bufferPrintf("syscfg: found version 0x%08x with %d entries using %d of %d bytes\r\n", header.version, header.entries, header.bytes_used, header.bytes_total); entries = (OIBSyscfgEntry*) malloc(sizeof(OIBSyscfgEntry) * header.entries); cursor = SCFG_LOCATION + sizeof(header); for(i = 0; i < header.entries; ++i) { mtd_read(dev, &curEntry, cursor, sizeof(curEntry)); if(curEntry.magic != CNTB_MAGIC) { entries[i].type = curEntry.magic; entries[i].size = 16; entries[i].data = (uint8_t*) malloc(16); memcpy(entries[i].data, curEntry.data, 16); } else { entries[i].type = curEntry.cntb.type; entries[i].size = curEntry.cntb.size; entries[i].data = (uint8_t*) malloc(curEntry.cntb.size); mtd_read(dev, entries[i].data, SCFG_LOCATION + curEntry.cntb.offset, curEntry.cntb.size); } cursor += sizeof(curEntry); } mtd_finish(dev); return 0; }
void images_duplicate(Image* image, uint32_t type, int index) { if(image == NULL) return; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); uint32_t offset = MaxOffset + (SegmentSize - (MaxOffset % SegmentSize)); uint32_t totalLen = sizeof(Img2Header) + image->padded; uint8_t* buffer = (uint8_t*) malloc(totalLen); mtd_read(dev, buffer, image->offset, totalLen); Img2Header* header = (Img2Header*) buffer; header->imageType = type; if(index >= 0) header->index = index; calculateDataHash(buffer + sizeof(Img2Header), image->padded, header->dataHash); uint32_t checksum = 0; crc32(&checksum, buffer, 0x64); header->header_checksum = checksum; calculateHash(header, header->hash); mtd_write(dev, buffer, offset, totalLen); free(buffer); mtd_finish(dev); images_release(); images_setup(); }
void images_append(void* data, int len) { mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); if(MaxOffset >= 0xfc000 || (MaxOffset + len) >= 0xfc000) { bufferPrintf("**ABORTED** Writing image of size %d at %x would overflow NOR!\r\n", len, MaxOffset); } else { mtd_write(dev, data, MaxOffset, len); // Destroy any following image if((MaxOffset + len) < 0xfc000) { uint8_t zero = 0; mtd_write(dev, &zero, MaxOffset + len, 1); } images_release(); images_setup(); } mtd_finish(dev); }
void images_uninstall(uint32_t _fourcc, uint32_t _unreplace) { ImageDataList* list = NULL; ImageDataList* cur = NULL; ImageDataList* oldImage = NULL; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); Image* curImage = imageList; while(curImage != NULL) { if(curImage->type != _fourcc) { if(cur == NULL) { list = cur = malloc(sizeof(ImageDataList)); } else { cur->next = malloc(sizeof(ImageDataList)); cur = cur->next; } bufferPrintf("Reading: "); print_fourcc(curImage->type); bufferPrintf(" (%d bytes)\r\n", curImage->padded); cur->type = curImage->type; cur->next = NULL; cur->data = malloc(curImage->padded); mtd_read(dev, cur->data, curImage->offset, curImage->padded); if(_fourcc != _unreplace && cur->type == _unreplace) { oldImage = cur; } } else { bufferPrintf("Skipping: "); print_fourcc(curImage->type); bufferPrintf(" (%d bytes)\r\n", curImage->padded); } curImage = curImage->next; } mtd_finish(dev); if(_fourcc != _unreplace && oldImage == NULL) { bufferPrintf("No openiBoot installation was found.\n"); while(list != NULL) { cur = list; list = list->next; free(cur->data); free(cur); } return; } oldImage->type = _fourcc; images_change_type(oldImage->data, _fourcc); images_rewind(); while(list != NULL) { cur = list; list = list->next; AppleImg3RootHeader* header = (AppleImg3RootHeader*) cur->data; bufferPrintf("Flashing: "); print_fourcc(cur->type); bufferPrintf(" (%x, %d bytes)\r\n", cur->data, header->base.size); images_append(cur->data, header->base.size); free(cur->data); free(cur); } bufferPrintf("Images uninstalled.\r\n"); images_release(); images_setup(); bufferPrintf("Uninstall complete.\r\n"); }
void images_install(void* newData, size_t newDataLen, uint32_t newFourcc, uint32_t replaceFourcc) { ImageDataList* list = NULL; ImageDataList* cur = NULL; ImageDataList* toReplace = NULL; ImageDataList* verify = NULL; int isReplace = (replaceFourcc != newFourcc) ? TRUE : FALSE; int isUpgrade = FALSE; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); Image* curImage = imageList; while(curImage != NULL) { if(cur == NULL) { list = cur = verify = malloc(sizeof(ImageDataList)); } else { cur->next = malloc(sizeof(ImageDataList)); cur = cur->next; } bufferPrintf("Reading: "); print_fourcc(curImage->type); bufferPrintf(" (%d bytes)\r\n", curImage->padded); cur->type = curImage->type; cur->next = NULL; cur->data = malloc(curImage->padded); mtd_read(dev, cur->data, curImage->offset, curImage->padded); if(isReplace && cur->type == replaceFourcc) { isUpgrade = TRUE; } else if(cur->type == newFourcc) { toReplace = cur; } curImage = curImage->next; } mtd_finish(dev); if(!isUpgrade) { bufferPrintf("Performing installation... (%d bytes)\r\n", newDataLen); ImageDataList* ibox = malloc(sizeof(ImageDataList)); ibox->type = replaceFourcc; ibox->data = toReplace->data; ibox->next = toReplace->next; toReplace->next = ibox; toReplace->data = images_inject_img3(toReplace->data, newData, newDataLen); images_change_type(ibox->data, ibox->type); } else { bufferPrintf("Performing upgrade... (%d bytes)\r\n", newDataLen); void* newIBoot = images_inject_img3(toReplace->data, newData, newDataLen); free(toReplace->data); toReplace->data = newIBoot; } //check for size and availability size_t newPaddedDataLen=0; size_t totalBytes=0; //if somebody can find how to get padded length for new ibot maybe this loop not needed while(verify != NULL) { cur = verify; verify = verify->next; AppleImg3RootHeader* header = (AppleImg3RootHeader*) cur->data; totalBytes += header->base.size; if(cur->type == newFourcc) { newPaddedDataLen = header->base.size; } } bufferPrintf("Total size to be written %d\r\n",totalBytes); if((ImagesStart + totalBytes) >= 0xfc000) { bufferPrintf("**ABORTED** Writing total image size: 0x%x, new ibot size: 0x%x at 0x%x would overflow NOR!\r\n", totalBytes, newPaddedDataLen,ImagesStart); images_rewind(); images_release(); images_setup(); return; } bufferPrintf("Flashing...\r\n"); images_rewind(); while(list != NULL) { cur = list; list = list->next; AppleImg3RootHeader* header = (AppleImg3RootHeader*) cur->data; bufferPrintf("Flashing: "); print_fourcc(cur->type); bufferPrintf(" (%x, %d bytes)\r\n", cur->data, header->base.size); images_append(cur->data, header->base.size); free(cur->data); free(cur); } bufferPrintf("Flashing Complete, Free space after flashing %d\r\n",0xfc000-MaxOffset); images_release(); images_setup(); //bufferPrintf("Configuring openiBoot settings...\r\n"); /*#ifndef CONFIG_S5L8720 //TODO: add this back in once FTL is up and running Volume* volume; io_func* io; io = bdev_open(0); volume = openVolume(io); char buffer [sizeof(XSTRINGIFY(OPENIBOOT_VERSION))]; strcpy(buffer, XSTRINGIFY(OPENIBOOT_VERSION)); add_hfs(volume, (uint8_t*)buffer, sizeof(buffer), "/openiboot"); closeVolume(volume); CLOSE(io); ftl_sync(); #endif*/ // TODO: This is broken now, move into menu.c for next release -- Ricky26 /* if(!nvram_getvar("opib-temp-os")) { nvram_setvar("opib-temp-os", "0"); } if(!nvram_getvar("opib-default-os")) { nvram_setvar("opib-default-os", "1"); } if(!nvram_getvar("opib-menu-timeout")) { nvram_setvar("opib-menu-timeout", "10000"); } nvram_save();*/ // TODO: The defaults should NOT be written to NVRAM. -- Ricky26 //bufferPrintf("openiBoot installation complete.\r\n"); }
unsigned int images_read(Image* image, void** data) { if(image == NULL) { *data = NULL; return 0; } mtd_t *dev = images_device(); if(!dev) { *data = NULL; return 0; } mtd_prepare(dev); *data = malloc(image->padded); if(!IsImg3) { mtd_read(dev, *data, image->offset + sizeof(Img2Header), image->length); aes_838_decrypt(*data, image->length, NULL); mtd_finish(dev); return image->length; } else { mtd_read(dev, *data, image->offset, image->padded); uint32_t dataOffset = 0; uint32_t dataLength = 0; uint32_t kbagOffset = 0; uint32_t kbagLength = 0; uint32_t offset = (uint32_t)(*data + sizeof(AppleImg3RootHeader)); while((offset - (uint32_t)(*data + sizeof(AppleImg3RootHeader))) < image->length) { AppleImg3Header* header = (AppleImg3Header*) offset; if(header->magic == IMG3_DATA_MAGIC) { dataOffset = offset + sizeof(AppleImg3Header); dataLength = header->dataSize; } if(header->magic == IMG3_KBAG_MAGIC) { kbagOffset = offset + sizeof(AppleImg3Header); kbagLength = header->dataSize; } offset += header->size; } AppleImg3KBAGHeader* kbag = (AppleImg3KBAGHeader*) kbagOffset; if(kbag != 0) { if(kbag->key_modifier == 1) { aes_decrypt((void*)(kbagOffset + sizeof(AppleImg3KBAGHeader)), 16 + (kbag->key_bits / 8), AESGID, NULL, 0, NULL); } AESKeyLen keyLen; switch(kbag->key_bits) { case 128: keyLen = AES128; break; case 192: keyLen = AES192; break; case 256: keyLen = AES256; break; default: keyLen = AES128; break; } aes_decrypt((void*)dataOffset, (dataLength / 16) * 16, AESCustom, (uint8_t*)(kbagOffset + sizeof(AppleImg3KBAGHeader) + 16), keyLen, (uint8_t*)(kbagOffset + sizeof(AppleImg3KBAGHeader))); } uint8_t* newBuf = malloc(dataLength); memcpy(newBuf, (void*)dataOffset, dataLength); free(*data); *data = newBuf; mtd_finish(dev); return dataLength; } }
int images_setup() { IMG2* header; Img2Header* curImg2; uint8_t hash[0x20]; mtd_t *dev = images_device(); if(!dev) return -1; mtd_prepare(dev); MaxOffset = 0; header = (IMG2*) malloc(sizeof(IMG2)); uint32_t IMG2Offset = 0x0; for(IMG2Offset = 0; IMG2Offset < NOREnd; IMG2Offset += 4096) { mtd_read(dev, header, IMG2Offset, sizeof(IMG2)); if(header->signature == IMG2Signature) { break; } } SegmentSize = header->segmentSize; ImagesStart = (header->imagesStart + header->dataStart) * SegmentSize; AppleImg3Header* img3Header = (AppleImg3Header*) malloc(sizeof(AppleImg3Header)); mtd_read(dev, img3Header, ImagesStart, sizeof(AppleImg3Header)); if(img3Header->magic == IMG3_MAGIC) { img3_setup(dev); mtd_finish(dev); free(img3Header); free(header); IsImg3 = TRUE; return 0; } else { free(img3Header); IsImg3 = FALSE; } curImg2 = (Img2Header*) malloc(sizeof(Img2Header)); Image* curImage = NULL; uint32_t curOffset; for(curOffset = ImagesStart; curOffset < NOREnd; curOffset += SegmentSize) { mtd_read(dev, curImg2, curOffset, sizeof(Img2Header)); if(curImg2->signature != Img2Signature) continue; uint32_t checksum = 0; crc32(&checksum, curImg2, 0x64); if(checksum != curImg2->header_checksum) { bufferPrintf("Checksum mismatch at %x\r\n", curOffset); continue; } if(curImage == NULL) { curImage = (Image*) malloc(sizeof(Image)); imageList = curImage; } else { curImage->next = (Image*) malloc(sizeof(Image)); curImage = curImage->next; } curImage->type = curImg2->imageType; curImage->offset = curOffset; curImage->length = curImg2->dataLen; curImage->padded = curImg2->dataLenPadded; curImage->index = curImg2->index; memcpy(curImage->dataHash, curImg2->dataHash, 0x40); calculateHash(curImg2, hash); if(memcmp(hash, curImg2->hash, 0x20) == 0) { curImage->hashMatch = TRUE; } else { curImage->hashMatch = FALSE; } curImage->next = NULL; if((curOffset + curImage->padded) > MaxOffset) { MaxOffset = curOffset + curImage->padded; } } free(curImg2); free(header); mtd_finish(dev); return 0; }