wmi.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright (c) 2010 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/win/wmi.h"
  5. #include <windows.h>
  6. #include <objbase.h>
  7. #include <stdint.h>
  8. #include <utility>
  9. #include "base/location.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "base/threading/scoped_thread_priority.h"
  13. #include "base/win/scoped_bstr.h"
  14. #include "base/win/scoped_variant.h"
  15. using Microsoft::WRL::ComPtr;
  16. namespace base {
  17. namespace win {
  18. const wchar_t kCimV2ServerName[] = L"ROOT\\CIMV2";
  19. const wchar_t kSecurityCenter2ServerName[] = L"ROOT\\SecurityCenter2";
  20. namespace {
  21. constexpr wchar_t kSerialNumberQuery[] = L"SELECT SerialNumber FROM Win32_Bios";
  22. // Instantiates `wmi_services` with a connection to `server_name` in WMI. Will
  23. // set a security blanket if `set_blanket` is true.
  24. absl::optional<WmiError> CreateLocalWmiConnection(
  25. const std::wstring& server_name,
  26. bool set_blanket,
  27. ComPtr<IWbemServices>* wmi_services) {
  28. DCHECK(wmi_services);
  29. ComPtr<IWbemLocator> wmi_locator;
  30. HRESULT hr =
  31. ::CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
  32. IID_PPV_ARGS(&wmi_locator));
  33. if (FAILED(hr))
  34. return WmiError::kFailedToCreateInstance;
  35. ComPtr<IWbemServices> wmi_services_r;
  36. hr = wmi_locator->ConnectServer(base::win::ScopedBstr(server_name).Get(),
  37. nullptr, nullptr, nullptr, 0, nullptr,
  38. nullptr, &wmi_services_r);
  39. if (FAILED(hr))
  40. return WmiError::kFailedToConnectToWMI;
  41. if (set_blanket) {
  42. hr = ::CoSetProxyBlanket(wmi_services_r.Get(), RPC_C_AUTHN_WINNT,
  43. RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
  44. RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
  45. if (FAILED(hr))
  46. return WmiError::kFailedToSetSecurityBlanket;
  47. }
  48. *wmi_services = std::move(wmi_services_r);
  49. return absl::nullopt;
  50. }
  51. // Runs `query` through `wmi_services` and sets the results' `enumerator`.
  52. bool TryRunQuery(const std::wstring& query,
  53. const ComPtr<IWbemServices>& wmi_services,
  54. ComPtr<IEnumWbemClassObject>* enumerator) {
  55. DCHECK(enumerator);
  56. base::win::ScopedBstr query_language(L"WQL");
  57. base::win::ScopedBstr query_bstr(query);
  58. ComPtr<IEnumWbemClassObject> enumerator_r;
  59. HRESULT hr = wmi_services->ExecQuery(
  60. query_language.Get(), query_bstr.Get(),
  61. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
  62. &enumerator_r);
  63. if (FAILED(hr))
  64. return false;
  65. *enumerator = std::move(enumerator_r);
  66. return true;
  67. }
  68. } // namespace
  69. absl::optional<WmiError> RunWmiQuery(const std::wstring& server_name,
  70. const std::wstring& query,
  71. ComPtr<IEnumWbemClassObject>* enumerator) {
  72. SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
  73. DCHECK(enumerator);
  74. ComPtr<IWbemServices> wmi_services;
  75. auto error = CreateLocalWmiConnection(server_name, /*set_blanket=*/true,
  76. &wmi_services);
  77. if (error.has_value())
  78. return error;
  79. if (!TryRunQuery(query, wmi_services, enumerator))
  80. return WmiError::kFailedToExecWMIQuery;
  81. return absl::nullopt;
  82. }
  83. bool CreateLocalWmiConnection(bool set_blanket,
  84. ComPtr<IWbemServices>* wmi_services) {
  85. // Mitigate the issues caused by loading DLLs on a background thread
  86. // (http://crbug/973868).
  87. SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
  88. auto error =
  89. CreateLocalWmiConnection(kCimV2ServerName, set_blanket, wmi_services);
  90. return !error.has_value();
  91. }
  92. bool CreateWmiClassMethodObject(IWbemServices* wmi_services,
  93. WStringPiece class_name,
  94. WStringPiece method_name,
  95. ComPtr<IWbemClassObject>* class_instance) {
  96. // We attempt to instantiate a COM object that represents a WMI object plus
  97. // a method rolled into one entity.
  98. ScopedBstr b_class_name(class_name);
  99. ScopedBstr b_method_name(method_name);
  100. ComPtr<IWbemClassObject> class_object;
  101. HRESULT hr;
  102. hr = wmi_services->GetObject(b_class_name.Get(), 0, nullptr, &class_object,
  103. nullptr);
  104. if (FAILED(hr))
  105. return false;
  106. ComPtr<IWbemClassObject> params_def;
  107. hr = class_object->GetMethod(b_method_name.Get(), 0, &params_def, nullptr);
  108. if (FAILED(hr))
  109. return false;
  110. if (!params_def.Get()) {
  111. // You hit this special case if the WMI class is not a CIM class. MSDN
  112. // sometimes tells you this. Welcome to WMI hell.
  113. return false;
  114. }
  115. hr = params_def->SpawnInstance(0, &(*class_instance));
  116. return SUCCEEDED(hr);
  117. }
  118. // The code in Launch() basically calls the Create Method of the Win32_Process
  119. // CIM class is documented here:
  120. // http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
  121. // NOTE: The documentation for the Create method suggests that the ProcessId
  122. // parameter and return value are of type uint32_t, but when we call the method
  123. // the values in the returned out_params, are VT_I4, which is int32_t.
  124. bool WmiLaunchProcess(const std::wstring& command_line, int* process_id) {
  125. ComPtr<IWbemServices> wmi_local;
  126. if (!CreateLocalWmiConnection(true, &wmi_local))
  127. return false;
  128. static constexpr wchar_t class_name[] = L"Win32_Process";
  129. static constexpr wchar_t method_name[] = L"Create";
  130. ComPtr<IWbemClassObject> process_create;
  131. if (!CreateWmiClassMethodObject(wmi_local.Get(), class_name, method_name,
  132. &process_create)) {
  133. return false;
  134. }
  135. ScopedVariant b_command_line(command_line.c_str());
  136. if (FAILED(process_create->Put(L"CommandLine", 0, b_command_line.AsInput(),
  137. 0))) {
  138. return false;
  139. }
  140. ComPtr<IWbemClassObject> out_params;
  141. HRESULT hr = wmi_local->ExecMethod(
  142. ScopedBstr(class_name).Get(), ScopedBstr(method_name).Get(), 0, nullptr,
  143. process_create.Get(), &out_params, nullptr);
  144. if (FAILED(hr))
  145. return false;
  146. // We're only expecting int32_t or uint32_t values, so no need for
  147. // ScopedVariant.
  148. VARIANT ret_value = {{{VT_EMPTY}}};
  149. hr = out_params->Get(L"ReturnValue", 0, &ret_value, nullptr, nullptr);
  150. if (FAILED(hr) || V_I4(&ret_value) != 0)
  151. return false;
  152. VARIANT pid = {{{VT_EMPTY}}};
  153. hr = out_params->Get(L"ProcessId", 0, &pid, nullptr, nullptr);
  154. if (FAILED(hr) || V_I4(&pid) == 0)
  155. return false;
  156. if (process_id)
  157. *process_id = V_I4(&pid);
  158. return true;
  159. }
  160. // static
  161. WmiComputerSystemInfo WmiComputerSystemInfo::Get() {
  162. WmiComputerSystemInfo info;
  163. ComPtr<IEnumWbemClassObject> enumerator_bios;
  164. auto error =
  165. RunWmiQuery(kCimV2ServerName, kSerialNumberQuery, &enumerator_bios);
  166. if (error.has_value())
  167. return info;
  168. info.PopulateSerialNumber(enumerator_bios);
  169. return info;
  170. }
  171. void WmiComputerSystemInfo::PopulateSerialNumber(
  172. const ComPtr<IEnumWbemClassObject>& enumerator_bios) {
  173. ComPtr<IWbemClassObject> class_obj;
  174. ULONG items_returned = 0;
  175. HRESULT hr =
  176. enumerator_bios->Next(WBEM_INFINITE, 1, &class_obj, &items_returned);
  177. if (FAILED(hr) || !items_returned)
  178. return;
  179. ScopedVariant serial_number;
  180. hr = class_obj->Get(L"SerialNumber", 0, serial_number.Receive(), nullptr,
  181. nullptr);
  182. if (SUCCEEDED(hr) && serial_number.type() == VT_BSTR) {
  183. serial_number_.assign(V_BSTR(serial_number.ptr()),
  184. ::SysStringLen(V_BSTR(serial_number.ptr())));
  185. }
  186. }
  187. } // namespace win
  188. } // namespace base