Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I read the "attributedBody" column in macOS' iMessage database?

Apple changed the Messages database schema in the latest macOS Ventura update, and sent messages seem to no longer store their body/content in the text column. The attributedBody column has the content, but it's stored as an encoded blob.

Has anyone had any luck getting plaintext out of this?

like image 875
stephancasas Avatar asked Oct 30 '25 12:10

stephancasas


1 Answers

The attributedBody column is a serialized NSMutableAttributedString — packed using NSArchiver. It can be unpacked and read using NSUnarchiver but must first be extracted from the Messages sqlite database without losing any of its non-printable characters.

To preserve the column's content when performing a query, you can use sqlite3's HEX() function. The resulting bytes can then be read back into their original state by iterating over them and building a new NSString.


In the example below, NSData is extended with two helper methods to handle reading a file with hex-encoded data. Using dataWithContentsOfHexEncodedFile, a message record's attributedBody can be passed to NSUnarchiver, which will handle decoding the serialized NSAttributedString. This can then be converted to a normal NSString by accessing the string property.

#import <Foundation/Foundation.h>

@implementation NSData (NSDataExtended)
+ (NSData *)dataWithContentsOfHexEncodedString:(NSString *) string {
    const char * chars = [string UTF8String];
    int i = 0;
    
    NSMutableData *data = [NSMutableData dataWithCapacity: string.length / 2];
    char byteChars[3] = {'\0', '\0', '\0'};
    unsigned long wholeByte;
    
    while (i < string.length) {
        byteChars[0] = chars[i++];
        byteChars[1] = chars[i++];
        wholeByte = strtoul(byteChars, NULL, 16);
        [data appendBytes:&wholeByte length:1];
    }
    
    return data;
}

+ (NSData *)dataWithContentsOfHexEncodedFile:(NSString *) filePath {
    return [self dataWithContentsOfHexEncodedString:[NSString
                                    stringWithContentsOfFile:filePath
                                    encoding:NSUTF8StringEncoding
                                    error:nil]];
}
@end

int main(int argc, const char * argv[]) {
    system([[[NSString alloc] initWithFormat:@"%s %s > %s",
             "/usr/bin/sqlite3 ~/Library/Messages/chat.db",
             "'SELECT HEX(attributedBody) FROM message ORDER BY ROWID DESC LIMIT 1'",
             "/private/tmp/msgbody"] UTF8String]);
    
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    NSMutableAttributedString *msg = [[[NSUnarchiver alloc]
                                       initForReadingWithData:[NSData dataWithContentsOfHexEncodedFile:@"/private/tmp/msgbody"]
                                      ] decodeTopLevelObjectAndReturnError:nil];
    
    NSLog(@"%@", [msg string]);
    
    return 0;
}


like image 120
stephancasas Avatar answered Nov 02 '25 02:11

stephancasas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!