Skip to content

Commit

Permalink
Merge branch 'main' into parallels
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper committed May 2, 2023
2 parents 44bb782 + 6e02f7a commit 2d837d0
Show file tree
Hide file tree
Showing 23 changed files with 455 additions and 207 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pip install dissect.target

This module is also automatically installed if you install the `dissect` package.

If you wish to use the YARA plugin (`target-query -f yara`), you can install `dissect.target[yara]` to automatically
install the `yara-python` dependency.

## Tools inside this project

### target-query
Expand Down
5 changes: 3 additions & 2 deletions dissect/target/helpers/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ def __init__(self, fs: Filesystem):
self.file_handles: dict[int, BinaryIO] = {}
self.dir_handles: dict[int, FilesystemEntry] = {}

@lru_cache(CACHE_SIZE)
self._get = lru_cache(CACHE_SIZE)(self._get)
self.getattr = lru_cache(CACHE_SIZE)(self.getattr)

def _get(self, path: str) -> FilesystemEntry:
try:
return self.fs.get(path)
except Exception:
raise FuseOSError(errno.ENOENT)

@lru_cache(CACHE_SIZE)
def getattr(self, path: str, fh: Optional[int] = None) -> dict:
fe = self._get(path)

Expand Down
2 changes: 1 addition & 1 deletion dissect/target/loaders/targetd.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
TARGETD_AVAILABLE = False
try:
from flow import remoting
from targetd.client import Client
from targetd.clients import Client

TARGETD_AVAILABLE = True
except Exception:
Expand Down
130 changes: 84 additions & 46 deletions dissect/target/plugins/browsers/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,35 @@
from dissect.target.helpers.record import create_extended_descriptor
from dissect.target.plugin import Plugin, export

GENERIC_DOWNLOAD_RECORD_FIELDS = [
("datetime", "ts_start"),
("datetime", "ts_end"),
("string", "browser"),
("varint", "id"),
("path", "path"),
("uri", "url"),
("filesize", "size"),
("varint", "state"),
("path", "source"),
]

GENERIC_EXTENSION_RECORD_FIELDS = [
("datetime", "ts_install"),
("datetime", "ts_update"),
("string", "browser"),
("string", "id"),
("string", "name"),
("string", "short_name"),
("string", "default_title"),
("string", "description"),
("string", "version"),
("path", "ext_path"),
("boolean", "from_webstore"),
("string[]", "permissions"),
("varint", "manifest_version"),
("path", "source"),
]

GENERIC_HISTORY_RECORD_FIELDS = [
("datetime", "ts"),
("string", "browser"),
Expand All @@ -20,25 +49,15 @@
("uri", "from_url"),
("path", "source"),
]
GENERIC_DOWNLOAD_RECORD_FIELDS = [
("datetime", "ts_start"),
("datetime", "ts_end"),
("string", "browser"),
("varint", "id"),
("path", "path"),
("uri", "url"),
("filesize", "size"),
("varint", "state"),
("path", "source"),
]

BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/history", GENERIC_HISTORY_RECORD_FIELDS
)

BrowserDownloadRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/download", GENERIC_DOWNLOAD_RECORD_FIELDS
)
BrowserExtensionRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/extension", GENERIC_EXTENSION_RECORD_FIELDS
)
BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/history", GENERIC_HISTORY_RECORD_FIELDS
)


class BrowserPlugin(Plugin):
Expand Down Expand Up @@ -69,16 +88,6 @@ def __init__(self, target):
except Exception:
target.log.exception("Failed to load browser plugin: %s", entry)

def check_compatible(self) -> bool:
"""Perform a compatibility check with the target.
This function checks if any of the supported browser plugins
can be used. Otherwise it should raise an ``UnsupportedPluginError``.
Raises:
UnsupportedPluginError: If the plugin could not be loaded.
"""
if not len(self._plugins):
raise UnsupportedPluginError("No compatible browser plugins found")

def _func(self, func_name: str):
"""Return the supported browser plugin records.
Expand All @@ -95,6 +104,55 @@ def _func(self, func_name: str):
except Exception:
self.target.log.exception("Failed to execute browser plugin: %s.%s", plugin_name._name, func_name)

def check_compatible(self) -> bool:
if not len(self._plugins):
raise UnsupportedPluginError("No compatible browser plugins found")

@export(record=BrowserDownloadRecord)
def downloads(self):
"""Return browser download records from all browsers installed and supported.
Yields BrowserDownloadRecord with the following fields:
hostname (string): The target hostname.
domain (string): The target domain.
ts_start (datetime): Download start timestamp.
ts_end (datetime): Download end timestamp.
browser (string): The browser from which the records are generated from.
id (string): Record ID.
path (string): Download path.
url (uri): Download URL.
size (varint): Download file size.
state (varint): Download state number.
source: (path): The source file of the download record.
"""
yield from self._func("downloads")

@export(record=BrowserExtensionRecord)
def extensions(self):
"""Return browser extensions from all browsers installed and supported.
Browser extensions for Chrome, Chromium, and Edge (Chromium).
Yields BrowserExtensionRecord with the following fields:
hostname (string): The target hostname.
domain (string): The target domain.
ts_install (datetime): Extension install timestamp.
ts_update (datetime): Extension update timestamp.
browser (string): The browser from which the records are generated.
id (string): Extension unique identifier.
name (string): Name of the extension.
short_name (string): Short name of the extension.
default_title (string): Default title of the extension.
description (string): Description of the extension.
version (string): Version of the extension.
ext_path (path): Relative path of the extension.
from_webstore (boolean): Extension from webstore.
permissions (string[]): Permissions of the extension.
manifest (varint): Version of the extensions' manifest.
source: (path): The source file of the download record.
"""
yield from self._func("extensions")

@export(record=BrowserHistoryRecord)
def history(self):
"""Return browser history records from all browsers installed and supported.
Expand Down Expand Up @@ -122,26 +180,6 @@ def history(self):
"""
yield from self._func("history")

@export(record=BrowserDownloadRecord)
def downloads(self):
"""Return browser download records from all browsers installed and supported.
Yields:
BrowserDownloadRecord with the following fieds:
hostname (string): The target hostname.
domain (string): The target domain.
ts_start (datetime): Download start timestamp.
ts_end (datetime): Download end timestamp.
browser (string): The browser from which the records are generated from.
id (string): Record ID.
path (string): Download path.
url (uri): Download URL.
size (varint): Download file size.
state (varint): Download state number.
source: (path): The source file of the download record.
"""
yield from self._func("downloads")


def try_idna(url: str) -> bytes:
"""Attempts to convert a possible Unicode url to ASCII using the IDNA standard.
Expand Down
26 changes: 18 additions & 8 deletions dissect/target/plugins/browsers/chrome.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from dissect.target.plugin import Plugin, export
from dissect.target.plugins.browsers.browser import (
GENERIC_DOWNLOAD_RECORD_FIELDS,
GENERIC_EXTENSION_RECORD_FIELDS,
GENERIC_HISTORY_RECORD_FIELDS,
)
from dissect.target.plugins.browsers.chromium import ChromiumMixin
Expand All @@ -20,22 +21,31 @@ class ChromePlugin(ChromiumMixin, Plugin):
"Local Settings/Application Data/Google/Chrome/User Data/Default",
# Linux
".config/google-chrome/Default",
".var/app/com.google.Chrome/config/google-chrome/Default",
# Macos
"Library/Application Support/Google/Chrome/Default",
]
BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/chrome/history", GENERIC_HISTORY_RECORD_FIELDS
)
BrowserDownloadRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/chrome/download", GENERIC_DOWNLOAD_RECORD_FIELDS
)

@export(record=BrowserHistoryRecord)
def history(self):
"""Return browser history records for Google Chrome."""
yield from super().history("chrome")
BrowserExtensionRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/chrome/extension", GENERIC_EXTENSION_RECORD_FIELDS
)
BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
"browser/chrome/history", GENERIC_HISTORY_RECORD_FIELDS
)

@export(record=BrowserDownloadRecord)
def downloads(self):
"""Return browser download records for Google Chrome."""
yield from super().downloads("chrome")

@export(record=BrowserExtensionRecord)
def extensions(self):
"""Return browser extension records for Google Chrome."""
yield from super().extensions("chrome")

@export(record=BrowserHistoryRecord)
def history(self):
"""Return browser history records for Google Chrome."""
yield from super().history("chrome")
Loading

0 comments on commit 2d837d0

Please sign in to comment.