导语:最近遇到了一个有趣的问题: 我在尝试使用wmi获取当前系统已安装的程序列表时,并不能获得完整的列表。于是做了进一步研究,找出错误原因,改变思路,完成目标。

0x00 前言

最近遇到了一个有趣的问题:我在尝试使用wmi获取当前系统已安装的程序列表时,并不能获得完整的列表。于是做了进一步研究,找出错误原因,改变思路,完成目标。

本文是一篇介绍基础知识的文章,用来解决基本的问题。

0x01 简介

本文将要介绍以下内容:

·通过wmi获取当前系统已安装的程序列表

·wmi查询结果不完整的原因

·获取完整程序列表的实现思路

0x02 获取当前系统已安装的程序列表

1、使用powershell调用wmi

代码如下:

Get-WmiObject -class Win32_Product

对输出结果进行过滤,只显示程序名称,代码如下:

Get-WmiObject -class Win32_Product |Select-Object -Property name

获得结果如下图

01.png

2、使用wmic调用wmi

代码如下:

wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product

对输出结果进行过滤,只显示程序名称,代码如下:

wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product get name /FORMAT:table

获得结果如下图

02.png

3、使用WMI Explorer调用wmi

下载地址:

https://wmie.codeplex.com/releases/view/135794

界面化的WMI查询工具,可用来查询wmi支持的类,是研究wmi的好工具

首先点击Connect连接本机

选中ROOT\CIMV2 -> Query

输入查询命令:

SELECT * FROM Win32_Product

获得结果如下图

03.png

4、通过控制面板查询已安装的程序

控制面板 -> 程序 -> 程序和功能

发现部分程序通过wmi查询无法获得,例如Google Chrome,对比结果如下图

04.png

0x03 wmi查询结果不完整的原因

通过WMI查询Win32_Product只能获得特定的程序列表

这些程序有一个共同的特征: 安装包由Windows Installer制作,安装过程中调用Windows Installer服务进行安装

说明:

Microsoft Windows Installer: Windows 操作系统的一个组件,是安装和卸载软件的标准基础。

Windows Installer服务: 添加、修改和删除作为Windows Installer程序包提供的应用程序。

除了Microsoft Windows Installer,制作安装包还可使用EasySetup、Setup2Go、Advanced Installer、Qt installer framework和WinRAR

Chrome的在安装过程中不会调用Microsoft Windows Installer组件,所以通过WMI查询Win32_Product无法找到Chrome

0x04 获取完整程序列表的实现思路

我们知道,通过控制面板 -> 程序 -> 程序和功能获取的程序列表比较完整,该列表对应注册表键值:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\

每个子健代表列表中的一个程序

所以,可以通过枚举注册表键值的方法获得完整程序列表

值得注意的是64位系统下,注册表存在重定向的问题,也会影响程序列表的显示

32位程序列表对应注册表键值HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\

64位程序列表对应注册表键值HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\

注:

这个问题在之前的文章《关于32位程序在64位系统下运行中需要注意的重定向问题》进行过整理

编写powershell脚本实现枚举注册表,获得完整的程序列表

关键代码:

1、枚举指定注册表项下的子项

dir Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -Name

如下图

05.png

2、查询指定注册表项的注册表键值

(Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4F3742E0-700E-431D-BF19-5B27ED98E8F1}").DisplayName

如下图

06.png

3、加入foreach循环实现枚举

$RegPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
$QueryPath = dir $RegPath -Name
foreach($Name in $QueryPath)
{
    (Get-ItemProperty -Path $RegPath$Name).DisplayName
}

4、加入判断系统位数,自动判断注册表重定向

完整代码可参考如下地址:

https://github.com/3gstudent/ListInstalledPrograms

0x05 补充

通常,已安装的程序会创建快捷方式,所以,尝试枚举快捷方式文件也能获得完整的程序列表

通过wmic获取所有快捷方式:

wmic PATH Win32_ShortcutFile get name /FORMAT:table

0x06 小结

本文介绍了通过wmi无法获得当前系统已安装程序完整列表的原因,编写powershell脚本,通过枚举注册表项,实现获得程序完整列表。作为一篇介绍基础知识的文章,希望能给新人带来启发。

源链接

Hacking more

...