-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
201 additions
and
1 deletion.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from typing import Iterator | ||
|
||
from dissect.target.exceptions import UnsupportedPluginError | ||
from dissect.target.helpers import configutil | ||
from dissect.target.helpers.fsutil import TargetPath | ||
from dissect.target.helpers.record import UnixApplicationRecord | ||
from dissect.target.plugin import Plugin, export | ||
from dissect.target.target import Target | ||
|
||
|
||
class UnixApplicationsPlugin(Plugin): | ||
"""Unix Applications plugin.""" | ||
|
||
SYSTEM_PATHS = [ | ||
"/usr/share/applications/", | ||
"/usr/local/share/applications/", | ||
"/var/lib/snapd/desktop/applications/", | ||
"/var/lib/flatpak/exports/share/applications/", | ||
] | ||
|
||
USER_PATHS = [ | ||
".local/share/applications/", | ||
] | ||
|
||
SYSTEM_APPS = [ | ||
"org.gnome.", | ||
] | ||
|
||
def __init__(self, target: Target): | ||
super().__init__(target) | ||
self.desktop_files = list(self.find_desktop_files()) | ||
|
||
def find_desktop_files(self) -> Iterator[TargetPath]: | ||
for dir in self.SYSTEM_PATHS: | ||
for file in self.target.fs.path(dir).glob("*.desktop"): | ||
yield file | ||
|
||
for user_details in self.target.user_details.all_with_home(): | ||
for dir in self.USER_PATHS: | ||
for file in user_details.home_path.joinpath(dir).glob("*.desktop"): | ||
yield file | ||
|
||
def check_compatible(self) -> None: | ||
if not self.desktop_files: | ||
raise UnsupportedPluginError("No application .desktop files found") | ||
|
||
@export(record=UnixApplicationRecord) | ||
def applications(self) -> Iterator[UnixApplicationRecord]: | ||
"""Yield installed Unix GUI applications from GNOME and XFCE. | ||
Resources: | ||
- https://wiki.archlinux.org/title/Desktop_entries | ||
- https://specifications.freedesktop.org/desktop-entry-spec/latest/ | ||
- https://unix.stackexchange.com/questions/582928/where-gnome-apps-are-installed | ||
""" | ||
for file in self.desktop_files: | ||
parser = configutil.parse(file, hint="ini") | ||
config = parser.get("Desktop Entry") or {} | ||
stat = file.lstat() | ||
|
||
yield UnixApplicationRecord( | ||
ts_modified=stat.st_mtime, | ||
ts_installed=stat.st_btime if hasattr(stat, "st_btime") else None, | ||
name=config.get("Name"), | ||
version=config.get("Version"), | ||
path=config.get("Exec"), | ||
type="system" if config.get("Icon", "")[0:10] in self.SYSTEM_APPS else "user", | ||
_target=self.target, | ||
) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from typing import Iterator | ||
|
||
from dissect.target.exceptions import UnsupportedPluginError | ||
from dissect.target.filesystems.squashfs import SquashFSFilesystem | ||
from dissect.target.helpers import configutil | ||
from dissect.target.helpers.fsutil import TargetPath | ||
from dissect.target.helpers.record import UnixApplicationRecord | ||
from dissect.target.plugin import Plugin, export | ||
from dissect.target.target import Target | ||
|
||
|
||
class SnapPlugin(Plugin): | ||
"""Canonical Linux Snapcraft plugin. | ||
Reads information from installed ``*.snap`` files found in ``/var/lib/snapd/snaps``. | ||
Logs of the ``snapd`` daemon can be parsed using the ``journal`` or ``syslog`` plugins. | ||
Resources: | ||
- https://github.com/canonical/snapcraft | ||
- https://en.wikipedia.org/wiki/Snap_(software) | ||
""" | ||
|
||
PATHS = [ | ||
"/var/lib/snapd/snaps", | ||
] | ||
|
||
def __init__(self, target: Target): | ||
super().__init__(target) | ||
self.installs = list(self._find_installs()) | ||
|
||
def check_compatible(self) -> None: | ||
if not configutil.HAS_YAML: | ||
raise UnsupportedPluginError("Missing required dependency ruamel.yaml") | ||
|
||
if not self.installs: | ||
raise UnsupportedPluginError("No snapd install folder(s) found") | ||
|
||
def _find_installs(self) -> Iterator[TargetPath]: | ||
for str_path in self.PATHS: | ||
if (path := self.target.fs.path(str_path)).exists(): | ||
yield path | ||
|
||
@export(record=UnixApplicationRecord) | ||
def snap(self) -> Iterator[UnixApplicationRecord]: | ||
"""Yield installed snap packages.""" | ||
|
||
for install_path in self.installs: | ||
for snap in install_path.glob("*.snap"): | ||
try: | ||
squashfs = SquashFSFilesystem(snap.open()) | ||
|
||
except (ValueError, NotImplementedError) as e: | ||
self.target.log.warning("Unable to open snap file %s", snap) | ||
self.target.log.debug("", exc_info=e) | ||
continue | ||
|
||
if not (meta := squashfs.path("meta/snap.yaml")).exists(): | ||
self.target.log.warning("Snap %s has no meta/snap.yaml file") | ||
continue | ||
|
||
meta_data = configutil.parse(meta, hint="yaml") | ||
|
||
yield UnixApplicationRecord( | ||
ts_modified=meta.lstat().st_mtime, | ||
name=meta_data.get("name"), | ||
version=meta_data.get("version"), | ||
path=snap, | ||
_target=self.target, | ||
) |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from typing import Iterator | ||
|
||
from dissect.target.exceptions import UnsupportedPluginError | ||
from dissect.target.helpers.record import WindowsApplicationRecord | ||
from dissect.target.plugin import Plugin, export | ||
from dissect.target.target import Target | ||
|
||
|
||
class WindowsApplicationsPlugin(Plugin): | ||
"""Windows Applications plugin.""" | ||
|
||
KEY = "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" | ||
|
||
def __init__(self, target: Target): | ||
super().__init__(target) | ||
self.keys = list(self.target.registry.keys(self.KEY)) | ||
|
||
def check_compatible(self) -> None: | ||
if not self.target.has_function("registry"): | ||
raise UnsupportedPluginError("No Windows registry found") | ||
|
||
if not self.keys: | ||
raise UnsupportedPluginError("No 'Uninstall' registry keys found") | ||
|
||
@export(record=WindowsApplicationRecord) | ||
def applications(self) -> Iterator[WindowsApplicationRecord]: | ||
"""Yields installed applications from the Windows registry.""" | ||
for uninstall in self.keys: | ||
for app in uninstall.subkeys(): | ||
values = {value.name: value.value for value in app.values()} | ||
|
||
yield WindowsApplicationRecord( | ||
ts_modified=app.ts, | ||
ts_installed=values.get("InstallDate"), | ||
name=values.get("DisplayName"), | ||
version=values.get("DisplayVersion"), | ||
author=values.get("Publisher"), | ||
type="system" if values.get("SystemComponent") else "user", | ||
path=values.get("DisplayIcon") or values.get("InstallLocation") or values.get("InstallSource"), | ||
_target=self.target, | ||
) |
Empty file.
Empty file.
Empty file.