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?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With