Created
September 14, 2019 02:34
-
-
Save daddycocoaman/e1a4f31109e17188d5ce8fd0ca15b63e to your computer and use it in GitHub Desktop.
Parses sticky note files in .snt/.sqlite formats. Sqlite files may require the WAL and SHM files of the same name as well. Once run, WAL/SHM files will be merged into .sqlite file.
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 json | |
import sqlite3 | |
import olefile | |
import argparse | |
def parse_snt_file(file): | |
# https://www.tutorialspoint.com/python_digital_forensics/python_digital_forensics_important_artifacts_in_windows | |
if not olefile.isOleFile(file): | |
return "Invalid OLE file" | |
ole = olefile.OleFileIO(file) | |
note = {} | |
for stream in ole.listdir(): | |
if stream[0].count("-") == 3: | |
if stream[0] not in note: | |
note[stream[0]] = {"created": str(ole.getctime(stream[0])), "modified": str(ole.getmtime(stream[0]))} | |
content = None | |
if stream[1] == '3': | |
content = ole.openstream(stream).read().decode("utf-16").rstrip("\u0000") | |
if content: | |
note[stream[0]][stream[1]] = content | |
return json.dumps(note, indent=4, sort_keys=True) | |
def dict_factory(cursor, row): | |
d = {} | |
for idx, col in enumerate(cursor.description): | |
d[col[0]] = row[idx] | |
return d | |
def parse_plum_file(db): | |
con = sqlite3.connect(db) | |
con.row_factory = dict_factory | |
cur = con.cursor() | |
#tableNames = [v for name in cur.execute("SELECT name FROM sqlite_master WHERE type='table'") for k,v in name.items()] | |
tableNames = ["Note", "Stroke", "StrokeMetadata", "User", "SyncState", "UpgradedNote", "Media"] | |
finaloutput = {} | |
for name in tableNames: | |
#Don't do this in real life. | |
cur.execute(f"select * from {name}") | |
res = cur.fetchall() | |
for item in res: | |
if not item.get("LastServerVersion") == None: | |
item["LastServerVersion"] = json.loads(item.get("LastServerVersion")) | |
finaloutput[name] = res | |
return (json.dumps(finaloutput, indent=4)) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="""Parses sticky note files in .snt/.sqlite formats. | |
Sqlite files may require the WAL and SHM files of the same | |
name as well. Once run, WAL/SHM files will be merged into .sqlite file.""") | |
parser.add_argument('-s', metavar="<.snt file>", help='Sticky note .snt file', type=argparse.FileType('r')) | |
parser.add_argument('-p', metavar="<.sqlite file>", help='Sticky note plum.sqlite file', type=argparse.FileType('r')) | |
args = parser.parse_args() | |
line = "*" * 10 | |
if args.s: | |
print(f"{line}\n{args.s.name}\n{line}") | |
print(parse_snt_file(args.s.name), end="\n\n") | |
if args.p: | |
print(f"{line}\n{args.p.name}\n{line}") | |
print(parse_plum_file(args.p.name), end="\n\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment