关于使用WMI获取杀毒软件信息

在学习本文前,你需要一点点的VBS基础,WMI了解常识,COM接口皮毛就行。

 

今天的问题是,如何获得系统中安装的杀毒软件?有人会说遍历注册表之类的。其实用不着这么麻烦。每个正式的AV(Anti-Virus)软件,都要向系统注册自己。通过查看WMI中的/root/SecurityCenter这个名称空间,我们就能知道其中装了那些反病毒产品。

我们来看一段Vbs代码:

[vb]  view plain  copy
  1. strComputer = "."  
  2. Set objComputer = CreateObject("Shell.LocalMachine")  
  3. Set oWMI = GetObject("winmgmts://" & strComputer & "/root/SecurityCenter")  
  4. Set colAV = oWMI.ExecQuery("Select * from AntiVirusProduct")  
  5.   For Each objAntiVirusProduct In colAV  
  6.    If IsNull(objAntiVirusProduct.instanceGuid) Then  
  7.     strSubject = "Anti-virus is not running on " & objComputer.MachineName  
  8.     strTextbody = "You will need to check on " & objComputer.MachineName   
  9.     Call SmtpServer    
  10.    Else  
  11.     strCompany = objAntiVirusProduct.companyName  
  12.     strAV = objAntiVirusProduct.displayName  
  13.     strScanning = objAntiVirusProduct.onAccessScanningEnabled  
  14.     strUptodate = objAntiVirusProduct.productUptoDate  

如果以上代码你觉得很难懂的话,那么不推荐你继续看下去,请稍微补习下Vbs和Wmi相关的知识。

Select * from AntiVirusProduct是一条WQL语句,用来查询所有的反病毒软件,并返回一个集合。我们用WMITools里面的WMI CIM Studio进行查看下/root/SecurityCenter这个名称空间里面有哪些Win32 Class


 在左边,看到了么,AntiVirusProduct。还有FireWallProduct,防火墙产品,本机没有防火墙,就用查看反病毒软件来做说明吧。

右边的呢,都是AntiVirusProduct这个类的属性(Properties)。里面有产品名,产品公司名,版本号等等。那么我现在需要的,就是通过C++获取到和Vbs一样的信息。上面的Vbs脚本不知道你执行过了么?

我们接下来看C++代码

[cpp]  view plain  copy
  1. #define _WIN32_DCOM  
  2.   
  3. #include <iostream>  
  4.   
  5. using namespace std;  
  6.   
  7. #include <comdef.h>  
  8.   
  9. #include <Wbemidl.h>  
  10.   
  11.   
  12. # pragma comment(lib, "wbemuuid.lib")  
  13.   
  14.   
  15. int main(int argc, char **argv)  
  16.   
  17. {  
  18.   
  19.     HRESULT hres;  
  20.   
  21.   
  22.     // Step 1: --------------------------------------------------  
  23.   
  24.     // Initialize COM. ------------------------------------------  
  25.   
  26.   
  27.     hres =  CoInitializeEx(0, COINIT_MULTITHREADED);   
  28.   
  29.     if (FAILED(hres))  
  30.   
  31.     {  
  32.   
  33.         cout << "Failed to initialize COM library. Error code = 0x"   
  34.   
  35.             << hex << hres << endl;  
  36.   
  37.         return 1;                  // Program has failed.  
  38.   
  39.     }  
  40.   
  41.   
  42.     // Step 2: --------------------------------------------------  
  43.   
  44.     // Set general COM security levels --------------------------  
  45.   
  46.   
  47.     hres =  CoInitializeSecurity(  
  48.   
  49.         NULL,   
  50.   
  51.         -1,                          // COM authentication  
  52.   
  53.         NULL,                        // Authentication services  
  54.   
  55.         NULL,                        // Reserved  
  56.   
  57.         RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication   
  58.   
  59.         RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation    
  60.   
  61.         NULL,                        // Authentication info  
  62.   
  63.         EOAC_NONE,                   // Additional capabilities   
  64.   
  65.         NULL                         // Reserved  
  66.   
  67.         );            
  68.   
  69.     if (FAILED(hres))  
  70.   
  71.     {  
  72.   
  73.         cout << "Failed to initialize security. Error code = 0x"   
  74.   
  75.             << hex << hres << endl;  
  76.   
  77.         CoUninitialize();  
  78.   
  79.         return 1;                    // Program has failed.  
  80.   
  81.     }  
  82.   
  83.   
  84.     // Step 3: ---------------------------------------------------  
  85.   
  86.     // Obtain the initial locator to WMI -------------------------  
  87.   
  88.   
  89.     IWbemLocator *pLoc = NULL;  
  90.   
  91.   
  92.     hres = CoCreateInstance(  
  93.   
  94.         CLSID_WbemLocator,               
  95.   
  96.         0,   
  97.   
  98.         CLSCTX_INPROC_SERVER,   
  99.   
  100.         IID_IWbemLocator, (LPVOID *) &pLoc);  
  101.   
  102.   
  103.     if (FAILED(hres))  
  104.   
  105.     {  
  106.   
  107.         cout << "Failed to create IWbemLocator object."  
  108.   
  109.             << " Err code = 0x"  
  110.   
  111.             << hex << hres << endl;  
  112.   
  113.         CoUninitialize();  
  114.   
  115.         return 1;                 // Program has failed.  
  116.   
  117.     }  
  118.   
  119.   
  120.     // Step 4: -----------------------------------------------------  
  121.   
  122.     // Connect to WMI through the IWbemLocator::ConnectServer method  
  123.   
  124.   
  125.     IWbemServices *pSvc = NULL;  
  126.   
  127.     // Connect to the root/SecurityCenter namespace with  
  128.   
  129.     // the current user and obtain pointer pSvc  
  130.   
  131.     // to make IWbemServices calls.  
  132.   
  133.     hres = pLoc->ConnectServer(  
  134.   
  135.          _bstr_t(L"ROOT//SecurityCenter"), // Object path of WMI namespace  
  136.   
  137.          NULL,                    // User name. NULL = current user  
  138.   
  139.          NULL,                    // User password. NULL = current  
  140.   
  141.          0,                       // Locale. NULL indicates current  
  142.   
  143.          NULL,                    // Security flags.  
  144.   
  145.          0,                       // Authority (e.g. Kerberos)  
  146.   
  147.          0,                       // Context object   
  148.   
  149.          &pSvc                    // pointer to IWbemServices proxy  
  150.   
  151.          );  
  152.   
  153.   
  154.     if (FAILED(hres))  
  155.   
  156.     {  
  157.   
  158.         cout << "Could not connect. Error code = 0x"   
  159.   
  160.              << hex << hres << endl;  
  161.   
  162.         pLoc->Release();       
  163.   
  164.         CoUninitialize();  
  165.   
  166.         return 1;                // Program has failed.  
  167.   
  168.     }  
  169.   
  170.   
  171.     cout << "Connected to ROOT//SecurityCenter WMI namespace" << endl;   
  172.   
  173.     // Step 5: --------------------------------------------------  
  174.   
  175.     // Set security levels on the proxy -------------------------  
  176.   
  177.   
  178.     hres = CoSetProxyBlanket(  
  179.   
  180.        pSvc,                        // Indicates the proxy to set  
  181.   
  182.        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx  
  183.   
  184.        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx  
  185.   
  186.        NULL,                        // Server principal name   
  187.   
  188.        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx   
  189.   
  190.        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx  
  191.   
  192.        NULL,                        // client identity  
  193.   
  194.        EOAC_NONE                    // proxy capabilities   
  195.   
  196.     );  
  197.   
  198.   
  199.     if (FAILED(hres))  
  200.   
  201.     {  
  202.   
  203.         cout << "Could not set proxy blanket. Error code = 0x"   
  204.   
  205.             << hex << hres << endl;  
  206.   
  207.         pSvc->Release();  
  208.   
  209.         pLoc->Release();       
  210.   
  211.         CoUninitialize();  
  212.   
  213.         return 1;               // Program has failed.  
  214.   
  215.     }  
  216.   
  217.   
  218.     // Step 6: --------------------------------------------------  
  219.   
  220.     // Use the IWbemServices pointer to make requests of WMI ----  
  221.   
  222.   
  223.     // For example, get the name of the operating system  
  224.   
  225.     IEnumWbemClassObject* pEnumerator = NULL;  
  226.   
  227.     hres = pSvc->ExecQuery(  
  228.   
  229.         bstr_t("WQL"),   
  230.   
  231.         bstr_t("SELECT * FROM AntiVirusProduct"),  
  232.   
  233.         WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,   
  234.   
  235.         NULL,  
  236.   
  237.         &pEnumerator);  
  238.   
  239.   
  240.     if (FAILED(hres))  
  241.   
  242.     {  
  243.   
  244.         cout << "Query for operating system name failed."  
  245.   
  246.             << " Error code = 0x"   
  247.   
  248.             << hex << hres << endl;  
  249.   
  250.         pSvc->Release();  
  251.   
  252.         pLoc->Release();  
  253.   
  254.         CoUninitialize();  
  255.   
  256.         return 1;               // Program has failed.  
  257.   
  258.     }  
  259.   
  260.   
  261.     // Step 7: -------------------------------------------------  
  262.   
  263.     // Get the data from the query in step 6 -------------------  
  264.   
  265.   
  266.     IWbemClassObject *pclsObj;  
  267.   
  268.     ULONG uReturn = 0;  
  269.   
  270.   
  271.     while (pEnumerator)  
  272.   
  273.     {  
  274.   
  275.         HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,   
  276.   
  277.             &pclsObj, &uReturn);  
  278.   
  279.   
  280.         if(0 == uReturn)  
  281.   
  282.         {  
  283.   
  284.             break;  
  285.   
  286.         }  
  287.   
  288.   
  289.         VARIANT vtProp;  
  290.   
  291.   
  292.         // Get the value of the Name property  
  293.   
  294.         hr = pclsObj->Get(L"displayName", 0, &vtProp, 0, 0);  
  295.   
  296.         wcout << "AV  Product displayName : " << vtProp.bstrVal << endl;  
  297.   
  298.         hr = pclsObj->Get(L"companyName", 0, &vtProp, 0, 0);  
  299.   
  300.         wcout << "AV  Product companyName : " << vtProp.bstrVal << endl;  
  301.   
  302.         hr = pclsObj->Get(L"pathToSignedProductExe", 0, &vtProp, 0, 0);  
  303.   
  304.         wcout << "AV  Product pathToSignedProductExe : " << vtProp.bstrVal << endl;           
  305.   
  306.         hr = pclsObj->Get(L"versionNumber", 0, &vtProp, 0, 0);  
  307.   
  308.         wcout << "AV  Product versionNumber : " << vtProp.bstrVal << endl;             
  309.   
  310.         VariantClear(&vtProp);   
  311.   
  312.         pclsObj->Release();  
  313.   
  314.     }  
  315.   
  316.   
  317.     // Cleanup  
  318.   
  319.     // ========  
  320.   
  321.   
  322.     pSvc->Release();  
  323.   
  324.     pLoc->Release();  
  325.   
  326.     pEnumerator->Release();  
  327.   
  328.     //pclsObj->Release();  
  329.   
  330.     CoUninitialize();  
  331.   
  332.   
  333.     return 0;   // Program successfully completed.  
  334.   
  335. }  
这份代码是我从MSDN中的C++ WMI例子中抠出来然后针对具体情况进行修改,所以并不能算是真正意义上的原创。但是呢,这个教材文章确实是原创的 (Tr0j4n *_*)

运行效果:


注释大部分都是微软加的,所以非常详细。它本来是用来查询ROOT//CIMV2这个名称空间中的Win32_OperatingSystem类,然后获得操作系统的名称。说实话,用C++调用WMI就为了得到操作系统名称,这简直是一种浪费,简单的Win32 API调用就能实现了。所以我把它改成了查看本机的反病毒产品的代码。

C++操作WMI执行WQL返回,其实就是一个模板,所以我认为大家有掌握的必要。而且可以举一反三。

Step1:Initialize COM parameters with a call to CoInitializeEx.
For more information, see Initializing COM for a WMI Application.

Step2:Initialize COM process security by calling CoInitializeSecurity. 
Windows 2000:  Specify the default authentication credentials for a user by using a SOLE_AUTHENTICATION_LIST structure in the pAuthList parameter of CoInitializeSecurity.
For more information, see Setting the Default Process Security Level Using C++.

Step3:Obtain the initial locator to WMI by calling CoCreateInstance. 
For more information, see Creating a Connection to a WMI Namespace.

Step4:Obtain a pointer to IWbemServices for the root/cimv2 namespace on the local computer by calling IWbemLocator::ConnectServer. To connect to a remote computer, see Example: Getting WMI Data from a Remote Computer. 
For more information, see Creating a Connection to a WMI Namespace.

Step5:Set IWbemServices proxy security so the WMI service can impersonate the client by calling CoSetProxyBlanket.
For more information, see Setting the Security Levels on a WMI Connection.

Step6:Use the IWbemServices pointer to make requests of WMI. This example executes a query for the name of the operating system by calling IWbemServices::ExecQuery. 
The following WQL query is one of the method arguments.

SELECT * FROM Win32_OperatingSystem   这就是WQL语句

The result of this query is stored in an IEnumWbemClassObject pointer. This allows the data objects from the query to be retrieved semisynchronously with the IEnumWbemClassObject interface. For more information, see Enumerating WMI. For getting the data asynchronously, see Example: Getting WMI Data from the Local Computer Asynchronously.
For more information about making requests to WMI, see Manipulating Class and Instance Information, Querying WMI, and Calling a Method.

Step7:Get and display the data from the WQL query. The IEnumWbemClassObject pointer is linked to the data objects that the query returned, and the data objects can be retrieved with the IEnumWbemClassObject::Next method. This method links the data objects to an IWbemClassObject pointer that is passed into the method. Use the IWbemClassObject::Get method to get the desired information from the data objects.

以上解释出自MSDN。MSDN用得好,对编程能力是一个很大的帮助。如果觉得英语不行,只能去恶补咯。

 

其实,关键在4,6,7步。第四步弄的是名称空间,第六步写的是WQL语句,第七步获得返回值。至于第七步。你对比那个While循环中的C++语句,和文章开头的Vbs语句中的For each对比,你看出了什么名堂了吗?

Vbs通过For each枚举类实例,而C++中通过IEnumWbemClassObject接口指针。

如何获得IEnumWbemClassObject接口指针呢?微软告诉我们有4种方法。我用的是第一种,执行一个WQL语句,获得一个AntiVirusProduct类实例的枚举接口指针。

IWbemServices::ExecQuery 
IWbemServices::CreateInstanceEnum 
IWbemServices::CreateClassEnum 
IWbemServices::ExecNotificationQuery

我是怎么实现变量的呢?我用的是枚举接口指针的Next方法,其实它还有别的方法,比如Skip跳过,NextAsync异步下一个。

今后有什么WMI的代码想在VC中实现,只要按这个模板一套用,属于你自己的C++ WMI代码就出炉的。对C++ WMI编程感兴趣的同学,可以参考 这里

0
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值