Skip to content

Instantly share code, notes, and snippets.

@enigmaticape
Created May 22, 2014 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save enigmaticape/26fb131f7379a20c7718 to your computer and use it in GitHub Desktop.
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.
#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