initial code for dumping imessages in a reasonable format
This commit is contained in:
374
dump-imessages/iphone-dataprotection/emf_decrypter/hfs/xattr.c
Normal file
374
dump-imessages/iphone-dataprotection/emf_decrypter/hfs/xattr.c
Normal file
@@ -0,0 +1,374 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hfs/hfsplus.h>
|
||||
|
||||
static inline void flipAttrData(HFSPlusAttrData* data) {
|
||||
FLIPENDIAN(data->recordType);
|
||||
FLIPENDIAN(data->size);
|
||||
}
|
||||
|
||||
static inline void flipAttrForkData(HFSPlusAttrForkData* data) {
|
||||
FLIPENDIAN(data->recordType);
|
||||
flipForkData(&data->theFork);
|
||||
}
|
||||
|
||||
static inline void flipAttrExtents(HFSPlusAttrExtents* data) {
|
||||
FLIPENDIAN(data->recordType);
|
||||
flipExtentRecord(&data->extents);
|
||||
}
|
||||
|
||||
static int attrCompare(BTKey* vLeft, BTKey* vRight) {
|
||||
HFSPlusAttrKey* left;
|
||||
HFSPlusAttrKey* right;
|
||||
uint16_t i;
|
||||
|
||||
uint16_t cLeft;
|
||||
uint16_t cRight;
|
||||
|
||||
left = (HFSPlusAttrKey*) vLeft;
|
||||
right =(HFSPlusAttrKey*) vRight;
|
||||
|
||||
if(left->fileID < right->fileID) {
|
||||
return -1;
|
||||
} else if(left->fileID > right->fileID) {
|
||||
return 1;
|
||||
} else {
|
||||
for(i = 0; i < left->name.length; i++) {
|
||||
if(i >= right->name.length) {
|
||||
return 1;
|
||||
} else {
|
||||
cLeft = left->name.unicode[i];
|
||||
cRight = right->name.unicode[i];
|
||||
|
||||
if(cLeft < cRight)
|
||||
return -1;
|
||||
else if(cLeft > cRight)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(i < right->name.length) {
|
||||
return -1;
|
||||
} else {
|
||||
/* do a safety check on key length. Otherwise, bad things may happen later on when we try to add or remove with this key */
|
||||
/*if(left->keyLength == right->keyLength) {
|
||||
return 0;
|
||||
} else if(left->keyLength < right->keyLength) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define UNICODE_START (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t))
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 void attrKeyPrint(BTKey* toPrint) {
|
||||
HFSPlusAttrKey* key;
|
||||
|
||||
key = (HFSPlusAttrKey*)toPrint;
|
||||
|
||||
printf("attribute%d:%d:", key->fileID, key->startBlock);
|
||||
printUnicode(&key->name);
|
||||
}
|
||||
|
||||
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 int updateAttributes(Volume* volume, HFSPlusAttrKey* skey, HFSPlusAttrRecord* srecord) {
|
||||
HFSPlusAttrKey key;
|
||||
HFSPlusAttrRecord* record;
|
||||
int ret, len;
|
||||
|
||||
memcpy(&key, skey, skey->keyLength);
|
||||
|
||||
switch(srecord->recordType) {
|
||||
case kHFSPlusAttrInlineData:
|
||||
len = srecord->attrData.size + sizeof(HFSPlusAttrData);
|
||||
record = (HFSPlusAttrRecord*) malloc(len);
|
||||
memcpy(record, srecord, len);
|
||||
flipAttrData((HFSPlusAttrData*) record);
|
||||
removeFromBTree(volume->attrTree, (BTKey*)(&key));
|
||||
ret = addToBTree(volume->attrTree, (BTKey*)(&key), len, (unsigned char *)record);
|
||||
free(record);
|
||||
break;
|
||||
case kHFSPlusAttrForkData:
|
||||
record = (HFSPlusAttrRecord*) malloc(sizeof(HFSPlusAttrForkData));
|
||||
memcpy(record, srecord, sizeof(HFSPlusAttrForkData));
|
||||
flipAttrForkData((HFSPlusAttrForkData*) record);
|
||||
removeFromBTree(volume->attrTree, (BTKey*)(&key));
|
||||
ret = addToBTree(volume->attrTree, (BTKey*)(&key), sizeof(HFSPlusAttrForkData), (unsigned char *)record);
|
||||
free(record);
|
||||
break;
|
||||
case kHFSPlusAttrExtents:
|
||||
record = (HFSPlusAttrRecord*) malloc(sizeof(HFSPlusAttrExtents));
|
||||
memcpy(record, srecord, sizeof(HFSPlusAttrExtents));
|
||||
flipAttrExtents((HFSPlusAttrExtents*) record);
|
||||
removeFromBTree(volume->attrTree, (BTKey*)(&key));
|
||||
ret = addToBTree(volume->attrTree, (BTKey*)(&key), sizeof(HFSPlusAttrExtents), (unsigned char *)record);
|
||||
free(record);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t getAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t** data) {
|
||||
HFSPlusAttrKey key;
|
||||
HFSPlusAttrRecord* record;
|
||||
size_t size;
|
||||
int exact;
|
||||
|
||||
if(!volume->attrTree)
|
||||
return FALSE;
|
||||
|
||||
memset(&key, 0 , sizeof(HFSPlusAttrKey));
|
||||
key.fileID = fileID;
|
||||
key.startBlock = 0;
|
||||
ASCIIToUnicode(name, &key.name);
|
||||
key.keyLength = sizeof(HFSPlusAttrKey) - sizeof(HFSUniStr255) + sizeof(key.name.length) + (sizeof(uint16_t) * key.name.length);
|
||||
|
||||
*data = NULL;
|
||||
|
||||
record = (HFSPlusAttrRecord*) search(volume->attrTree, (BTKey*)(&key), &exact, NULL, NULL);
|
||||
|
||||
if(exact == FALSE) {
|
||||
if(record)
|
||||
free(record);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(record->recordType)
|
||||
{
|
||||
case kHFSPlusAttrInlineData:
|
||||
size = record->attrData.size;
|
||||
*data = (uint8_t*) malloc(size);
|
||||
memcpy(*data, record->attrData.data, size);
|
||||
free(record);
|
||||
return size;
|
||||
default:
|
||||
fprintf(stderr, "unsupported attribute node format\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int setAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t* data, size_t size) {
|
||||
HFSPlusAttrKey key;
|
||||
HFSPlusAttrData* record;
|
||||
int ret, exact;
|
||||
|
||||
if(!volume->attrTree)
|
||||
return FALSE;
|
||||
|
||||
memset(&key, 0 , sizeof(HFSPlusAttrKey));
|
||||
key.fileID = fileID;
|
||||
key.startBlock = 0;
|
||||
ASCIIToUnicode(name, &key.name);
|
||||
key.keyLength = sizeof(HFSPlusAttrKey) - sizeof(HFSUniStr255) + sizeof(key.name.length) + (sizeof(uint16_t) * key.name.length);
|
||||
|
||||
record = (HFSPlusAttrData*) malloc(sizeof(HFSPlusAttrData) + size);
|
||||
memset(record, 0, sizeof(HFSPlusAttrData));
|
||||
|
||||
record->recordType = kHFSPlusAttrInlineData;
|
||||
record->size = size;
|
||||
memcpy(record->data, data, size);
|
||||
|
||||
ret = updateAttributes(volume, &key, (HFSPlusAttrRecord*) record);
|
||||
|
||||
free(record);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unsetAttribute(Volume* volume, uint32_t fileID, const char* name) {
|
||||
HFSPlusAttrKey key;
|
||||
|
||||
if(!volume->attrTree)
|
||||
return FALSE;
|
||||
|
||||
memset(&key, 0 , sizeof(HFSPlusAttrKey));
|
||||
key.fileID = fileID;
|
||||
key.startBlock = 0;
|
||||
ASCIIToUnicode(name, &key.name);
|
||||
key.keyLength = sizeof(HFSPlusAttrKey) - sizeof(HFSUniStr255) + sizeof(key.name.length) + (sizeof(uint16_t) * key.name.length);
|
||||
return removeFromBTree(volume->attrTree, (BTKey*)(&key));
|
||||
}
|
||||
|
||||
XAttrList* getAllExtendedAttributes(HFSCatalogNodeID CNID, Volume* volume) {
|
||||
BTree* tree;
|
||||
HFSPlusAttrKey key;
|
||||
HFSPlusAttrRecord* record;
|
||||
uint32_t nodeNumber;
|
||||
int recordNumber;
|
||||
BTNodeDescriptor* descriptor;
|
||||
HFSPlusAttrKey* currentKey;
|
||||
off_t recordOffset;
|
||||
XAttrList* list = NULL;
|
||||
XAttrList* lastItem = NULL;
|
||||
XAttrList* item = NULL;
|
||||
|
||||
if(!volume->attrTree)
|
||||
return NULL;
|
||||
|
||||
memset(&key, 0 , sizeof(HFSPlusAttrKey));
|
||||
key.fileID = CNID;
|
||||
key.startBlock = 0;
|
||||
key.name.length = 0;
|
||||
key.keyLength = sizeof(HFSPlusAttrKey) - sizeof(HFSUniStr255) + sizeof(key.name.length) + (sizeof(uint16_t) * key.name.length);
|
||||
|
||||
tree = volume->attrTree;
|
||||
record = (HFSPlusAttrRecord*) search(tree, (BTKey*)(&key), NULL, &nodeNumber, &recordNumber);
|
||||
if(record == NULL)
|
||||
return NULL;
|
||||
|
||||
free(record);
|
||||
|
||||
while(nodeNumber != 0) {
|
||||
descriptor = readBTNodeDescriptor(nodeNumber, tree);
|
||||
|
||||
while(recordNumber < descriptor->numRecords) {
|
||||
recordOffset = getRecordOffset(recordNumber, nodeNumber, tree);
|
||||
currentKey = (HFSPlusAttrKey*) READ_KEY(tree, recordOffset, tree->io);
|
||||
|
||||
if(currentKey->fileID == CNID) {
|
||||
item = (XAttrList*) malloc(sizeof(XAttrList));
|
||||
item->name = (char*) malloc(currentKey->name.length + 1);
|
||||
int i;
|
||||
for(i = 0; i < currentKey->name.length; i++) {
|
||||
item->name[i] = currentKey->name.unicode[i];
|
||||
}
|
||||
item->name[currentKey->name.length] = '\0';
|
||||
item->next = NULL;
|
||||
|
||||
if(lastItem != NULL) {
|
||||
lastItem->next = item;
|
||||
} else {
|
||||
list = item;
|
||||
}
|
||||
|
||||
lastItem = item;
|
||||
|
||||
free(currentKey);
|
||||
} else {
|
||||
free(currentKey);
|
||||
free(descriptor);
|
||||
return list;
|
||||
}
|
||||
|
||||
recordNumber++;
|
||||
}
|
||||
|
||||
nodeNumber = descriptor->fLink;
|
||||
recordNumber = 0;
|
||||
|
||||
free(descriptor);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
BTree* openAttributesTree(io_func* file) {
|
||||
return openBTree(file, &attrCompare, &attrKeyRead, &attrKeyWrite, &attrKeyPrint, &attrDataRead);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user