strozfriedberg/plistutils

Erros occur when using NSKeyedArchiveParser or BookmarkParser

Opened this issue · 2 comments

NSKeyedArchiveParser error occurs with my test script below, if I try to parse the sample_files.zip I attached.
But ccl_bplist can do it.

Test script 1:

from plistutils.nskeyedarchiver import NSKeyedArchiveParser, NSKeyedArchiveException
from plistutils.plistparser import PlistParser

fullpath = '/Users/macforensics/Desktop/sample1_backgrounditems.btm'

with open(fullpath, 'rb') as plist_file:
    data = PlistParser.parse(plist_file)
    if NSKeyedArchiveParser.is_known_nskeyedarchive(data, fullpath):
        nska_parser = NSKeyedArchiveParser(fullpath)
        try:
            unarchived_data = nska_parser.parse_archive(data).get('root', {})
        except NSKeyedArchiveException:
            print('NSKeyedArchiveException occurred')
            exit(1)
        print(unarchived_data)

The error is like below:

% python ~/Documents/GitHub/forked/test/btm_parsing_test1.py
--- Logging error ---
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 1083, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 927, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 663, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 367, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
  File "/Users/macforensics/Documents/GitHub/forked/test/btm_parsing_test1.py", line 11, in <module>
    unarchived_data = nska_parser.parse_archive(data).get('root', {})
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 50, in parse_archive
    ret[name] = self.process_obj(top, objects_list)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 71, in process_obj
    ret = self.convert_dict(obj, objects_list, parents)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 226, in convert_dict
    return self.get_processors().get(class_name, NSKeyedArchiveParser._process_default)(self, class_name, d, objects_list, parents)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 92, in _process_ns_dictionary
    assembled_dict[self.process_obj(k, objects_list, parents)] = self.process_obj(d['NS.objects'][idx],
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 75, in process_obj
    ret = self.process_obj(objects_list[obj.integer], objects_list, parents)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 71, in process_obj
    ret = self.convert_dict(obj, objects_list, parents)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 226, in convert_dict
    return self.get_processors().get(class_name, NSKeyedArchiveParser._process_default)(self, class_name, d, objects_list, parents)
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/nskeyedarchiver.py", line 181, in _process_default
    logger.warning(
Message: "Unknown NSKeyedArchiver class name {} with data ({}) in '{}', please report."
Arguments: ('BackgroundItems', {'allContainers': Uid(6), '$class': Uid(20)}, '/Users/macforensics/Desktop/sample1_backgrounditems.btm')
{'version': 2, 'backgroundItems': None}

Actually, the sample files contain Bookmark structure data too.
BookmarkParser does not seem to be able to parse that data completely. It can parse the bookmark data, but it will also display a parsing error.
I am sorry, but I do not properly understand what the "idx" and "name" variables mean in the following script.

Test script 2:

import ccl_bplist
from plistutils.bookmark import BookmarkParser
from plistutils.plistparser import PlistParser

fullpath = '/Users/macforensics/Desktop/sample1_backgrounditems.btm'

with open(fullpath, 'rb') as fp:
    plist = ccl_bplist.load(fp)
    ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
    ccl_bplist.set_object_converter(ccl_bplist.NSKeyedArchiver_common_objects_convertor)
    btm_login_items_entries = ns_keyed_archiver_obj['root']['backgroundItems']['allContainers']
    for item_num in list(range(len(btm_login_items_entries))):
        if type(btm_login_items_entries[item_num]['internalItems'][0]['bookmark']['data']) == bytes:
            bookmark_data = btm_login_items_entries[item_num]['internalItems'][0]['bookmark']['data']
        elif type(btm_login_items_entries[item_num]['internalItems'][0]['bookmark']['data']) == ccl_bplist.NsKeyedArchiverDictionary:
            bookmark_data = btm_login_items_entries[item_num]['internalItems'][0]['bookmark']['data']['NS.data']
        idx = 0
        name = ''
        for bookmark_record in BookmarkParser.parse_bookmark(fullpath, idx, name, bookmark_data):
            print(bookmark_record)

Error message:

% python ~/Documents/GitHub/forked/test/btm_parsing_test2.py
--- Logging error ---
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 1083, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 927, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 663, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py", line 367, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
  File "/Users/macforensics/Documents/GitHub/forked/test/btm_parsing_test2.py", line 19, in <module>
    for bookmark_record in BookmarkParser.parse_bookmark(fullpath, idx, name, bookmark_data):
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/bookmark.py", line 181, in parse_bookmark
    cls.process_field(fullpath, buf, item_name, data_offset, cur_toc_entry,
  File "/Users/macforensics/envs/mac_apt/lib/python3.9/site-packages/plistutils/bookmark.py", line 209, in process_field
    logger.warning(
Message: "Unknown bookmark record/data type ({}/{}) in item '{}' from file '{}', please report."
Arguments: (983055, 1281, '', '/Users/macforensics/Desktop/sample1_backgrounditems.btm')
{'bookmark_index': 0, 'toc_depth': 1, 'path': '/System/Applications/Utilities/Terminal.app', 'inode_path': '/1152921500311879701/1152921500311879703/1152921500311961301/1152921500311989407', 'resource_props': 'IsDirectory, IsPackage, IsApplication', 'creation_date': datetime.datetime(2020, 1, 1, 8, 0), 'volume_path': '/', 'volume_url': 'file:///', 'volume_name': 'Macintosh HD', 'volume_uuid': '0A81F3B1-51D9-3335-B3E3-169C3640360D', 'volume_size': 107164426240, 'volume_creation_date': datetime.datetime(2020, 1, 1, 8, 0), 'volume_props': 'IsLocal, IsInternal, SupportsPersistentIDs', 'volume_was_boot': True, 'display_name': 'Terminal'}

sample_files.zip

tcptps commented

try to pass None as a positional argument for idx, worked for me
@mnrkbys

with open(fullpath, 'rb') as plist_file:
    data = PlistParser.parse(plist_file)
    # Iterate parsed plist and pass index/Alias data to parse_bookmark()
    for alias_record in AliasParser.parse(fullpath, None, data['Alias']):
           print(alias_record)
tcptps commented

from this example:

with open(fullpath, rb) as plist_file:
    data = PlistParser.parse(plist_file)
    # Iterate parsed plist and pass index/Alias data to parse_bookmark()
    for alias_record in AliasParser.parse(fullpath, idx, data['Alias']):
        print(alias_record)