0x00 前言
最近遇到了一个有趣的问题: 我在尝试使用wmi获取当前系统已安装的程序列表时,并不能获得完整的列表。于是做了进一步研究,找出错误原因,改变思路,完成目标。
本文是一篇介绍基础知识的文章,用来解决基本的问题。
0x01 简介
本文将要介绍以下内容:
- 通过wmi获取当前系统已安装的程序列表
- wmi查询结果不完整的原因
- 获取完整程序列表的实现思路
0x02 获取当前系统已安装的程序列表
1、使用powershell调用wmi
代码如下:
Get-WmiObject -class Win32_Product
对输出结果进行过滤,只显示程序名称,代码如下:
Get-WmiObject -class Win32_Product |Select-Object -Property name
获得结果如下图
2、使用wmic调用wmi
代码如下:
wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product
对输出结果进行过滤,只显示程序名称,代码如下:
wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product get name /FORMAT:table
获得结果如下图
3、使用WMI Explorer调用wmi
下载地址:
https://wmie.codeplex.com/releases/view/135794
界面化的WMI查询工具,可用来查询wmi支持的类,是研究wmi的好工具
首先点击Connect
连接本机
选中ROOT\CIMV2
-> Query
输入查询命令:
SELECT * FROM Win32_Product
获得结果如下图
4、通过控制面板查询已安装的程序
控制面板
-> 程序
-> 程序和功能
发现部分程序通过wmi查询无法获得,例如Google Chrome,对比结果如下图
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
如下图
2、查询指定注册表项的注册表键值
(Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4F3742E0-700E-431D-BF19-5B27ED98E8F1}").DisplayName
如下图
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脚本,通过枚举注册表项,实现获得程序完整列表。作为一篇介绍基础知识的文章,希望能给新人带来启发。