static int attrKeyWrite(off_t offset, BTKey* toWrite, io_func* io) { HFSPlusAttrKey* key; uint16_t keyLength; uint16_t nodeNameLength; int i; keyLength = toWrite->keyLength; key = (HFSPlusAttrKey*) malloc(keyLength); memcpy(key, toWrite, keyLength); nodeNameLength = key->name.length; FLIPENDIAN(key->keyLength); FLIPENDIAN(key->fileID); FLIPENDIAN(key->startBlock); FLIPENDIAN(key->name.length); for(i = 0; i < nodeNameLength; i++) { FLIPENDIAN(key->name.unicode[i]); } if(!WRITE(io, offset, keyLength, key)) return FALSE; free(key); return TRUE; }
static BTKey* attrKeyRead(off_t offset, io_func* io) { int i; HFSPlusAttrKey* key; key = (HFSPlusAttrKey*) malloc(sizeof(HFSPlusAttrKey)); if(!READ(io, offset, UNICODE_START, key)) return NULL; FLIPENDIAN(key->keyLength); FLIPENDIAN(key->fileID); FLIPENDIAN(key->startBlock); FLIPENDIAN(key->name.length); if(key->name.length > 254) { printf("Invalid xattr key at offset %x\n", offset); free(key); return NULL; } if(!READ(io, offset + UNICODE_START, key->name.length * sizeof(uint16_t), ((unsigned char *)key) + UNICODE_START)) return NULL; for(i = 0; i < key->name.length; i++) { FLIPENDIAN(key->name.unicode[i]); } return (BTKey*)key; }
uint8* decrypt_key(const char* filesystem, uint8* passphrase) { int i = 0; EVP_CIPHER_CTX ctx; uint8 data[0x30]; int outlen, tmplen = 0; FILE* fd = fopen(filesystem, "rb"); if (fd == NULL) { fprintf(stderr, "error opening file: %s", filesystem); return NULL; } uint8* buffer = (uint8*) malloc(BUF_SIZE); if(buffer == NULL) { fprintf(stderr, "unable to allocate memory\n"); fclose(fd); return NULL; } fread(buffer, 1, sizeof(encrcdsa_header), fd); uint32 blocks = 0; fread(&blocks, 1, sizeof(uint32), fd); FLIPENDIAN(blocks); fread(buffer, 1, sizeof(encrcdsa_block) * blocks, fd); fread(buffer, 1, 0x80, fd); uint32 skip = 0; fread(&skip, 1, sizeof(uint32), fd); FLIPENDIAN(skip); fread(buffer, 1, skip-3, fd); uint8* out = malloc(0x30); free(buffer); for (i = 0; i < 0x20; i++) { if (fread(data, 1, 0x30, fd) <= 0) { fprintf(stderr, "Error reading filesystem image"); free(out); return NULL; } if(data[0] == 0) break; EVP_CIPHER_CTX_init(&ctx); EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, passphrase, &passphrase[24]); EVP_DecryptUpdate(&ctx, out, &outlen, data, 0x30); if (EVP_DecryptFinal_ex(&ctx, out + outlen, &tmplen)) { return out; } fseek(fd, 0x238, SEEK_CUR); } fclose(fd); return out; }
void flipCompHeader(CompHeader* header) { FLIPENDIAN(header->signature); FLIPENDIAN(header->compression_type); FLIPENDIAN(header->checksum); FLIPENDIAN(header->length_uncompressed); FLIPENDIAN(header->length_compressed); }
static int catalogKeyWrite(off_t offset, BTKey* toWrite, io_func* io) { HFSPlusCatalogKey* key; uint16_t i; uint16_t keyLength; uint16_t nodeNameLength; keyLength = toWrite->keyLength + sizeof(uint16_t); key = (HFSPlusCatalogKey*) malloc(keyLength); memcpy(key, toWrite, keyLength); nodeNameLength = key->nodeName.length; FLIPENDIAN(key->keyLength); FLIPENDIAN(key->parentID); FLIPENDIAN(key->nodeName.length); for(i = 0; i < nodeNameLength; i++) { if(key->nodeName.unicode[i] == ':') /* ugly hack that iPhone seems to do */ key->nodeName.unicode[i] = '/'; FLIPENDIAN(key->nodeName.unicode[i]); } if(!WRITE(io, offset, keyLength, key)) return FALSE; free(key); return TRUE; }
void flipForkData(HFSPlusForkData* forkData) { FLIPENDIAN(forkData->logicalSize); FLIPENDIAN(forkData->clumpSize); FLIPENDIAN(forkData->totalBlocks); flipExtentRecord(&forkData->extents); }
static void flipCSumResource(unsigned char* data, char out) { CSumResource* cSum; cSum = (CSumResource*) data; FLIPENDIAN(cSum->version); FLIPENDIAN(cSum->type); FLIPENDIAN(cSum->checksum); }
void flipHFSPlusCmpfEnd(HFSPlusCmpfEnd* data) { FLIPENDIAN(data->unk1); FLIPENDIAN(data->unk2); FLIPENDIAN(data->unk3); FLIPENDIAN(data->magic); FLIPENDIAN(data->flags); FLIPENDIANLE(data->size); FLIPENDIANLE(data->unk4); }
static BTKey* extentKeyRead(off_t offset, io_func* io) { HFSPlusExtentKey* key; key = (HFSPlusExtentKey*) malloc(sizeof(HFSPlusExtentKey)); if(!READ(io, offset, sizeof(HFSPlusExtentKey), key)) return NULL; FLIPENDIAN(key->keyLength); FLIPENDIAN(key->forkType); FLIPENDIAN(key->fileID); FLIPENDIAN(key->startBlock); return (BTKey*)key; }
static void cacheChunk(FileVaultInfo* info, uint32_t chunk) { unsigned char buffer[info->blockSize]; unsigned char msgDigest[FILEVAULT_MSGDGST_LENGTH]; uint32_t msgDigestLen; if(chunk == info->curChunk) { return; } if(info->dirty) { writeChunk(info); } info->file->seek(info->file, chunk * info->blockSize + info->dataOffset); info->file->read(info->file, buffer, info->blockSize); info->curChunk = chunk; FLIPENDIAN(chunk); HMAC_Init_ex(&(info->hmacCTX), NULL, 0, NULL, NULL); HMAC_Update(&(info->hmacCTX), (unsigned char *) &chunk, sizeof(uint32_t)); HMAC_Final(&(info->hmacCTX), msgDigest, &msgDigestLen); AES_cbc_encrypt(buffer, info->chunk, info->blockSize, &(info->aesKey), msgDigest, AES_DECRYPT); }
AbstractFile* duplicateAbstractFile(AbstractFile* file, AbstractFile* backing) { uint32_t signatureBE; uint32_t signatureLE; AbstractFile* orig; if (!backing) { /* imagine that: createAbstractFileFromComp() fails, because of decompress_lzss() */ return NULL; } file->seek(file, 0); file->read(file, &signatureBE, sizeof(signatureBE)); signatureLE = signatureBE; FLIPENDIAN(signatureBE); FLIPENDIANLE(signatureLE); file->seek(file, 0); if(signatureLE == IMG2_SIGNATURE) { orig = createAbstractFileFromImg2(file); return duplicateAbstractFile(orig, duplicateImg2File(orig, backing)); } else if(signatureLE == IMG3_SIGNATURE) { orig = createAbstractFileFromImg3(file); return duplicateAbstractFile(orig, duplicateImg3File(orig, backing)); } else if(signatureBE == COMP_SIGNATURE) { orig = createAbstractFileFromComp(file); return duplicateAbstractFile(orig, duplicateCompFile(orig, backing)); } else { file->close(file); return backing; } }
AbstractFile *openAbstractFile(AbstractFile * file) { uint32_t signatureBE; uint32_t signatureLE; if (!file) return NULL; file->seek(file, 0); file->read(file, &signatureBE, sizeof(signatureBE)); signatureLE = signatureBE; FLIPENDIAN(signatureBE); FLIPENDIANLE(signatureLE); file->seek(file, 0); if (signatureBE == SIGNATURE_8900) { return openAbstractFile(createAbstractFileFrom8900(file)); } else if (signatureLE == IMG2_SIGNATURE) { return openAbstractFile(createAbstractFileFromImg2(file)); } else if (signatureLE == IMG3_SIGNATURE) { return openAbstractFile(createAbstractFileFromImg3(file)); } else if (signatureBE == COMP_SIGNATURE) { return openAbstractFile(createAbstractFileFromComp(file)); } else { return file; } }
void flipUDIFChecksum(UDIFChecksum* o, char out) { int i; FLIPENDIAN(o->type); if(out) { for(i = 0; i < o->size; i++) { FLIPENDIAN(o->data[i]); } FLIPENDIAN(o->size); } else { FLIPENDIAN(o->size); for(i = 0; i < o->size; i++) { FLIPENDIAN(o->data[i]); } } }
AbstractFile *duplicateAbstractFile2(AbstractFile * file, AbstractFile * backing, const unsigned int *key, const unsigned int *iv, AbstractFile * certificate) { uint32_t signatureBE; uint32_t signatureLE; AbstractFile *orig; AbstractFile *newFile; file->seek(file, 0); file->read(file, &signatureBE, sizeof(signatureBE)); signatureLE = signatureBE; FLIPENDIAN(signatureBE); FLIPENDIANLE(signatureLE); file->seek(file, 0); if (signatureBE == SIGNATURE_8900) { orig = createAbstractFileFrom8900(file); newFile = duplicate8900File(orig, backing); if (certificate != NULL) replaceCertificate8900(newFile, certificate); return duplicateAbstractFile(orig, newFile); } else if (signatureLE == IMG2_SIGNATURE) { orig = createAbstractFileFromImg2(file); return duplicateAbstractFile(orig, duplicateImg2File(orig, backing)); } else if (signatureLE == IMG3_SIGNATURE) { AbstractFile2 *newFile; AbstractFile2 *img3; img3 = (AbstractFile2 *) createAbstractFileFromImg3(file); if (key != NULL) img3->setKey(img3, key, iv); newFile = (AbstractFile2 *) duplicateImg3File((AbstractFile *) img3, backing); if (key != NULL) img3->setKey(newFile, key, iv); if (certificate != NULL) replaceCertificateImg3((AbstractFile *) newFile, certificate); return duplicateAbstractFile((AbstractFile *) img3, (AbstractFile *) newFile); } else if (signatureBE == COMP_SIGNATURE) { orig = createAbstractFileFromComp(file); return duplicateAbstractFile(orig, duplicateCompFile(orig, backing)); } else { file->close(file); return backing; } }
static int extentKeyWrite(off_t offset, BTKey* toWrite, io_func* io) { HFSPlusExtentKey* key; key = (HFSPlusExtentKey*) malloc(sizeof(HFSPlusExtentKey)); memcpy(key, toWrite, sizeof(HFSPlusExtentKey)); FLIPENDIAN(key->keyLength); FLIPENDIAN(key->forkType); FLIPENDIAN(key->fileID); FLIPENDIAN(key->startBlock); if(!WRITE(io, offset, sizeof(HFSPlusExtentKey), key)) return FALSE; free(key); return TRUE; }
static BTKey* catalogDataRead(off_t offset, io_func* io) { int16_t recordType; HFSPlusCatalogRecord* record; uint16_t nameLength; if(!READ(io, offset, sizeof(int16_t), &recordType)) return NULL; FLIPENDIAN(recordType); fflush(stdout); switch(recordType) { case kHFSPlusFolderRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogFolder)); if(!READ(io, offset, sizeof(HFSPlusCatalogFolder), record)) return NULL; flipCatalogFolder((HFSPlusCatalogFolder*)record); break; case kHFSPlusFileRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogFile)); if(!READ(io, offset, sizeof(HFSPlusCatalogFile), record)) return NULL; flipCatalogFile((HFSPlusCatalogFile*)record); break; case kHFSPlusFolderThreadRecord: case kHFSPlusFileThreadRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogThread)); if(!READ(io, offset + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), sizeof(uint16_t), &nameLength)) return NULL; FLIPENDIAN(nameLength); if(!READ(io, offset, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * nameLength), record)) return NULL; flipCatalogThread((HFSPlusCatalogThread*)record, FALSE); break; } return (BTKey*)record; }
void flipApple8900Header(Apple8900Header* header) { FLIPENDIAN(header->magic); FLIPENDIANLE(header->unknown1); FLIPENDIANLE(header->sizeOfData); FLIPENDIANLE(header->footerSignatureOffset); FLIPENDIANLE(header->footerCertOffset); FLIPENDIANLE(header->footerCertLen); FLIPENDIANLE(header->unknown2); FLIPENDIANLE(header->epoch); }
static void flipSizeResource(unsigned char* data, char out) { SizeResource* size; size = (SizeResource*) data; FLIPENDIAN(size->version); FLIPENDIAN(size->isHFS); FLIPENDIAN(size->unknown2); FLIPENDIAN(size->unknown3); FLIPENDIAN(size->volumeModified); FLIPENDIAN(size->unknown4); FLIPENDIAN(size->volumeSignature); FLIPENDIAN(size->sizePresent); }
void flipCatalogThread(HFSPlusCatalogThread* record, int out) { int i; int nameLength; FLIPENDIAN(record->recordType); FLIPENDIAN(record->parentID); if(out) { nameLength = record->nodeName.length; FLIPENDIAN(record->nodeName.length); } else { FLIPENDIAN(record->nodeName.length); nameLength = record->nodeName.length; } for(i = 0; i < nameLength; i++) { if(out) { if(record->nodeName.unicode[i] == ':') { record->nodeName.unicode[i] = '/'; } FLIPENDIAN(record->nodeName.unicode[i]); } else { FLIPENDIAN(record->nodeName.unicode[i]); if(record->nodeName.unicode[i] == '/') { record->nodeName.unicode[i] = ':'; } } } }
void flipCatalogFile(HFSPlusCatalogFile* record) { FLIPENDIAN(record->recordType); FLIPENDIAN(record->flags); FLIPENDIAN(record->fileID); FLIPENDIAN(record->createDate); FLIPENDIAN(record->contentModDate); FLIPENDIAN(record->attributeModDate); FLIPENDIAN(record->accessDate); FLIPENDIAN(record->backupDate); flipBSDInfo(&record->permissions); flipFileInfo(&record->userInfo); flipExtendedFileInfo(&record->finderInfo); FLIPENDIAN(record->textEncoding); flipForkData(&record->dataFork); flipForkData(&record->resourceFork); }
static void doPartialSHA1(unsigned char md[SHA_DIGEST_LENGTH], const unsigned char *toHashData, int toHashLength, DataValue *partialDigest) { const unsigned *q = (const unsigned *)partialDigest->value; unsigned v31 = q[0]; // XXX ASSERT(v31 == ecid->size == 64)? unsigned v32 = q[1]; SHA_CTX hashctx; memset(&hashctx, 0, sizeof(hashctx)); hashctx.h0 = q[2]; hashctx.h1 = q[3]; hashctx.h2 = q[4]; hashctx.h3 = q[5]; hashctx.h4 = q[6]; FLIPENDIAN(hashctx.h0); FLIPENDIAN(hashctx.h1); FLIPENDIAN(hashctx.h2); FLIPENDIAN(hashctx.h3); FLIPENDIAN(hashctx.h4); FLIPENDIANLE(v32); hashctx.Nl = 8 * v32 + 64; // XXX could this 64 be actually v31? SHA1_Update(&hashctx, toHashData, toHashLength); SHA1_Final(md, &hashctx); }
static BTKey* catalogKeyRead(off_t offset, io_func* io) { HFSPlusCatalogKey* key; uint16_t i; key = (HFSPlusCatalogKey*) malloc(sizeof(HFSPlusCatalogKey)); if(!READ(io, offset, UNICODE_START, key)) return NULL; FLIPENDIAN(key->keyLength); FLIPENDIAN(key->parentID); FLIPENDIAN(key->nodeName.length); if(!READ(io, offset + UNICODE_START, key->nodeName.length * sizeof(uint16_t), ((unsigned char *)key) + UNICODE_START)) return NULL; for(i = 0; i < key->nodeName.length; i++) { FLIPENDIAN(key->nodeName.unicode[i]); if(key->nodeName.unicode[i] == '/') /* ugly hack that iPhone seems to do */ key->nodeName.unicode[i] = ':'; } return (BTKey*)key; }
static void flipBLKXRun(BLKXRun* data) { BLKXRun* run; run = (BLKXRun*) data; FLIPENDIAN(run->type); FLIPENDIAN(run->reserved); FLIPENDIAN(run->sectorStart); FLIPENDIAN(run->sectorCount); FLIPENDIAN(run->compOffset); FLIPENDIAN(run->compLength); }
void replaceCertificateAbstractFile(AbstractFile* file, AbstractFile* certificate) { uint32_t signatureBE; uint32_t signatureLE; AbstractFile* f; file->seek(file, 0); file->read(file, &signatureBE, sizeof(signatureBE)); signatureLE = signatureBE; FLIPENDIAN(signatureBE); FLIPENDIANLE(signatureLE); file->seek(file, 0); if(signatureLE == IMG3_SIGNATURE) { f = createAbstractFileFromImg3(file); replaceCertificateImg3(f, certificate); f->close(f); } }
AbstractFile *openAbstractFile3(AbstractFile * file, const unsigned int *key, const unsigned int *iv, int layers) { uint32_t signatureBE; uint32_t signatureLE; AbstractFile *cur; if (!file) return NULL; file->seek(file, 0); file->read(file, &signatureBE, sizeof(signatureBE)); signatureLE = signatureBE; FLIPENDIAN(signatureBE); FLIPENDIANLE(signatureLE); file->seek(file, 0); if (signatureBE == SIGNATURE_8900) { cur = createAbstractFileFrom8900(file); } else if (signatureLE == IMG2_SIGNATURE) { cur = createAbstractFileFromImg2(file); } else if (signatureLE == IMG3_SIGNATURE) { AbstractFile2 *img3 = (AbstractFile2 *) createAbstractFileFromImg3(file); if (key && iv) img3->setKey(img3, key, iv); cur = (AbstractFile *) img3; key = NULL; iv = NULL; } else if (signatureBE == COMP_SIGNATURE) { cur = createAbstractFileFromComp(file); key = NULL; iv = NULL; } else { return file; } if (layers < 0 || layers > 0) return openAbstractFile3(cur, key, iv, layers - 1); else return cur; }
static BTKey* attrDataRead(off_t offset, io_func* io) { HFSPlusAttrRecord* record; record = (HFSPlusAttrRecord*) malloc(sizeof(HFSPlusAttrRecord)); if(!READ(io, offset, sizeof(uint32_t), record)) return NULL; FLIPENDIAN(record->recordType); switch(record->recordType) { case kHFSPlusAttrInlineData: if(!READ(io, offset, sizeof(HFSPlusAttrData), record)) return NULL; flipAttrData((HFSPlusAttrData*) record); record = realloc(record, sizeof(HFSPlusAttrData) + ((HFSPlusAttrData*) record)->size); if(!READ(io, offset + sizeof(HFSPlusAttrData), ((HFSPlusAttrData*) record)->size, ((HFSPlusAttrData*) record)->data)) return NULL; break; case kHFSPlusAttrForkData: if(!READ(io, offset, sizeof(HFSPlusAttrForkData), record)) return NULL; flipAttrForkData((HFSPlusAttrForkData*) record); break; case kHFSPlusAttrExtents: if(!READ(io, offset, sizeof(HFSPlusAttrExtents), record)) return NULL; flipAttrExtents((HFSPlusAttrExtents*) record); break; } return (BTKey*)record; }
static void writeChunk(FileVaultInfo* info) { unsigned char buffer[info->blockSize]; unsigned char buffer2[info->blockSize]; unsigned char msgDigest[FILEVAULT_MSGDGST_LENGTH]; uint32_t msgDigestLen; uint32_t myChunk; myChunk = info->curChunk; FLIPENDIAN(myChunk); HMAC_Init_ex(&(info->hmacCTX), NULL, 0, NULL, NULL); HMAC_Update(&(info->hmacCTX), (unsigned char *) &myChunk, sizeof(uint32_t)); HMAC_Final(&(info->hmacCTX), msgDigest, &msgDigestLen); AES_cbc_encrypt(info->chunk, buffer, info->blockSize, &(info->aesEncKey), msgDigest, AES_ENCRYPT); info->file->seek(info->file, (info->curChunk * info->blockSize) + info->dataOffset); info->file->read(info->file, buffer2, info->blockSize); info->file->seek(info->file, (info->curChunk * info->blockSize) + info->dataOffset); info->file->write(info->file, buffer, info->blockSize); info->dirty = FALSE; }
static inline void flipAttrForkData(HFSPlusAttrForkData* data) { FLIPENDIAN(data->recordType); flipForkData(&data->theFork); }
static inline void flipAttrData(HFSPlusAttrData* data) { FLIPENDIAN(data->recordType); FLIPENDIAN(data->size); }
static inline void flipAttrExtents(HFSPlusAttrExtents* data) { FLIPENDIAN(data->recordType); flipExtentRecord(&data->extents); }