使用 WMI 服务连接系统





5.00/5 (1投票)
使用 WMI 服务连接系统,包括远程和本地系统
引言
对于本技巧中的任何语法错误,敬请谅解。本技巧主要讲解如何连接 WMI 服务到本地和远程计算机。
背景
嗯,一开始我不想写这个技巧,因为网上已经有很多代码了。但很多时候,这些代码并不尽如人意。最终促使我写了这篇文章。希望我做到了。
Using the Code
很多时候,在连接 WMI 服务时,我都会收到“访问被拒绝”的错误消息。但我对 VC++ 并没有失去信心,这要归功于 MSDN。
这里有一个简单的程序,可以通过 WMI 服务连接到远程系统。
在每一步,我都检查了远程系统的安全性。
我从以下网址找到了获取主机名和域名的方法
http://msdn.microsoft.com/en-us/library/ms992621%28v=EXCHG.65%29.aspx
上面的部分是必需的,因为我们不知道是否会意外地输入本地计算机名,因为与 Explorer 不同,WMI 类无法连接到本地计算机。因此,为了预防起见,我使用了这个。另外,我们也不知道输入的字符串是计算机名还是 IP 地址。因此,我们使用了 Is3Dots
。如果提供了 IP 地址,则获取所提供 IP 的主机(计算机)名,然后执行比较。
CREDUI_INFO
结构用于传递用于 "CredUIPromptForCredentials" 的结构。这会提供凭据对话框,从中提取用户名和密码。一旦我们有了 **用户名** 和 **密码**,我们就可以为将来使用而保留它们。这里需要注意的重要一点是 -
slash = _tcschr ( pszName , L'\\' ) ;
if ( slash == NULL )
{
AfxMessageBox ( _T("Could not create Auth identity. No domain specified\nEnter the Credentails as \"DomainName\\UserName\"") ) ;
continue ;
}
这样可以确保我们一次性获取 **用户名** 和 **域名**。
运行窗口直到提供的 **用户名** 和 **密码** 与远程计算机的 Windows 凭据匹配,或者用户取消操作。在我们获取 **用户名** 和 **密码** 后,我们验证凭据。首先,我们使用 WNetCancelConnection2
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa385427%28v=vs.85%29.aspx)取消为远程计算机设置的所有凭据,然后使用 WNetUseConnection
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa385482%28v=vs.85%29.aspx),该函数使用用户提供的用户名和密码来验证连接详细信息。与 WNetAddConnection
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa385413%28v=vs.85%29.aspx)不同,它将使用先前提供的凭据。
这是在一个循环中进行的,直到执行了“成功”或“取消”操作。
在验证了远程系统后,我们可以通过步骤 4 连接到远程系统的 WMI 服务
hres = pLoc->ConnectServer( _bstr_t ( strServer ), _bstr_t ( useToken ? NULL : pszName ) , // User name _bstr_t ( useToken ? NULL : pszPwd ) , // User password NULL, // Locale NULL, // Security flags _bstr_t ( useNTLM ? NULL : pszAuthority ) ,// Authority NULL, // Context object &pSvc // IWbemServices proxy );
本地计算机的 strServer 将是 -
strServer = _T("\\\\.\\root\\cimv2") ;
远程系统的 strServer 将是 -
strServer = _T("\\\\<Computer_Name> or <IP Address>\\root\\cimv2") ;
C
OAUTHIDENTITY
在步骤 5 中起着重要作用,可用于设置代理的安全。
主要问题在于连接以及通过正确的逻辑来处理。这可以通过“CoSetProxyBlanket
”(http://msdn.microsoft.com/en-us/library/aa910618.aspx)来实现。正确使用它可以使我们一开始就“赢得一半的战斗”。这在步骤 6 和步骤 8 中完成。
CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_DEFAULT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_xxx
COLE_DEFAULT_PRINCIPAL, // Server principal name
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
userAcct, // client identity
EOAC_NONE // proxy capabilities
);
与其他语言一样,C++ 也通过 WMI 类维护安全性,这不仅有助于用户正确验证远程系统的凭据,还有助于开发人员维护安全性,以避免凭据验证中的任何缺陷或泄露。
在绑定了凭据之后,我们就可以在 ExecQuery
中获取所有需要的信息了,这在步骤 7 中完成。该函数看起来像 -
IEnumWbemClassObject* pEnumerator = NULL ; hres = pSvc->ExecQuery ( SysAllocString(L"WQL"), SysAllocString(L"Select * from Win32_LogicalDisk"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_WBEM_COMPLETE , NULL , &pEnumerator ) ;
凭据之后的重要部分是运行查询。在此示例中,我使用了 -Win32_LogicalDisk。此函数不区分大小写。
**步骤 7** 处理所需数据的提取。在此示例中,我只需要逻辑磁盘名称及其驱动器号。
我在每一步之后都使用了
函数,以便了解代码生成失败的位置,并从系统中适当地获取错误消息。GetErrorMessage
void GetErrorMessage ( HRESULT hresRet = NULL, CString strText = _T("") ) { LPVOID lpMsgBuf = NULL ; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL , hresRet , 0, (LPTSTR) &lpMsgBuf, 0, NULL ) ; strText = (LPCTSTR)lpMsgBuf + strText ; AfxMessageBox ( strText , MB_OK | MB_ICONERROR ) ; LocalFree ( lpMsgBuf ) ; }
在列表控件中收到输出后,请勿忘记在程序结束前释放所有使用的资源。优秀的程序员总是明智地使用计算机和代码资源。
要获取正确的信息,请转到 **运行** 命令,键入“**wbemtest
**”,然后连接到所需的计算机。
其他 WMI 类和参考可以在以下网址找到
http://msdn.microsoft.com/en-us/library/aa394554%28v=vs.85%29.aspx
一旦您熟悉了 WMI 类,就很容易理解。
WMI 类工具可以从以下网址下载 -
http://www.microsoft.com/en-us/download/details.aspx?id=24045
关注点
我搜索了数百个代码,但找不到正确的连接方法。这最终导致我破解了 Microsoft Windows 安全部门的 WMI 类。希望这能帮助您理解 WMI 类并提取所需的信息。
历史
将来我将发布一些关于枚举 WMI 类中的所有属性/标题和信息的内容。在那之前,祝您好运。