Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add new wsl plugin #279

Merged
merged 3 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions regipy/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@
from .software.spp_clients import SppClientsPlugin
from .system.backuprestore import BackupRestorePlugin
from .system.timezone_data2 import TimezoneDataPlugin2
from .ntuser.wsl import WSLPlugin
111 changes: 111 additions & 0 deletions regipy/plugins/ntuser/wsl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import logging

from regipy.exceptions import RegistryKeyNotFoundException
from regipy.hive_types import NTUSER_HIVE_TYPE
from regipy.plugins.plugin import Plugin
from regipy.utils import convert_wintime

logger = logging.getLogger(__name__)

# Ressources : https://patrickwu.space/2020/07/19/wsl-related-registry/

WSL_PATH = r"\Software\Microsoft\Windows\CurrentVersion\Lxss"


class WSLPlugin(Plugin):
NAME = "wsl"
DESCRIPTION = "Get WSL information"
COMPATIBLE_HIVE = NTUSER_HIVE_TYPE

def get_wls_info(self, subkey, distribs=None):
if distribs is None:
distribs = []

try:
flags = subkey.get_value("Flags")
state = subkey.get_value("State")
version = subkey.get_value("Version")

# Initialize the entry for a distribution with its GUID as the key
distribution_entry = {
"GUID": subkey.name,
"last_modified": convert_wintime(
subkey.header.last_modified, as_json=self.as_json
),
"wsl_distribution_source_location": subkey.get_value("BasePath"),
"default_uid": subkey.get_value("DefaultUid"),
"distribution_name": subkey.get_value("DistributionName"),
"default_environment": subkey.get_value(
"DefaultEnvironment"
), # REG_MULTI_SZ
"flags": flags,
"kernel_command_line": subkey.get_value("KernelCommandLine"),
"package_family_name": subkey.get_value("PackageFamilyName"),
"state": state,
"filesystem": (
"lxfs" if version == 1 else "wslfs" if version == 2 else "Unknown"
),
}

# Decode flags for additional information
if flags is not None:
distribution_entry["enable_interop"] = bool(flags & 0x1)
distribution_entry["append_nt_path"] = bool(flags & 0x2)
distribution_entry["enable_drive_mounting"] = bool(flags & 0x4)

# Decode the state of the distribution
if state is not None:
if state == 0x1:
distribution_entry["state"] = "Normal"
elif state == 0x3:
distribution_entry["state"] = "Installing"
elif state == 0x4:
distribution_entry["state"] = "Uninstalling"
else:
distribution_entry["state"] = "Unknown"

# Add the distribution entry with its GUID to the list of distributions
distribs.append(distribution_entry)

except Exception as e:
logger.error(f"Error processing subkey {subkey.name}: {e}")
raise

return distribs

def run(self):

try:
# Attempt to get the WSL registry key
wsl_key = self.registry_hive.get_key(WSL_PATH)
except RegistryKeyNotFoundException as ex:
logger.error(f"Registry key not found at path {WSL_PATH}: {ex}")
return

self.entries = {
WSL_PATH: {
"last_modified": convert_wintime(
wsl_key.header.last_modified, as_json=self.as_json
),
"number_of_distrib": wsl_key.header.subkey_count,
"default_distrib_GUID": wsl_key.get_value("DefaultDistribution"),
"wsl_version": (
"WSL1"
if wsl_key.get_value("DefaultVersion") == 1
else (
"WSL2"
if wsl_key.get_value("DefaultVersion") == 2
else "Unknown"
)
),
"nat_ip_address": wsl_key.get_value("NatIpAddress"),
"distributions": [],
}
}

try:
for distrib in wsl_key.iter_subkeys():
distribs = self.get_wls_info(distrib)
self.entries[WSL_PATH]["distributions"] = distribs
except Exception as e:
logger.error(f"Error iterating over subkeys in {distrib.path}: {e}")
1 change: 1 addition & 0 deletions regipy_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@
from .validation.validation_tests import timezone_data2_validation
from .validation.validation_tests import winrar_plugin_validation
from .validation.validation_tests import winver_plugin_validation
from .validation.validation_tests import wsl_plugin_validation
Binary file added regipy_tests/data/NTUSER-WSL.DAT.xz
Binary file not shown.
1 change: 1 addition & 0 deletions regipy_tests/validation/plugin_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
| winscp_saved_sessions | Retrieve list of WinSCP saved sessions | WinSCPSavedSessionsPlugin | WinSCPSavedSessionsPluginValidationCase | True |
| winver_plugin | Get relevant OS information | WinVersionPlugin | WinVersionPluginValidationCase | True |
| word_wheel_query | Parse the word wheel query artifact | WordWheelQueryPlugin | WordWheelQueryPluginValidationCase | True |
| wsl | Get data about WSL | WSLPlugin | WSLPluginValidationCase | True |

## Plugins without validation
**Starting regipy v5.0.0 - plugin validation replaces tests and is mandatary, being enforced by the build process**
Expand Down
34 changes: 34 additions & 0 deletions regipy_tests/validation/validation_tests/wsl_plugin_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from regipy.plugins.ntuser.wsl import WSLPlugin
from regipy_tests.validation.validation import ValidationCase


class WSLPluginValidationCase(ValidationCase):
plugin = WSLPlugin
test_hive_file_name = "NTUSER-WSL.DAT.xz"
exact_expected_result = {
"\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss": {
"last_modified": "2024-11-26T23:13:44.535966+00:00",
"number_of_distrib": 4,
"default_distrib_GUID": "{e3986a51-3357-4c37-8a3e-1a83d995a3da}",
"wsl_version": "WSL2",
"nat_ip_address": None,
"distributions": [
{
"GUID": "{e3986a51-3357-4c37-8a3e-1a83d995a3da}",
"last_modified": "2024-11-26T23:06:39.553058+00:00",
"wsl_distribution_source_location": "C:\\Users\\admin\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\\LocalState",
"default_uid": 0,
"distribution_name": "Ubuntu-20.04",
"default_environment": None,
"flags": 7,
"kernel_command_line": None,
"package_family_name": "CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc",
"state": "Normal",
"filesystem": "wslfs",
"enable_interop": True,
"append_nt_path": True,
"enable_drive_mounting": True,
}
],
}
}