diff options
Diffstat (limited to 'src/plist.c')
| -rw-r--r-- | src/plist.c | 284 | 
1 files changed, 284 insertions, 0 deletions
| diff --git a/src/plist.c b/src/plist.c index c4d6bfa..0024577 100644 --- a/src/plist.c +++ b/src/plist.c @@ -23,8 +23,10 @@  #include <libxml/tree.h>  #include <string.h>  #include <assert.h> +#include "utils.h"  #include "plist.h" +  const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\  <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\  <plist version=\"1.0\">\n\ @@ -243,3 +245,285 @@ void free_dictionary(char **dictionary)  	free(dictionary);  } + +/* + * Binary propertylist code follows + */ + + +/* + * This is how parsing a bplist is going to have to work: + * 		- The entire binary plist is going to have to be in memory. + * 		- A function, parse_nodes(), will have to be a recursive function + * 		  which iterates over the binary plist and reads in elements into bplist_node structs + * 		  and handles them accordingly. The end result should be a somewhat-hierarchical layout  + * 		  of bplist_nodes. + * 		- parse_nodes() will return the first node it encounters, which is usually the "root" node.  + */ + +uint32_t uipow(uint32_t value, uint32_t power) { +	if (!power) return 1; +	int i = 0, oVal = value; +	for (i = 1; i < power; i++) { +		value *= oVal; +	} +	return value; +} + +void byte_convert(char *address, size_t size) { +	int i = 0, j = 0; +	char tmp = '\0'; +	 +	for (i = 0; i < (size / 2); i++) { +		tmp = address[i]; +		j = ((size-1) + 0) - i; +		address[i] = address[j]; +		address[j] = tmp; +	} +} +		 +bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t *position, uint8_t ref_size) { +	if (!position || !bpbuffer || !bplength) return NULL; +	 +	uint8_t modifier = 0; +	bplist_node *new_node = (bplist_node*)malloc(sizeof(bplist_node)); +	bplist_node *length_stupidity = NULL; +	memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct +	 +	int myPos = *position; +	if (myPos == bplength || (myPos+1) == bplength) { free(new_node); return NULL; } // end of string +	 +	uint32_t length = 0; +	if (!myPos) { +		if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { +			return NULL; // badness! +		} +		myPos += strlen("bplist00"); +	} +	 +	// Get the node's type. +	if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real +		// better handling of date; basically interpret as real or double +		new_node->type = BPLIST_DATE; +		new_node->length = 8; // always 8 for "date" (Apple intended it, not me) +		myPos++; +		memcpy(&new_node->realval, bpbuffer+myPos, sizeof(new_node->realval)); +		byte_convert(&new_node->realval, sizeof(new_node->realval)); +		myPos += new_node->length; +		*position = myPos; +		return new_node; +	} +	 +	new_node->type = bpbuffer[myPos] & BPLIST_MASK; +	new_node->length = bpbuffer[myPos] & BPLIST_FILL; +	if (!new_node->type) { +		// what? check if it's a boolean. +		if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) { +			// okay, so it is. Carry on. +			new_node->type = bpbuffer[myPos]; +			new_node->length = 0; +		} else {  +			// er, what? we have a bad type here. Return NULL. +			free(new_node); +			//printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); +			return NULL; +		} +	} +	 +	myPos++; // puts us in the data. +	if (new_node->length == BPLIST_FILL) { // Data happens to contain length... +		// what? you're going to make me parse an int for the length. You suck. +		*position = myPos; +		length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); +		switch (length_stupidity->length) { +			case sizeof(uint8_t): +				new_node->length = length_stupidity->intval8; +				break; +			case sizeof(uint16_t): +				new_node->length = length_stupidity->intval16; +				break; +			case sizeof(uint32_t): +				new_node->length = length_stupidity->intval32; +				break; +			case sizeof(uint64_t): +				new_node->length = length_stupidity->intval64; +				break; +			default: +				free(new_node); +				free(length_stupidity); +				return NULL; +		} +		// There, we have our fucking length now. +		*position = myPos; +		free(length_stupidity); // cleanup +	} + +	// Now we're in the data.  +	// Error-checking sorta +	if ((myPos + new_node->length) >= bplength) { +		new_node->length = bplength - myPos; // truncate the object +	} +	 +	// And now for the greatest show on earth: the giant fucking switch statement. +	switch (new_node->type) { +		case BPLIST_INT: +			new_node->length = uipow(2, new_node->length); // make length less misleading +			switch (new_node->length) { +				case sizeof(uint8_t): +					new_node->intval8 = bpbuffer[myPos]; +					break; +				case sizeof(uint16_t): +					memcpy(&new_node->intval16, bpbuffer+myPos, sizeof(uint16_t)); +					new_node->intval16 = ntohs(new_node->intval16); +					break; +				case sizeof(uint32_t): +					memcpy(&new_node->intval32, bpbuffer+myPos, sizeof(uint32_t)); +					new_node->intval32 = ntohl(new_node->intval32); +					break; +				case sizeof(uint64_t): +					memcpy(&new_node->intval64, bpbuffer+myPos, sizeof(uint64_t)); +					byte_convert(&new_node->intval64, sizeof(uint64_t)); +					break; +				default: +					free(new_node); +					printf("parse_raw_node: lol: invalid int: size given %i\n", new_node->length); +					printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); +					return NULL; +			} +			break; +		 +		case BPLIST_REAL: +			new_node->length = uipow(2, new_node->length); +			memcpy(&new_node->realval, bpbuffer+myPos, new_node->length); // XXX: probable buffer overflow here +			//new_node->realval = bpbuffer[myPos]; // why not +			byte_convert(&new_node->realval, sizeof(double)); +			break; +			 +		case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ +			new_node->length = new_node->length * 2; // dicts lie +		case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ +			new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space.  +		case BPLIST_STRING: +		case BPLIST_DATA: +		default: /* made to hold raw data. */ +			modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1; +			new_node->strval = (char*)malloc(sizeof(char) * (new_node->length * modifier)); +			memcpy(new_node->strval, bpbuffer+myPos, (new_node->length * modifier)); +			break; +		 +		case BPLIST_UNICODE: +			new_node->unicodeval = (wchar_t*)malloc(sizeof(wchar_t) * new_node->length); +			memcpy(new_node->unicodeval, bpbuffer+myPos, new_node->length); +			break; +	} +	 +	myPos += new_node->length; +	*position = myPos; +	return new_node; +} + +void print_bytes(char *val, size_t size) { +	int i = 0; +	for (i = 0; i < size; i++) { +		printf("Byte %i: 0x%x\n", i, val[i]); +	} +} + +bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t *position) { +	bplist_node **nodeslist = NULL, **newaddr = NULL; +	bplist_node *new_node = NULL, *root_node = NULL; +	 +	uint32_t nodeslength = 0; +	uint8_t offset_size = 0, dict_param_size = 0; +	offset_size = bpbuffer[bplength-26]; +	dict_param_size = bpbuffer[bplength-25];  +	uint64_t current_offset = 0; +	//uint64_t num_objects = *(bpbuffer+(bplength-24)), root_object = *(bpbuffer+(bplength-16)), offset_table_index = *(bpbuffer+(bplength-8)); +	uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; +	memcpy(&num_objects, bpbuffer+bplength-24, sizeof(uint64_t)); +	memcpy(&root_object, bpbuffer+bplength-16, sizeof(uint64_t)); +	memcpy(&offset_table_index, bpbuffer+bplength-8, sizeof(uint64_t)); +	byte_convert(&num_objects, sizeof(uint64_t)); +	byte_convert(&root_object, sizeof(uint64_t)); +	byte_convert(&offset_table_index, sizeof(uint64_t)); +	 +	log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength-26]); +	log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength-25]); +	log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer+bplength-24)); +	log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer+bplength-16)); +	log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer+bplength-8)); +	log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); +	 +	int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; +	uint32_t index1 = 0, index2 = 0; +	 +	nodeslist = (bplist_node**)malloc(sizeof(bplist_node*) * num_objects); +	if (!nodeslist) return NULL; + +	for (i = 0; i < num_objects; i++) { +		memcpy(¤t_offset, bpbuffer+(offset_table_index+(i*offset_size)), offset_size); +		//current_offset = (offset_size == 2) ? ntohs(current_offset) : (offset_size == 4) ? ntohl(current_offset) : current_offset; +		//if (offset_size == 8) byte_convert(¤t_offset, 8); +		byte_convert(¤t_offset, (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); +		log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); +		nodeslist[i] = parse_raw_node(bpbuffer, bplength, ¤t_offset, dict_param_size); +		log_debug_msg("parse_nodes: parse_raw_node done\n"); +	} + + +	for (i = 0; i < num_objects; i++) { +		// set elements for dicts and arrays and leave the rest alone +		log_debug_msg("parse_nodes: on node %i\n", i); +		switch (nodeslist[i]->type) { +			case BPLIST_DICT: +				log_debug_msg("parse_nodes: dictionary found\n"); +				nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); +				for (j = 0; j < (nodeslist[i]->length / 2); j++) { +					str_i = j * nodeslist[i]->intval8; +					str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8; + +					memcpy(&index1, nodeslist[i]->strval+str_i, nodeslist[i]->intval8); +					memcpy(&index2, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); +					//index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; +					//index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2; +					byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); +					byte_convert(&index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); +					//printf("parse_nodes: key index %i value %i\n", index1, index2); +					//printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length); +					//printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length); +					nodeslist[i]->subnodes[k++] = nodeslist[index1]; +					nodeslist[i]->subnodes[k++] = nodeslist[index2]; +				} +				 +				nodeslist[i]->length = nodeslist[i]->length / 2; +				free(nodeslist[i]->strval);  +				k = 0; +				break; +			 +			case BPLIST_ARRAY: +				log_debug_msg("parse_nodes: array found\n"); +				nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data +				 +				for (j = 0; j < nodeslist[i]->length; j++) { +					log_debug_msg("parse_nodes: array index %i\n", j); +					str_j = j * nodeslist[i]->intval8; +					//index1 = nodeslist[i]->strval[j]; +					memcpy(&index1, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); +					log_debug_msg("parse_nodes: post-memcpy\n"); +					//index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; +					byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); +					log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); +					nodeslist[i]->subnodes[j] = nodeslist[index1]; +					log_debug_msg("parse_nodes: post-assignment\n"); +				} +				free(nodeslist[i]->strval); +				break; +			default: +				//printf("lol... type %x\n", nodeslist[i]->type); +				break; +		} // those are the only two we need to correct for. +	} +	 +	root_node = nodeslist[root_object]; +	return root_node; +} | 
