Created
May 22, 2014 16:17
-
-
Save enigmaticape/26fb131f7379a20c7718 to your computer and use it in GitHub Desktop.
Quick, dirty and really painfully ugly way to parse the data fields out of an app store receipt.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
typedef struct _ASNObject { | |
NSInteger index; | |
uint8_t type; | |
NSUInteger datap; | |
NSUInteger length; | |
NSUInteger next; | |
} ASNObject; | |
NSUInteger intValueFromDataAtIndexWithSize(uint16_t index, uint8_t * data, NSUInteger * value, uint16_t size ) { | |
while( size-- ) { | |
*value <<= 8; | |
*value |= data[ index++ ]; | |
} | |
return index; | |
} | |
NSUInteger readLengthBytes(NSInteger index, uint8_t * data, NSUInteger * length) { | |
return intValueFromDataAtIndexWithSize( | |
(data[index] & 0x80) == 0x80 ? index + 1 : index, | |
data, | |
length, | |
(data[index] & 0x80) == 0x80 ? data[index] - 0x80 : 1 | |
); | |
} | |
ASNObject objectAtIndex(NSInteger index, uint8_t * data) { | |
ASNObject obj = {0,0,0,0,0}; | |
obj.index = index; | |
obj.type = data[index]; | |
obj.datap = readLengthBytes(index + 1, data, &obj.length); | |
obj.next = (0x20 & obj.type) == 0x20 ? obj.datap : obj.datap + obj.length; | |
return obj; | |
} | |
NSInteger indexOfNextObjectOfType(NSInteger index, uint8_t * data, uint8_t type) { | |
ASNObject obj = objectAtIndex(index, data); | |
while (obj.type != type) { | |
obj = objectAtIndex(obj.next, data); | |
} | |
return obj.index; | |
} | |
NSInteger indexOfNextObjectOfTypeWithValue(NSInteger index, uint8_t * data, uint8_t type, uint8_t * value, uint16_t length) { | |
while( 1 ) { | |
index = indexOfNextObjectOfType(index, data, type); | |
ASNObject obj = objectAtIndex(index, data); | |
if( obj.length == length ) { | |
if( 0x00 == memcmp(&data[obj.datap], value, length) ) { | |
return obj.index; | |
} | |
} | |
index = obj.next; | |
} | |
return -1; | |
} | |
NSUInteger intValueFromObject(ASNObject obj, uint8_t * data) { | |
NSUInteger value = 0; | |
intValueFromDataAtIndexWithSize(obj.datap, data, &value, obj.length); | |
return value; | |
} | |
NSString * stringValueFromObject(ASNObject obj, uint8_t * data) { | |
ASNObject strobj = objectAtIndex(obj.datap, data); | |
if( strobj.datap + strobj.length == obj.next ) { | |
if( strobj.type == 0x0c || strobj.type == 0x16 ) { | |
return [[NSString alloc] initWithBytes: &data[strobj.datap] length: strobj.length encoding: NSUTF8StringEncoding]; | |
} | |
if( strobj.type == 0x02 ) { | |
return [NSString stringWithFormat:@"%@", @(intValueFromObject(strobj, data))]; | |
} | |
} | |
return [[NSData dataWithBytes:&data[obj.datap] length:obj.length] description]; | |
} | |
void dumpDataSection(uint8_t * receipt_bytes) { | |
uint8_t data_obj_id[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01}; | |
NSUInteger index = 0; | |
ASNObject octets = {}; | |
ASNObject aapl_typ_int; | |
ASNObject aapl_ver_int; | |
ASNObject aapl_oct_str; | |
index = indexOfNextObjectOfTypeWithValue(0,receipt_bytes,0x06,data_obj_id, 9); | |
octets = objectAtIndex(indexOfNextObjectOfType(index, receipt_bytes, 0x04), receipt_bytes); | |
index = octets.datap; | |
while( index < octets.next ) { | |
index = indexOfNextObjectOfType(index, receipt_bytes, 0x02); | |
aapl_typ_int = objectAtIndex(index, receipt_bytes); | |
aapl_ver_int = objectAtIndex(aapl_typ_int.next, receipt_bytes); | |
aapl_oct_str = objectAtIndex(aapl_ver_int.next, receipt_bytes); | |
index = indexOfNextObjectOfType(aapl_oct_str.next, receipt_bytes, 0x30); | |
NSLog( | |
@"Type : %@ Version : %@ Octets : %@", | |
@(intValueFromObject(aapl_typ_int, receipt_bytes)), | |
@(intValueFromObject(aapl_ver_int, receipt_bytes)), | |
stringValueFromObject(aapl_oct_str, receipt_bytes) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment