From 4ac69e9485040c7aac3c66c17586eefe73e8611b Mon Sep 17 00:00:00 2001 From: JSCU-CNI <121175071+JSCU-CNI@users.noreply.github.com> Date: Tue, 19 May 2026 12:34:31 +0200 Subject: [PATCH 1/2] Add pcat command to target-shell to read plist files --- dissect/target/tools/shell.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dissect/target/tools/shell.py b/dissect/target/tools/shell.py index b772090c5e..06ca0196e8 100644 --- a/dissect/target/tools/shell.py +++ b/dissect/target/tools/shell.py @@ -10,6 +10,7 @@ import logging import os import platform +import plistlib import pydoc import random import re @@ -23,6 +24,7 @@ from datetime import datetime, timedelta, timezone from enum import IntEnum from pathlib import Path, PurePosixPath +from pprint import pprint from tarfile import BLKTYPE, CHRTYPE, DIRTYPE, FIFOTYPE, LNKTYPE, REGTYPE, SYMTYPE from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, TextIO @@ -1504,6 +1506,16 @@ def cmd_hexdump(self, args: argparse.Namespace, stdout: TextIO) -> bool: return False + @arg("path", type=TargetPathArgument) + def cmd_pcat(self, args: argparse.Namespace, stdout: TextIO) -> bool: + """Print the contents of an Apple plist file.""" + paths = list(self.resolve_glob_path(args.path)) + for path in paths: + if len(paths) > 1: + print(path) + pprint(plistlib.load(path.open("rb")), stream=stdout) + return False + @arg("path", type=TargetPathArgument) @alias("digest") @alias("shasum") From ccc626e7b9ede3b5f5696311421e7e641fd571b8 Mon Sep 17 00:00:00 2001 From: Computer Network Investigation <121175071+JSCU-CNI@users.noreply.github.com> Date: Tue, 19 May 2026 15:07:46 +0200 Subject: [PATCH 2/2] Apply suggestion from @JSCU-CNI --- dissect/target/tools/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dissect/target/tools/shell.py b/dissect/target/tools/shell.py index 06ca0196e8..e1104f409b 100644 --- a/dissect/target/tools/shell.py +++ b/dissect/target/tools/shell.py @@ -1507,7 +1507,7 @@ def cmd_hexdump(self, args: argparse.Namespace, stdout: TextIO) -> bool: return False @arg("path", type=TargetPathArgument) - def cmd_pcat(self, args: argparse.Namespace, stdout: TextIO) -> bool: + def cmd_plcat(self, args: argparse.Namespace, stdout: TextIO) -> bool: """Print the contents of an Apple plist file.""" paths = list(self.resolve_glob_path(args.path)) for path in paths: