Tinkered with valgrind, the makefiles, and enabled using filevault encrypted files as a backing source for dmg actions, so you can decrypt and extract at the same time
This commit is contained in:
Родитель
b9fef5d9a8
Коммит
4b0f0db508
|
@ -0,0 +1,19 @@
|
|||
all: hfs dmg
|
||||
|
||||
dmg: dmg/dmg
|
||||
|
||||
hfs: hfs/hfsplus
|
||||
|
||||
dmg/dmg:
|
||||
cd dmg; make
|
||||
|
||||
hfs/hfsplus:
|
||||
cd hfs; make
|
||||
|
||||
clean:
|
||||
cd dmg; make clean
|
||||
cd hfs; make clean
|
||||
|
||||
dist-clean: clean
|
||||
-cd dmg/zlib-1.2.3; make clean
|
||||
-rm dmg/zlib-1.2.3/Makefile
|
19
dmg/Makefile
19
dmg/Makefile
|
@ -1,15 +1,22 @@
|
|||
DMGOBJS=dmg.o base64.o resources.o checksum.o udif.o partition.o io.o abstractfile.o zlib-1.2.3/libz.a
|
||||
DMGOBJS=dmg.o base64.o resources.o checksum.o udif.o partition.o io.o abstractfile.o filevault.o zlib-1.2.3/libz.a
|
||||
HFSOBJS=../hfs/volume.o ../hfs/btree.o ../hfs/extents.o ../hfs/rawfile.o ../hfs/catalog.o ../hfs/flatfile.o ../hfs/utility.o
|
||||
CFLAGS=-D_FILE_OFFSET_BITS=64
|
||||
CFLAGS=-D_FILE_OFFSET_BITS=64 -DHAVE_CRYPT
|
||||
LIBRARIES=-lcrypto
|
||||
|
||||
all: dmg
|
||||
|
||||
dmg: $(DMGOBJS) $(HFSOBJS)
|
||||
$(CC) $(CFLAGS) $(DMGOBJS) $(HFSOBJS) -o dmg
|
||||
$(CC) $(CFLAGS) $(DMGOBJS) $(HFSOBJS) $(LIBRARIES) -o dmg
|
||||
|
||||
%.o: %.c dmg.h
|
||||
%.o: %.c dmg.h filevault.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
zlib-1.2.3/Makefile:
|
||||
cd zlib-1.2.3; ./configure
|
||||
|
||||
zlib-1.2.3/libz.a: zlib-1.2.3/Makefile
|
||||
cd zlib-1.2.3; make
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
rm dmg
|
||||
-rm *.o
|
||||
-rm dmg
|
||||
|
|
|
@ -165,3 +165,45 @@ void abstractFilePrint(AbstractFile* file, const char* format, ...) {
|
|||
va_end(args);
|
||||
ASSERT(file->write(file, buffer, length) == length, "fwrite");
|
||||
}
|
||||
|
||||
int absFileRead(io_func* io, off_t location, size_t size, void *buffer) {
|
||||
AbstractFile* file;
|
||||
file = (AbstractFile*) io->data;
|
||||
file->seek(file, location);
|
||||
if(file->read(file, buffer, size) == size) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int absFileWrite(io_func* io, off_t location, size_t size, void *buffer) {
|
||||
AbstractFile* file;
|
||||
file = (AbstractFile*) io->data;
|
||||
file->seek(file, location);
|
||||
if(file->write(file, buffer, size) == size) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void closeAbsFile(io_func* io) {
|
||||
AbstractFile* file;
|
||||
file = (AbstractFile*) io->data;
|
||||
file->close(file);
|
||||
free(io);
|
||||
}
|
||||
|
||||
|
||||
io_func* IOFuncFromAbstractFile(AbstractFile* file) {
|
||||
io_func* io;
|
||||
|
||||
io = (io_func*) malloc(sizeof(io_func));
|
||||
io->data = file;
|
||||
io->read = &absFileRead;
|
||||
io->write = &absFileWrite;
|
||||
io->close = &closeAbsFile;
|
||||
|
||||
return io;
|
||||
}
|
||||
|
|
118
dmg/dmg.c
118
dmg/dmg.c
|
@ -4,6 +4,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "dmg.h"
|
||||
#include "filevault.h"
|
||||
|
||||
char endianness;
|
||||
|
||||
|
@ -55,10 +56,7 @@ uint32_t calculateMasterChecksum(ResourceKey* resources) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int buildDmg(const char* source, const char* dest) {
|
||||
AbstractFile* abstractOut;
|
||||
AbstractFile* abstractIn;
|
||||
|
||||
int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
|
||||
io_func* io;
|
||||
Volume* volume;
|
||||
|
||||
|
@ -84,13 +82,11 @@ int buildDmg(const char* source, const char* dest) {
|
|||
uint32_t plistSize;
|
||||
uint32_t dataForkChecksum;
|
||||
|
||||
io = openFlatFileRO(source);
|
||||
io = IOFuncFromAbstractFile(abstractIn);
|
||||
volume = openVolume(io);
|
||||
volumeHeader = volume->volumeHeader;
|
||||
|
||||
abstractIn = createAbstractFileFromFile(fopen(source, "rb"));
|
||||
abstractOut = createAbstractFileFromFile(fopen(dest, "wb"));
|
||||
|
||||
|
||||
if(volumeHeader->signature != HFSX_SIGNATURE) {
|
||||
printf("Warning: ASR data only reverse engineered for case-sensitive HFS+ volumes\n");fflush(stdout);
|
||||
}
|
||||
|
@ -227,7 +223,6 @@ int buildDmg(const char* source, const char* dest) {
|
|||
releaseResources(resources);
|
||||
|
||||
abstractOut->close(abstractOut);
|
||||
abstractIn->close(abstractIn);
|
||||
closeVolume(volume);
|
||||
CLOSE(io);
|
||||
|
||||
|
@ -236,9 +231,7 @@ int buildDmg(const char* source, const char* dest) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
int convertToDMG(const char* source, const char* dest) {
|
||||
AbstractFile* abstractIn;
|
||||
AbstractFile* abstractOut;
|
||||
int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut) {
|
||||
Partition* partitions;
|
||||
DriverDescriptorRecord* DDM;
|
||||
int i;
|
||||
|
@ -276,9 +269,6 @@ int convertToDMG(const char* source, const char* dest) {
|
|||
|
||||
partitions = (Partition*) malloc(SECTOR_SIZE);
|
||||
|
||||
ASSERT(abstractIn = createAbstractFileFromFile(fopen(source, "rb")), "fopen");
|
||||
ASSERT(abstractOut = createAbstractFileFromFile(fopen(dest, "wb")), "fopen");
|
||||
|
||||
printf("Processing DDM...\n"); fflush(stdout);
|
||||
DDM = (DriverDescriptorRecord*) malloc(SECTOR_SIZE);
|
||||
abstractIn->seek(abstractIn, 0);
|
||||
|
@ -456,36 +446,18 @@ int convertToDMG(const char* source, const char* dest) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
int convertToISO(const char* source, const char* dest) {
|
||||
AbstractFile* abstractIn;
|
||||
AbstractFile* abstractOut;
|
||||
int convertToISO(AbstractFile* abstractIn, AbstractFile* abstractOut) {
|
||||
off_t fileLength;
|
||||
UDIFResourceFile resourceFile;
|
||||
ResourceKey* resources;
|
||||
ResourceData* blkx;
|
||||
BLKXTable* blkxTable;
|
||||
|
||||
abstractIn = createAbstractFileFromFile(fopen(source, "rb"));
|
||||
|
||||
if(!abstractIn) {
|
||||
fprintf(stderr, "Cannot open source file\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fileLength = abstractIn->getLength(abstractIn);
|
||||
abstractIn->seek(abstractIn, fileLength - sizeof(UDIFResourceFile));
|
||||
readUDIFResourceFile(abstractIn, &resourceFile);
|
||||
resources = readResources(abstractIn, &resourceFile);
|
||||
|
||||
abstractOut = createAbstractFileFromFile(fopen(dest, "wb"));
|
||||
if(!abstractOut ) {
|
||||
fprintf(stderr, "Cannot open target file\n");
|
||||
releaseResources(resources);
|
||||
|
||||
abstractIn->close(abstractIn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
blkx = (getResourceByKey(resources, "blkx"))->data;
|
||||
|
||||
printf("Writing out data..\n"); fflush(stdout);
|
||||
|
@ -506,35 +478,17 @@ int convertToISO(const char* source, const char* dest) {
|
|||
|
||||
}
|
||||
|
||||
int extractDmg(const char* source, const char* dest, int partNum) {
|
||||
AbstractFile* abstractIn;
|
||||
AbstractFile* abstractOut;
|
||||
int extractDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, int partNum) {
|
||||
off_t fileLength;
|
||||
UDIFResourceFile resourceFile;
|
||||
ResourceKey* resources;
|
||||
ResourceData* blkxData;
|
||||
|
||||
abstractIn = createAbstractFileFromFile(fopen(source, "rb"));
|
||||
|
||||
if(!abstractIn) {
|
||||
fprintf(stderr, "Cannot open source file\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
fileLength = abstractIn->getLength(abstractIn);
|
||||
abstractIn->seek(abstractIn, fileLength - sizeof(UDIFResourceFile));
|
||||
readUDIFResourceFile(abstractIn, &resourceFile);
|
||||
resources = readResources(abstractIn, &resourceFile);
|
||||
|
||||
abstractOut = createAbstractFileFromFile(fopen(dest, "wb"));
|
||||
if(!abstractOut) {
|
||||
fprintf(stderr, "Cannot open target file\n");
|
||||
releaseResources(resources);
|
||||
|
||||
abstractIn->close(abstractIn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
printf("Writing out data..\n"); fflush(stdout);
|
||||
|
||||
/* reasonable assumption that 2 is the main partition, given that that's usually the case in SPUD layouts */
|
||||
|
@ -552,29 +506,69 @@ int extractDmg(const char* source, const char* dest, int partNum) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
int buildInOut(const char* source, const char* dest, AbstractFile** in, AbstractFile** out) {
|
||||
*in = createAbstractFileFromFile(fopen(source, "rb"));
|
||||
if(!(*in)) {
|
||||
printf("cannot open source: %s\n", source);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out = createAbstractFileFromFile(fopen(dest, "wb"));
|
||||
if(!(*out)) {
|
||||
(*in)->close(*in);
|
||||
printf("cannot open destination: %s\n", dest);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int partNum;
|
||||
AbstractFile* in;
|
||||
AbstractFile* out;
|
||||
int index;
|
||||
int hasKey;
|
||||
|
||||
TestByteOrder();
|
||||
|
||||
if(argc < 4) {
|
||||
printf("usage: %s [extract <dmg> <img> (partition)|build <img> <dmg>]\n", argv[0]);
|
||||
printf("usage: %s [extract|build|iso|dmg] <in> <out> (-k <key>) (partition)\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!buildInOut(argv[2], argv[3], &in, &out)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hasKey = FALSE;
|
||||
if(argc > 5) {
|
||||
if(strcmp(argv[4], "-k") == 0) {
|
||||
in = createAbstractFileFromFileVault(in, argv[5]);
|
||||
hasKey = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(strcmp(argv[1], "extract") == 0) {
|
||||
partNum = 2;
|
||||
|
||||
if(argc > 4) {
|
||||
sscanf(argv[4], "%d", &partNum);
|
||||
if(hasKey) {
|
||||
if(argc > 6) {
|
||||
sscanf(argv[6], "%d", &partNum);
|
||||
}
|
||||
} else {
|
||||
if(argc > 4) {
|
||||
sscanf(argv[4], "%d", &partNum);
|
||||
}
|
||||
}
|
||||
extractDmg(argv[2], argv[3], partNum);
|
||||
extractDmg(in, out, partNum);
|
||||
} else if(strcmp(argv[1], "build") == 0) {
|
||||
buildDmg(argv[2], argv[3]);
|
||||
buildDmg(in, out);
|
||||
} else if(strcmp(argv[1], "iso") == 0) {
|
||||
convertToISO(argv[2], argv[3]);
|
||||
convertToISO(in, out);
|
||||
} else if(strcmp(argv[1], "dmg") == 0) {
|
||||
convertToDMG(argv[2], argv[3]);
|
||||
convertToDMG(in, out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
13
dmg/dmg.h
13
dmg/dmg.h
|
@ -1,3 +1,6 @@
|
|||
#ifndef DMG_H
|
||||
#define DMG_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -349,6 +352,7 @@ AbstractFile* createAbstractFileFromFile(FILE* file);
|
|||
AbstractFile* createAbstractFileFromDummy();
|
||||
AbstractFile* createAbstractFileFromMemory(void* buffer, size_t size);
|
||||
void abstractFilePrint(AbstractFile* file, const char* format, ...);
|
||||
io_func* IOFuncFromAbstractFile(AbstractFile* file);
|
||||
|
||||
void extractBLKX(AbstractFile* in, AbstractFile* out, BLKXTable* blkx);
|
||||
BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorNumber, uint32_t numSectors, uint32_t blocksDescriptor,
|
||||
|
@ -356,8 +360,9 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
|
|||
void* compressedChkToken, Volume* volume);
|
||||
|
||||
|
||||
int extractDmg(const char* source, const char* dest, int partNum);
|
||||
int buildDmg(const char* source, const char* dest);
|
||||
int convertToISO(const char* source, const char* dest);
|
||||
int convertToDMG(const char* source, const char* dest);
|
||||
int extractDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, int partNum);
|
||||
int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut);
|
||||
int convertToISO(AbstractFile* abstractIn, AbstractFile* abstractOut);
|
||||
int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dmg.h"
|
||||
#include "filevault.h"
|
||||
|
||||
#ifdef HAVE_CRYPT
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#define CHUNKNO(oft) ((uint32_t)((oft)/FILEVAULT_CHUNK_SIZE))
|
||||
#define CHUNKOFFSET(oft) ((size_t)((oft) - ((off_t)(CHUNKNO(oft)) * (off_t)FILEVAULT_CHUNK_SIZE)))
|
||||
#define CHUNKBEGIN(oft) C_OFFSET(CHUNKNO(oft))
|
||||
|
||||
|
||||
|
||||
static void flipFileVaultV2Header(FileVaultV2Header* header) {
|
||||
FLIPENDIAN(header->signature);
|
||||
FLIPENDIAN(header->version);
|
||||
FLIPENDIAN(header->encIVSize);
|
||||
FLIPENDIAN(header->unk1);
|
||||
FLIPENDIAN(header->unk2);
|
||||
FLIPENDIAN(header->unk3);
|
||||
FLIPENDIAN(header->unk4);
|
||||
FLIPENDIAN(header->unk5);
|
||||
FLIPENDIAN(header->unk5);
|
||||
|
||||
FLIPENDIAN(header->blockSize);
|
||||
FLIPENDIAN(header->dataSize);
|
||||
FLIPENDIAN(header->dataOffset);
|
||||
FLIPENDIAN(header->kdfAlgorithm);
|
||||
FLIPENDIAN(header->kdfPRNGAlgorithm);
|
||||
FLIPENDIAN(header->kdfIterationCount);
|
||||
FLIPENDIAN(header->kdfSaltLen);
|
||||
FLIPENDIAN(header->blobEncIVSize);
|
||||
FLIPENDIAN(header->blobEncKeyBits);
|
||||
FLIPENDIAN(header->blobEncAlgorithm);
|
||||
FLIPENDIAN(header->blobEncPadding);
|
||||
FLIPENDIAN(header->blobEncMode);
|
||||
FLIPENDIAN(header->encryptedKeyblobSize);
|
||||
}
|
||||
|
||||
static void writeChunk(FileVaultInfo* info) {
|
||||
unsigned char buffer[FILEVAULT_CHUNK_SIZE];
|
||||
unsigned char buffer2[FILEVAULT_CHUNK_SIZE];
|
||||
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), (void *) &myChunk, sizeof(uint32_t));
|
||||
HMAC_Final(&(info->hmacCTX), msgDigest, &msgDigestLen);
|
||||
|
||||
AES_cbc_encrypt(info->chunk, buffer, FILEVAULT_CHUNK_SIZE, &(info->aesEncKey), msgDigest, AES_ENCRYPT);
|
||||
|
||||
info->file->seek(info->file, (info->curChunk * FILEVAULT_CHUNK_SIZE) + info->header.v2.dataOffset);
|
||||
info->file->read(info->file, buffer2, FILEVAULT_CHUNK_SIZE);
|
||||
|
||||
info->file->seek(info->file, (info->curChunk * FILEVAULT_CHUNK_SIZE) + info->header.v2.dataOffset);
|
||||
info->file->write(info->file, buffer, FILEVAULT_CHUNK_SIZE);
|
||||
|
||||
info->dirty = FALSE;
|
||||
}
|
||||
|
||||
static void cacheChunk(FileVaultInfo* info, uint32_t chunk) {
|
||||
unsigned char buffer[FILEVAULT_CHUNK_SIZE];
|
||||
unsigned char buffer2[FILEVAULT_CHUNK_SIZE];
|
||||
unsigned char msgDigest[FILEVAULT_MSGDGST_LENGTH];
|
||||
unsigned char msgDigest2[FILEVAULT_MSGDGST_LENGTH];
|
||||
uint32_t msgDigestLen;
|
||||
|
||||
if(chunk == info->curChunk) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(info->dirty) {
|
||||
writeChunk(info);
|
||||
}
|
||||
|
||||
info->file->seek(info->file, chunk * FILEVAULT_CHUNK_SIZE + info->header.v2.dataOffset);
|
||||
info->file->read(info->file, buffer, FILEVAULT_CHUNK_SIZE);
|
||||
|
||||
info->curChunk = chunk;
|
||||
|
||||
FLIPENDIAN(chunk);
|
||||
HMAC_Init_ex(&(info->hmacCTX), NULL, 0, NULL, NULL);
|
||||
HMAC_Update(&(info->hmacCTX), (void *) &chunk, sizeof(uint32_t));
|
||||
HMAC_Final(&(info->hmacCTX), msgDigest, &msgDigestLen);
|
||||
|
||||
AES_cbc_encrypt(buffer, info->chunk, FILEVAULT_CHUNK_SIZE, &(info->aesKey), msgDigest, AES_DECRYPT);
|
||||
}
|
||||
|
||||
size_t fvRead(AbstractFile* file, void* data, size_t len) {
|
||||
size_t lengthInCurrentChunk;
|
||||
FileVaultInfo* info;
|
||||
size_t toRead;
|
||||
|
||||
info = (FileVaultInfo*) (file->data);
|
||||
|
||||
if((CHUNKOFFSET(info->offset) + len) > FILEVAULT_CHUNK_SIZE) {
|
||||
toRead = FILEVAULT_CHUNK_SIZE - CHUNKOFFSET(info->offset);
|
||||
memcpy(data, (void *)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset)), toRead);
|
||||
info->offset += toRead;
|
||||
cacheChunk(info, CHUNKNO(info->offset));
|
||||
return toRead + fvRead(file, (void *)((uint64_t)data + (uint64_t)toRead), len - toRead);
|
||||
} else {
|
||||
toRead = len;
|
||||
memcpy(data, (void *)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset)), toRead);
|
||||
info->offset += toRead;
|
||||
cacheChunk(info, CHUNKNO(info->offset));
|
||||
return toRead;
|
||||
}
|
||||
}
|
||||
|
||||
size_t fvWrite(AbstractFile* file, const void* data, size_t len) {
|
||||
size_t lengthInCurrentChunk;
|
||||
FileVaultInfo* info;
|
||||
size_t toRead;
|
||||
int i;
|
||||
|
||||
info = (FileVaultInfo*) (file->data);
|
||||
|
||||
if((CHUNKOFFSET(info->offset) + len) > FILEVAULT_CHUNK_SIZE) {
|
||||
toRead = FILEVAULT_CHUNK_SIZE - CHUNKOFFSET(info->offset);
|
||||
for(i = 0; i < toRead; i++) {
|
||||
ASSERT(*((char*)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset) + i)) == ((char*)data)[i], "blah");
|
||||
}
|
||||
memcpy((void *)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset)), data, toRead);
|
||||
info->dirty = TRUE;
|
||||
info->offset += toRead;
|
||||
cacheChunk(info, CHUNKNO(info->offset));
|
||||
return toRead + fvWrite(file, (void *)((uint64_t)data + (uint64_t)toRead), len - toRead);
|
||||
} else {
|
||||
toRead = len;
|
||||
for(i = 0; i < toRead; i++) {
|
||||
ASSERT(*((char*)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset) + i)) == ((char*)data)[i], "blah");
|
||||
}
|
||||
memcpy((void *)((uint64_t)(&(info->chunk)) + (uint64_t)CHUNKOFFSET(info->offset)), data, toRead);
|
||||
info->dirty = TRUE;
|
||||
info->offset += toRead;
|
||||
cacheChunk(info, CHUNKNO(info->offset));
|
||||
return toRead;
|
||||
}
|
||||
}
|
||||
|
||||
int fvSeek(AbstractFile* file, off_t offset) {
|
||||
FileVaultInfo* info = (FileVaultInfo*) (file->data);
|
||||
info->offset = offset;
|
||||
cacheChunk(info, CHUNKNO(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t fvTell(AbstractFile* file) {
|
||||
FileVaultInfo* info = (FileVaultInfo*) (file->data);
|
||||
return info->offset;
|
||||
}
|
||||
|
||||
off_t fvGetLength(AbstractFile* file) {
|
||||
FileVaultInfo* info = (FileVaultInfo*) (file->data);
|
||||
return info->header.v2.dataSize;
|
||||
}
|
||||
|
||||
void fvClose(AbstractFile* file) {
|
||||
FileVaultInfo* info = (FileVaultInfo*) (file->data);
|
||||
|
||||
/* force a flush */
|
||||
if(info->curChunk == 0) {
|
||||
cacheChunk(info, 1);
|
||||
} else {
|
||||
cacheChunk(info, 0);
|
||||
}
|
||||
|
||||
HMAC_CTX_cleanup(&(info->hmacCTX));
|
||||
|
||||
info->file->close(info->file);
|
||||
free(info);
|
||||
free(file);
|
||||
}
|
||||
|
||||
AbstractFile* createAbstractFileFromFileVault(AbstractFile* file, const char* key) {
|
||||
FileVaultInfo* info;
|
||||
AbstractFile* toReturn;
|
||||
uint64_t signature;
|
||||
uint8_t aesKey[16];
|
||||
uint8_t hmacKey[20];
|
||||
|
||||
int i;
|
||||
|
||||
file->seek(file, 0);
|
||||
file->read(file, &signature, sizeof(uint64_t));
|
||||
FLIPENDIAN(signature);
|
||||
if(signature != FILEVAULT_V2_SIGNATURE) {
|
||||
/* no FileVault v1 handling yet */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
toReturn = (AbstractFile*) malloc(sizeof(AbstractFile));
|
||||
info = (FileVaultInfo*) malloc(sizeof(FileVaultInfo));
|
||||
|
||||
file->seek(file, 0);
|
||||
file->read(file, &(info->header.v2), sizeof(FileVaultV2Header));
|
||||
flipFileVaultV2Header(&(info->header.v2));
|
||||
|
||||
for(i = 0; i < 16; i++) {
|
||||
sscanf(&(key[i * 2]), "%02hhx", &(aesKey[i]));
|
||||
}
|
||||
|
||||
for(i = 0; i < 20; i++) {
|
||||
sscanf(&(key[(16 * 2) + i * 2]), "%02hhx", &(hmacKey[i]));
|
||||
}
|
||||
|
||||
HMAC_CTX_init(&(info->hmacCTX));
|
||||
HMAC_Init_ex(&(info->hmacCTX), hmacKey, sizeof(hmacKey), EVP_sha1(), NULL);
|
||||
AES_set_decrypt_key(aesKey, FILEVAULT_CIPHER_KEY_LENGTH * 8, &(info->aesKey));
|
||||
AES_set_encrypt_key(aesKey, FILEVAULT_CIPHER_KEY_LENGTH * 8, &(info->aesEncKey));
|
||||
|
||||
info->offset = 0;
|
||||
info->file = file;
|
||||
|
||||
info->dirty = FALSE;
|
||||
info->curChunk = 1; /* just to set it to a value not 0 */
|
||||
cacheChunk(info, 0);
|
||||
|
||||
toReturn->data = info;
|
||||
toReturn->read = fvRead;
|
||||
toReturn->write = fvWrite;
|
||||
toReturn->seek = fvSeek;
|
||||
toReturn->tell = fvTell;
|
||||
toReturn->getLength = fvGetLength;
|
||||
toReturn->close = fvClose;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
AbstractFile* createAbstractFileFromFileVault(AbstractFile* file, const char* key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef FILEVAULT_H
|
||||
#define FILEVAULT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dmg.h"
|
||||
|
||||
#ifdef HAVE_CRYPT
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#define FILEVAULT_CIPHER_KEY_LENGTH 16
|
||||
#define FILEVAULT_CIPHER_BLOCKSIZE 16
|
||||
#define FILEVAULT_CHUNK_SIZE 4096
|
||||
#define FILEVAULT_PBKDF2_ITER_COUNT 1000
|
||||
#define FILEVAULT_MSGDGST_LENGTH 20
|
||||
|
||||
/*
|
||||
* Information about the FileVault format was yoinked from vfdecrypt, which was written by Ralf-Philipp Weinmann <ralf@coderpunks.org>,
|
||||
* Jacob Appelbaum <jacob@appelbaum.net>, and Christian Fromme <kaner@strace.org>
|
||||
*/
|
||||
|
||||
#define FILEVAULT_V2_SIGNATURE 0x656e637263647361
|
||||
|
||||
typedef struct FileVaultV1Header {
|
||||
uint8_t padding1[48];
|
||||
uint32_t kdfIterationCount;
|
||||
uint32_t kdfSaltLen;
|
||||
uint8_t kdfSalt[48];
|
||||
uint8_t unwrapIV[0x20];
|
||||
uint32_t wrappedAESKeyLen;
|
||||
uint8_t wrappedAESKey[296];
|
||||
uint32_t wrappedHMACSHA1KeyLen;
|
||||
uint8_t wrappedHMACSHA1Key[300];
|
||||
uint32_t integrityKeyLen;
|
||||
uint8_t integrityKey[48];
|
||||
uint8_t padding2[484];
|
||||
} __attribute__((__packed__)) FileVaultV1Header;
|
||||
|
||||
typedef struct FileVaultV2Header {
|
||||
uint64_t signature;
|
||||
uint32_t version;
|
||||
uint32_t encIVSize;
|
||||
uint32_t unk1;
|
||||
uint32_t unk2;
|
||||
uint32_t unk3;
|
||||
uint32_t unk4;
|
||||
uint32_t unk5;
|
||||
UDIFID uuid;
|
||||
uint32_t blockSize;
|
||||
uint64_t dataSize;
|
||||
uint64_t dataOffset;
|
||||
uint8_t padding[0x260];
|
||||
uint32_t kdfAlgorithm;
|
||||
uint32_t kdfPRNGAlgorithm;
|
||||
uint32_t kdfIterationCount;
|
||||
uint32_t kdfSaltLen;
|
||||
uint8_t kdfSalt[0x20];
|
||||
uint32_t blobEncIVSize;
|
||||
uint8_t blobEncIV[0x20];
|
||||
uint32_t blobEncKeyBits;
|
||||
uint32_t blobEncAlgorithm;
|
||||
uint32_t blobEncPadding;
|
||||
uint32_t blobEncMode;
|
||||
uint32_t encryptedKeyblobSize;
|
||||
uint8_t encryptedKeyblob[0x30];
|
||||
} __attribute__((__packed__)) FileVaultV2Header;
|
||||
|
||||
typedef struct FileVaultInfo {
|
||||
union {
|
||||
FileVaultV1Header v1;
|
||||
FileVaultV2Header v2;
|
||||
} header;
|
||||
|
||||
AbstractFile* file;
|
||||
|
||||
HMAC_CTX hmacCTX;
|
||||
AES_KEY aesKey;
|
||||
AES_KEY aesEncKey;
|
||||
|
||||
off_t offset;
|
||||
|
||||
uint32_t curChunk;
|
||||
unsigned char chunk[FILEVAULT_CHUNK_SIZE];
|
||||
|
||||
char dirty;
|
||||
} FileVaultInfo;
|
||||
#endif
|
||||
|
||||
AbstractFile* createAbstractFileFromFileVault(AbstractFile* file, const char* key);
|
||||
|
||||
#endif
|
|
@ -1,154 +0,0 @@
|
|||
# Makefile for zlib
|
||||
# Copyright (C) 1995-2005 Jean-loup Gailly.
|
||||
# For conditions of distribution and use, see copyright notice in zlib.h
|
||||
|
||||
# To compile and test, type:
|
||||
# ./configure; make test
|
||||
# The call of configure is optional if you don't have special requirements
|
||||
# If you wish to build zlib as a shared library, use: ./configure -s
|
||||
|
||||
# To use the asm code, type:
|
||||
# cp contrib/asm?86/match.S ./match.S
|
||||
# make LOC=-DASMV OBJA=match.o
|
||||
|
||||
# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
|
||||
# make install
|
||||
# To install in $HOME instead of /usr/local, use:
|
||||
# make install prefix=$HOME
|
||||
|
||||
CC=gcc
|
||||
|
||||
CFLAGS=-O3 -DUSE_MMAP
|
||||
#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
|
||||
#CFLAGS=-g -DDEBUG
|
||||
#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
|
||||
# -Wstrict-prototypes -Wmissing-prototypes
|
||||
|
||||
LDFLAGS=-L. libz.a
|
||||
LDSHARED=gcc
|
||||
CPP=gcc -E
|
||||
|
||||
LIBS=libz.a
|
||||
SHAREDLIB=libz.so
|
||||
SHAREDLIBV=libz.so.1.2.3
|
||||
SHAREDLIBM=libz.so.1
|
||||
|
||||
AR=ar rc
|
||||
RANLIB=ranlib
|
||||
TAR=tar
|
||||
SHELL=/bin/sh
|
||||
EXE=
|
||||
|
||||
prefix =/usr/local
|
||||
exec_prefix =${prefix}
|
||||
libdir =${exec_prefix}/lib
|
||||
includedir =${prefix}/include
|
||||
mandir =${prefix}/share/man
|
||||
man3dir = ${mandir}/man3
|
||||
|
||||
OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
|
||||
zutil.o inflate.o infback.o inftrees.o inffast.o
|
||||
|
||||
OBJA =
|
||||
# to use the asm code: make OBJA=match.o
|
||||
|
||||
TEST_OBJS = example.o minigzip.o
|
||||
|
||||
all: example$(EXE) minigzip$(EXE)
|
||||
|
||||
check: test
|
||||
test: all
|
||||
@LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
|
||||
echo hello world | ./minigzip | ./minigzip -d || \
|
||||
echo ' *** minigzip test FAILED ***' ; \
|
||||
if ./example; then \
|
||||
echo ' *** zlib test OK ***'; \
|
||||
else \
|
||||
echo ' *** zlib test FAILED ***'; \
|
||||
fi
|
||||
|
||||
libz.a: $(OBJS) $(OBJA)
|
||||
$(AR) $@ $(OBJS) $(OBJA)
|
||||
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
|
||||
|
||||
match.o: match.S
|
||||
$(CPP) match.S > _match.s
|
||||
$(CC) -c _match.s
|
||||
mv _match.o match.o
|
||||
rm -f _match.s
|
||||
|
||||
$(SHAREDLIBV): $(OBJS)
|
||||
$(LDSHARED) -o $@ $(OBJS)
|
||||
rm -f $(SHAREDLIB) $(SHAREDLIBM)
|
||||
ln -s $@ $(SHAREDLIB)
|
||||
ln -s $@ $(SHAREDLIBM)
|
||||
|
||||
example$(EXE): example.o $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
|
||||
|
||||
minigzip$(EXE): minigzip.o $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
|
||||
|
||||
install: $(LIBS)
|
||||
-@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
|
||||
-@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
|
||||
-@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
|
||||
-@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
|
||||
cp zlib.h zconf.h $(includedir)
|
||||
chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
|
||||
cp $(LIBS) $(libdir)
|
||||
cd $(libdir); chmod 755 $(LIBS)
|
||||
-@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
|
||||
cd $(libdir); if test -f $(SHAREDLIBV); then \
|
||||
rm -f $(SHAREDLIB) $(SHAREDLIBM); \
|
||||
ln -s $(SHAREDLIBV) $(SHAREDLIB); \
|
||||
ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
|
||||
(ldconfig || true) >/dev/null 2>&1; \
|
||||
fi
|
||||
cp zlib.3 $(man3dir)
|
||||
chmod 644 $(man3dir)/zlib.3
|
||||
# The ranlib in install is needed on NeXTSTEP which checks file times
|
||||
# ldconfig is for Linux
|
||||
|
||||
uninstall:
|
||||
cd $(includedir); \
|
||||
cd $(libdir); rm -f libz.a; \
|
||||
if test -f $(SHAREDLIBV); then \
|
||||
rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
|
||||
fi
|
||||
cd $(man3dir); rm -f zlib.3
|
||||
|
||||
mostlyclean: clean
|
||||
clean:
|
||||
rm -f *.o *~ example$(EXE) minigzip$(EXE) \
|
||||
libz.* foo.gz so_locations \
|
||||
_match.s maketree contrib/infback9/*.o
|
||||
|
||||
maintainer-clean: distclean
|
||||
distclean: clean
|
||||
cp -p Makefile.in Makefile
|
||||
cp -p zconf.in.h zconf.h
|
||||
rm -f .DS_Store
|
||||
|
||||
tags:
|
||||
etags *.[ch]
|
||||
|
||||
depend:
|
||||
makedepend -- $(CFLAGS) -- *.[ch]
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
adler32.o: zlib.h zconf.h
|
||||
compress.o: zlib.h zconf.h
|
||||
crc32.o: crc32.h zlib.h zconf.h
|
||||
deflate.o: deflate.h zutil.h zlib.h zconf.h
|
||||
example.o: zlib.h zconf.h
|
||||
gzio.o: zutil.h zlib.h zconf.h
|
||||
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
|
||||
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
|
||||
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
|
||||
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
|
||||
minigzip.o: zlib.h zconf.h
|
||||
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
|
||||
uncompr.o: zlib.h zconf.h
|
||||
zutil.o: zutil.h zlib.h zconf.h
|
|
@ -10,6 +10,6 @@ hfsplus: $(HFSPLUSOBJS)
|
|||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
rm hfsplus
|
||||
-rm *.o
|
||||
-rm hfsplus
|
||||
|
||||
|
|
29
hfs/common.h
29
hfs/common.h
|
@ -11,6 +11,7 @@
|
|||
#define FALSE 0
|
||||
|
||||
#define FLIPENDIAN(x) flipEndian((unsigned char *)(&(x)), sizeof(x))
|
||||
#define FLIPENDIANLE(x) flipEndianLE((unsigned char *)(&(x)), sizeof(x))
|
||||
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#define IS_LITTLE_ENDIAN 1
|
||||
|
@ -38,4 +39,32 @@ static inline void flipEndian(unsigned char* x, int length) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void flipEndianLE(unsigned char* x, int length) {
|
||||
int i;
|
||||
unsigned char tmp;
|
||||
|
||||
if(endianness == IS_LITTLE_ENDIAN) {
|
||||
return;
|
||||
} else {
|
||||
for(i = 0; i < (length / 2); i++) {
|
||||
tmp = x[i];
|
||||
x[i] = x[length - i - 1];
|
||||
x[length - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct io_func_struct;
|
||||
|
||||
typedef int (*readFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer);
|
||||
typedef int (*writeFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer);
|
||||
typedef void (*closeFunc)(struct io_func_struct* io);
|
||||
|
||||
typedef struct io_func_struct {
|
||||
void* data;
|
||||
readFunc read;
|
||||
writeFunc write;
|
||||
closeFunc close;
|
||||
} io_func;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#define WRITE_KEY(a, b, c, d) ((*((a)->keyWrite))(b, c, d))
|
||||
#define READ_DATA(a, b, c) ((*((a)->dataRead))(b, c))
|
||||
|
||||
struct io_func_struct;
|
||||
|
||||
struct BTKey {
|
||||
uint16_t keyLength;
|
||||
unsigned char data[0];
|
||||
|
@ -20,9 +18,6 @@ struct BTKey {
|
|||
|
||||
typedef struct BTKey BTKey;
|
||||
|
||||
typedef int (*readFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer);
|
||||
typedef int (*writeFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer);
|
||||
typedef void (*closeFunc)(struct io_func_struct* io);
|
||||
typedef BTKey* (*dataReadFunc)(off_t offset, struct io_func_struct* io);
|
||||
typedef void (*keyPrintFunc)(BTKey* toPrint);
|
||||
typedef int (*keyWriteFunc)(off_t offset, BTKey* toWrite, struct io_func_struct* io);
|
||||
|
@ -383,13 +378,6 @@ struct CatalogRecordList {
|
|||
};
|
||||
typedef struct CatalogRecordList CatalogRecordList;
|
||||
|
||||
typedef struct io_func_struct {
|
||||
void* data;
|
||||
readFunc read;
|
||||
writeFunc write;
|
||||
closeFunc close;
|
||||
} io_func;
|
||||
|
||||
struct Extent {
|
||||
uint32_t startBlock;
|
||||
uint32_t blockCount;
|
||||
|
|
Загрузка…
Ссылка в новой задаче