diff options
-rw-r--r-- | src/utils/probe.py | 65 | ||||
-rw-r--r-- | src/utils/sw_inventory.py | 60 |
2 files changed, 47 insertions, 78 deletions
diff --git a/src/utils/probe.py b/src/utils/probe.py index ee9a08e..c8218f2 100644 --- a/src/utils/probe.py +++ b/src/utils/probe.py @@ -12,6 +12,7 @@ import platform import logging import sys +from src.utils.winreg import * from enum import Enum from subprocess import PIPE @@ -45,35 +46,23 @@ def getlinuxversion(osrelease): def getwindowsversion(winreghives): """ - Tries to obtain windows version information by - querying the SOFTWARE registry hive. Registry - hives path is a required parameter. - - Runs hivexget(1) to fetch ProductName and - ReleaseId. If something fails (hivexget is - not installed, or registry is not found) it - returns a generic "Microsoft Windows" string. + Try to obtain windows version information by querying the SOFTWARE registry + hive to fetch ProductName and ReleaseId. + Return a generic "Microsoft Windows" string if something fails. """ - # XXX: 3.6 friendly try: - proc_prodname = subprocess.run(['hivexget', - f'{winreghives}/SOFTWARE', - 'microsoft\windows nt\currentversion', - 'ProductName'], stdout=PIPE) - proc_releaseid = subprocess.run(['hivexget', - f'{winreghives}/SOFTWARE', - 'microsoft\windows nt\currentversion', - 'ReleaseId'], stdout=PIPE) - - prodname = proc_prodname.stdout.decode().replace('\n', '') - releaseid = proc_releaseid.stdout.decode().replace('\n', '') - bits = ' 64 bits' if windows_is64bit(winreghives) else '' - - if proc_prodname.returncode == 0 and proc_releaseid.returncode == 0: - return f'{prodname} {releaseid}{bits}' - except FileNotFoundError: # hivexget command not found - pass + hivepath = f'{winreghives}/SOFTWARE' + hive = hive_handler_open(hivepath, write = False) + root_node = hive.root() + version_node = get_node_child_from_path(hive, root_node, 'Microsoft/Windows NT/CurrentVersion') + + prodname = get_value_from_node(hive, version_node, 'ProductName') + releaseid = get_value_from_node(hive, version_node, 'ReleaseId') + + return f'{prodname} {releaseid}' + except (RuntimeError, OgError) as e: + logging.error(f'Hivex was not able to operate over {hivepath}. Reported: {e}') return 'Microsoft Windows' @@ -81,28 +70,6 @@ def interpreter_is64bit(): return sys.maxsize > 2**32 -def windows_is64bit(winreghives): - """ - Check for 64 bit Windows by means of retrieving the value of - ProgramW6432Dir. This key is set if Windows is running 64 bit. - - If set returns True. - If not set or hivexget exits with non-zero, returns False. - """ - try: - proc_hivexget = subprocess.run(['hivexget', - f'{winreghives}/SOFTWARE', - 'Microsoft\Windows\CurrentVersion', - 'ProgramW6432Dir'], stdout=PIPE) - stdout = proc_hivexget.stdout.decode().replace('\n', '') - - if proc_hivexget.returncode == 0 and stdout: - return True - except FileNotFoundError: # hivexget command not found - pass - return False - - def linux_is64bit(mountpoint): """ If /sbin/init is detected, check if compiled for 64-bit machine. @@ -174,7 +141,7 @@ def os_probe(mountpoint): Returns a string depending on the OS it detects. """ - winreghives = f'{mountpoint}/Windows/System32/config' + winreghives = f'{mountpoint}{WINDOWS_HIVES_PATH}' osrelease = f'{mountpoint}/etc/os-release' if os.path.exists(osrelease): diff --git a/src/utils/sw_inventory.py b/src/utils/sw_inventory.py index bcf9f09..ccb70fe 100644 --- a/src/utils/sw_inventory.py +++ b/src/utils/sw_inventory.py @@ -16,33 +16,39 @@ from collections import namedtuple import hivex from src.utils.probe import os_probe +from src.utils.winreg import * Package = namedtuple('Package', ['name', 'version']) Package.__str__ = lambda pkg: f'{pkg.name} {pkg.version}' -WINDOWS_HIVES_PATH = '/Windows/System32/config' -WINDOWS_HIVES_SOFTWARE = f'{WINDOWS_HIVES_PATH}/SOFTWARE' DPKG_STATUS_PATH = '/var/lib/dpkg/status' OSRELEASE_PATH = '/etc/os-release' -def _fill_package_set(h, key, pkg_set): +def _fill_package_set(hive, key, pkg_set): """ Fill the package set looking for entries at the current registry node childs. Any valid node child must have "DisplayVersion" or "DisplayName" keys. """ - childs = h.node_children(key) - valid_childs = [h.node_get_child(key, h.node_name(child)) - for child in childs - for value in h.node_values(child) if h.value_key(value) == 'DisplayVersion'] + childs = hive.node_children(key) + valid_childs = [] + for child in childs: + child_name = hive.node_name(child) + values = hive.node_values(child) + + for value in values: + if hive.value_key(value) == 'DisplayVersion': + valid_child = hive.node_get_child(key, child_name) + valid_childs.append(valid_child) + for ch in valid_childs: try: - name = h.value_string(h.node_get_value(ch, 'DisplayName')) - value = h.node_get_value(ch, 'DisplayVersion') - version = h.value_string(value) + name = hive.value_string(hive.node_get_value(ch, 'DisplayName')) + value = hive.node_get_value(ch, 'DisplayVersion') + version = hive.value_string(value) pkg = Package(name, version) pkg_set.add(pkg) except RuntimeError: @@ -50,22 +56,19 @@ def _fill_package_set(h, key, pkg_set): pass -def _fill_package_set_1(h, pkg_set): +def _fill_package_set_1(hive, pkg_set): """ Looks for entries in registry path /Microsoft/Windows/CurrentVersion/Uninstall Fills the given set with Package instances for each program found. """ - key = h.root() - key = h.node_get_child(key, 'Microsoft') - key = h.node_get_child(key, 'Windows') - key = h.node_get_child(key, 'CurrentVersion') - key = h.node_get_child(key, 'Uninstall') - _fill_package_set(h, key, pkg_set) + root_node = hive.root() + key = get_node_child_from_path(hive, root_node, 'Microsoft/Windows/CurrentVersion/Uninstall') + _fill_package_set(hive, key, pkg_set) -def _fill_package_set_2(h, pkg_set): +def _fill_package_set_32_bit_compat(hive, pkg_set): """ Looks for entries in registry path /Wow6432Node/Microsoft/Windows/CurrentVersion/Uninstall @@ -73,23 +76,22 @@ def _fill_package_set_2(h, pkg_set): Fills the given set with Package instances for each program found. """ - key = h.root() - key = h.node_get_child(key, 'Wow6432Node') - key = h.node_get_child(key, 'Microsoft') - key = h.node_get_child(key, 'Windows') - key = h.node_get_child(key, 'CurrentVersion') - key = h.node_get_child(key, 'Uninstall') - _fill_package_set(h, key, pkg_set) + root_node = hive.root() + key = get_node_child_from_path(hive, root_node, 'Wow6432Node/Windows/CurrentVersion/Uninstall') + _fill_package_set(hive, key, pkg_set) def _get_package_set_windows(hivepath): packages = set() try: - h = hivex.Hivex(hivepath) + h = hive_handler_open(hivepath, write = False) _fill_package_set_1(h, packages) - _fill_package_set_2(h, packages) - except RuntimeError as e: + except (RuntimeError, OgError) as e: logging.error(f'Hivex was not able to operate over {hivepath}. Reported: {e}') + try: + _fill_package_set_32_bit_compat(h, packages) + except (RuntimeError, OgError) as e: + pass return packages @@ -119,7 +121,7 @@ def _get_package_set_dpkg(dpkg_status_path): def get_package_set(mountpoint): dpkg_status_path = f'{mountpoint}{DPKG_STATUS_PATH}' - softwarehive = f'{mountpoint}{WINDOWS_HIVES_SOFTWARE}' + softwarehive = f'{mountpoint}{WINDOWS_HIVE_SOFTWARE}' if os.path.exists(softwarehive): pkgset = _get_package_set_windows(softwarehive) elif os.path.exists(dpkg_status_path): |