Skip to content

Commit

Permalink
🧹 Use the registry directly to fetch Windows packages
Browse files Browse the repository at this point in the history
Signed-off-by: Preslav <[email protected]>
  • Loading branch information
preslavgerchev committed Jun 6, 2024
1 parent 7b1e2dd commit c677035
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 33 deletions.
8 changes: 4 additions & 4 deletions providers/os/registry/registrykey_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -137,7 +137,7 @@ func GetNativeRegistryKeyChildren(path string) ([]RegistryKeyChild, error) {

for i, entry := range entries {
res[i] = RegistryKeyChild{
Path: path,
Path: fullPath,
Name: entry,
}
}
Expand Down
123 changes: 94 additions & 29 deletions providers/os/resources/packages/windows_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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) {
Expand All @@ -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")
Expand All @@ -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
}

Expand Down

0 comments on commit c677035

Please sign in to comment.