From e0c30d25cc979a871249cbc2f05a0370155ba67f Mon Sep 17 00:00:00 2001 From: Preslav Date: Thu, 6 Jun 2024 18:31:14 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20Use=20the=20registry=20directly?= =?UTF-8?q?=20to=20fetch=20Windows=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Preslav --- providers/os/registry/registrykey_windows.go | 8 +- .../os/resources/packages/windows_packages.go | 123 +++++++++++++----- 2 files changed, 98 insertions(+), 33 deletions(-) diff --git a/providers/os/registry/registrykey_windows.go b/providers/os/registry/registrykey_windows.go index 320dc25e22..20b708abab 100644 --- a/providers/os/registry/registrykey_windows.go +++ b/providers/os/registry/registrykey_windows.go @@ -112,9 +112,9 @@ func GetNativeRegistryKeyItems(path string) ([]RegistryKeyItem, error) { return res, nil } -func GetNativeRegistryKeyChildren(path string) ([]RegistryKeyChild, error) { - log.Debug().Str("path", path).Msg("search registry key children using native registry api") - key, path, err := parseRegistryKeyPath(path) +func GetNativeRegistryKeyChildren(fullPath string) ([]RegistryKeyChild, error) { + log.Debug().Str("path", fullPath).Msg("search registry key children using native registry api") + key, path, err := parseRegistryKeyPath(fullPath) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func GetNativeRegistryKeyChildren(path string) ([]RegistryKeyChild, error) { for i, entry := range entries { res[i] = RegistryKeyChild{ - Path: path, + Path: fullPath, Name: entry, } } diff --git a/providers/os/resources/packages/windows_packages.go b/providers/os/resources/packages/windows_packages.go index edc7571068..90c62159d9 100644 --- a/providers/os/resources/packages/windows_packages.go +++ b/providers/os/resources/packages/windows_packages.go @@ -14,6 +14,7 @@ import ( "go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory" "go.mondoo.com/cnquery/v11/providers/os/connection/shared" "go.mondoo.com/cnquery/v11/providers/os/detector/windows" + "go.mondoo.com/cnquery/v11/providers/os/registry" "go.mondoo.com/cnquery/v11/providers/os/resources/cpe" "go.mondoo.com/cnquery/v11/providers/os/resources/powershell" ) @@ -203,15 +204,78 @@ func (w *WinPkgManager) Format() string { return "win" } -const installedAppsScript = ` -Get-ItemProperty (@( - 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*', - 'HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*', - 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*', - 'HKCU:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*' -) | Where-Object { Test-Path $_ }) | -Select-Object -Property DisplayName,DisplayVersion,Publisher,EstimatedSize,InstallSource,UninstallString | ConvertTo-Json -Compress -` +func (w *WinPkgManager) getInstalledApps() ([]Package, error) { + pkgs := []string{ + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + "HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + "HKCU\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + } + packages := []Package{} + for _, r := range pkgs { + // we get all the packages, found under the pkgs paths + children, err := registry.GetNativeRegistryKeyChildren(r) + if err != nil { + continue + } + for _, c := range children { + // for each package the information is contained as children of that registry's key + p := w.getPackageFromRegistryKey(c) + if p == nil { + continue + } + packages = append(packages, *p) + } + } + return packages, nil +} + +func (w *WinPkgManager) getPackageFromRegistryKey(key registry.RegistryKeyChild) *Package { + items, err := registry.GetNativeRegistryKeyItems(key.Path + "\\" + key.Name) + if err != nil { + log.Debug().Err(err).Str("path", key.Path).Str("name", key.Name).Msg("could not read registry key items") + return nil + } + var uninstallString string + var displayName string + var displayVersion string + var publisher string + + for _, i := range items { + if i.Key == "UninstallString" { + uninstallString = i.Value.String + } + if i.Key == "DisplayName" { + displayName = i.Value.String + } + if i.Key == "DisplayVersion" { + displayVersion = i.Value.String + } + if i.Key == "Publisher" { + publisher = i.Value.String + } + } + + if uninstallString == "" { + return nil + } + + cpeWfn := "" + if displayName != "" && displayVersion != "" { + cpeWfn, err = cpe.NewPackage2Cpe(publisher, displayName, displayVersion, "", "") + if err != nil { + log.Debug().Err(err).Str("name", displayName).Str("version", displayVersion).Msg("could not create cpe for windows app package") + } + } else { + log.Debug().Msg("ignored package since information is missing") + } + return &Package{ + Name: displayName, + Version: displayVersion, + Format: "windows/app", + CPE: cpeWfn, + } +} // returns installed appx packages as well as hot fixes func (w *WinPkgManager) List() ([]Package, error) { @@ -221,19 +285,17 @@ func (w *WinPkgManager) List() ([]Package, error) { } pkgs := []Package{} - - cmd, err := w.conn.RunCommand(powershell.Encode(installedAppsScript)) - if err != nil { - return nil, fmt.Errorf("could not read app package list") - } - appPkgs, err := ParseWindowsAppPackages(cmd.Stdout) + appPkgs, err := w.getInstalledApps() if err != nil { return nil, fmt.Errorf("could not read app package list") } pkgs = append(pkgs, appPkgs...) - // only win 10+ are compatible with app x packages - if b.Build > 10240 { + canRunCmd := w.conn.Capabilities().Has(shared.Capability_RunCommand) + if !canRunCmd { + log.Debug().Msg("cannot run command on windows, skipping appx package list") + } else if b.Build > 10240 { + // only win 10+ are compatible with app x packages cmd, err := w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_APPX_PACKAGES)) if err != nil { return nil, fmt.Errorf("could not read appx package list") @@ -245,19 +307,22 @@ func (w *WinPkgManager) List() ([]Package, error) { pkgs = append(pkgs, appxPkgs...) } - // hotfixes - cmd, err = w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_HOTFIXES)) - if err != nil { - return nil, errors.Wrap(err, "could not fetch hotfixes") - } - hotfixes, err := ParseWindowsHotfixes(cmd.Stdout) - if err != nil { - return nil, errors.Wrapf(err, "could not parse hotfix results") - } - hotfixAsPkgs := HotFixesToPackages(hotfixes) - - pkgs = append(pkgs, hotfixAsPkgs...) + if !canRunCmd { + log.Debug().Msg("cannot run command on windows, skipping hotfix list") + } else { + // hotfixes + cmd, err := w.conn.RunCommand(powershell.Wrap(WINDOWS_QUERY_HOTFIXES)) + if err != nil { + return nil, errors.Wrap(err, "could not fetch hotfixes") + } + hotfixes, err := ParseWindowsHotfixes(cmd.Stdout) + if err != nil { + return nil, errors.Wrapf(err, "could not parse hotfix results") + } + hotfixAsPkgs := HotFixesToPackages(hotfixes) + pkgs = append(pkgs, hotfixAsPkgs...) + } return pkgs, nil }