mirror of https://git.48k.eu/ogclient
src: refactor windows hive code
Remove usage of hivexget as a subprocess and use Python hivex to inspect the Windows Registry. Use registry path constants defined in src.utils.winreg Remove windows_is64bit() funcion as the code to identify the architecture relies on a broken Registry query. Fixing the query proved to be a challenge and the only implication is the removal of the string "64 bits" at the end of the listed Windows OS installed in each partition. Use utility function in src.utils.winreg to make the software inventory code more compact. Rewrite onliner in _fill_package_set function and parse the registry with a for loop.master
parent
aa570e66e6
commit
855768e144
|
@ -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)
|
||||
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 = proc_prodname.stdout.decode().replace('\n', '')
|
||||
releaseid = proc_releaseid.stdout.decode().replace('\n', '')
|
||||
bits = ' 64 bits' if windows_is64bit(winreghives) else ''
|
||||
prodname = get_value_from_node(hive, version_node, 'ProductName')
|
||||
releaseid = get_value_from_node(hive, version_node, 'ReleaseId')
|
||||
|
||||
if proc_prodname.returncode == 0 and proc_releaseid.returncode == 0:
|
||||
return f'{prodname} {releaseid}{bits}'
|
||||
except FileNotFoundError: # hivexget command not found
|
||||
pass
|
||||
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):
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue