Parsing Apple Notes database

Setup

You need python3 and sqlite3 installed on your system. Then install protobuf_inspector python package via pip3:

pip3 install protobuf_inspector

Now copy a Notes SQLite database file into your working folder:

cp ~/Library/Group\ Containers/group.com.apple.notes/NoteStore.sqlite3 .
sqlite3 NoteStore.sqlite3  # check that you can connect to the database

Inspect ZICNOTEDATA.ZDATA

import io
import sqlite3
import gzip
from protobuf_inspector.types import StandardParser

parser = StandardParser()

db = sqlite3.connect('NoteStore.sqlite')
cursor = db.cursor()
rows = cursor.execute('SELECT Z_PK, ZDATA FROM ZICNOTEDATA')

for (pk, data) in rows:
    if data != None:
        f = io.BytesIO(gzip.decompress(data))
        print(parser.parse_message(f, "message"))

Example output

message:
    1 <varint> = 0
    2 <chunk> = message:
        1 <varint> = 0
        2 <varint> = 0
        3 <chunk> = message:
            2 <chunk> = bytes (4)
                0000   EF BF BC 0A                                                              ....
            3 <chunk> = message:
                1 <chunk> = message(1 <varint> = 0, 2 <varint> = 0)
                2 <varint> = 0
                3 <chunk> = message(1 <varint> = 0, 2 <varint> = 0)
                5 <varint> = 1
            3 <chunk> = message:
                1 <chunk> = message(1 <varint> = 1, 2 <varint> = 0)
                2 <varint> = 1
                3 <chunk> = message(1 <varint> = 1, 2 <varint> = 0)
                5 <varint> = 2
            3 <chunk> = message:
                1 <chunk> = message(1 <varint> = 1, 2 <varint> = 1)
                2 <varint> = 1
                3 <chunk> = message(1 <varint> = 2, 2 <varint> = 1)
                5 <varint> = 3
            3 <chunk> = message:
                1 <chunk> = message(1 <varint> = 1, 2 <varint> = 2)
                2 <varint> = 1
                3 <chunk> = message(1 <varint> = 1, 2 <varint> = 10)
                4 <varint> = 1
                5 <varint> = 4
            3 <chunk> = message:
                1 <chunk> = message:
                    1 <varint> = 0
                    2 <varint> = 4294967295
                2 <varint> = 0
                3 <chunk> = message:
                    1 <varint> = 0
                    2 <varint> = 4294967295
            4 <chunk> = message:
                1 <chunk> = message:
                    1 <chunk> = bytes (16)
                        0000   14 7C 52 77 1B 58 48 0A 8B A8 6A 1C BB ED 04 59                          .|Rw.XH...j....Y
                    2 <chunk> = message(1 <varint> = 3)
                    2 <chunk> = message(1 <varint> = 11)
                1 <chunk> = message:
                    1 <chunk> = bytes (16)
                        0000   40 BD 5B D6 3A 85 40 6A BF 42 5D 09 54 D2 56 24                          @.[.:.@j.B].T.V$
                    2 <chunk> = message(1 <varint> = 1)
                    2 <chunk> = message(1 <varint> = 2)
            5 <chunk> = message:
                1 <varint> = 1
                12 <chunk> = message:
                    1 <chunk> = "7FCB3859-F34D-4177-B78C-929B989AA738"
                    2 <chunk> = "com.apple.drawing.2"
            5 <chunk> = message(1 <varint> = 1)

TODO: Explain output

Links


Changelog

  • 2021-03-11 Created post