Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop Integration with WMI API to Retrieve Installed Windows Updates #25766

Closed
3 tasks done
vikman90 opened this issue Sep 18, 2024 · 3 comments · Fixed by #26706 · May be fixed by wazuh/wazuh-agent#372
Closed
3 tasks done

Develop Integration with WMI API to Retrieve Installed Windows Updates #25766

vikman90 opened this issue Sep 18, 2024 · 3 comments · Fixed by #26706 · May be fixed by wazuh/wazuh-agent#372
Assignees

Comments

@vikman90
Copy link
Member

vikman90 commented Sep 18, 2024

Parent Issue:

Description

Following the findings of the spike, this task involves implementing the integration of the Wazuh agent with the WMI API to retrieve a list of installed Windows updates. This list will be combined with the current Syscollector inventory.

Requirements

  • Implement code to query the WMI API and retrieve installed Windows updates.
  • Ensure that the data retrieved from the WMI API is correctly merged with the existing Syscollector data.
  • Handle any errors or edge cases that may arise during the retrieval of updates from WMI.

Definition of Done

  • The Wazuh agent successfully queries the WMI API and retrieves the installed updates.
  • The retrieved data is merged with the Syscollector inventory.
  • The feature is tested on different Windows versions to ensure compatibility.
@lchico
Copy link
Member

lchico commented Oct 25, 2024

Update

I've begun investigating the issue and have gathered relevant context. I successfully set up the environment and replicated the output, which has allowed me to understand the problem better.

2024-10-25

Before integrating the original code that is working, I am trying to build it on Linux using cross-compilation to ensure I have all the necessary dependencies. Unfortunately, mingw-w64 does not include all the required components, so I started migrating what was needed. However, I brought in most of the Windows SDK without completing the build.

2024-10-28

I conducted some research to explore other options, such as installing Visual Studio Community or using Wine. For the latter, I received the following output:

Using wine libs
make
x86_64-w64-mingw32-g++ -Wall -Wextra -std=c++11 -Wno-expansion-to-defined -I/usr/x86_64-w64-mingw32/include -I/usr/share/mingw-w64/include -I/root/test/inc/ -c main.cpp -o main.o
In file included from main.cpp:3:
/root/test/inc/wuapi.h:938: warning: ignoring '#pragma region Desktop' [-Wunknown-pragmas]
  938 | #pragma region Desktop Family
      | 
/root/test/inc/wuapi.h:940: warning: ignoring '#pragma comment ' [-Wunknown-pragmas]
  940 | #pragma comment(lib, "wuguid.lib")
      | 
In file included from main.cpp:3:
/root/test/inc/wuapi.h:20236: warning: ignoring '#pragma endregion ' [-Wunknown-pragmas]
20236 | #pragma endregion
      | 
main.cpp:9: warning: ignoring '#pragma comment ' [-Wunknown-pragmas]
    9 | #pragma comment(lib, "wbemuuid.lib")
      | 
In file included from /usr/share/mingw-w64/include/wbemidl.h:16,
                 from main.cpp:1:
/usr/share/mingw-w64/include/wbemdisp.h:1238:26: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1238 |         BSTR strServer = L".",
      |                          ^~~~
/usr/share/mingw-w64/include/wbemdisp.h:1239:29: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1239 |         BSTR strNamespace = L"",
      |                             ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1240:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1240 |         BSTR strUser = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1241:28: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1241 |         BSTR strPassword = L"",
      |                            ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1242:26: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1242 |         BSTR strLocale = L"",
      |                          ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1243:29: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1243 |         BSTR strAuthority = L"",
      |                             ^~~
In file included from /usr/share/mingw-w64/include/wbemidl.h:16,
                 from main.cpp:1:
/usr/share/mingw-w64/include/wbemdisp.h:1390:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1390 |         BSTR strObjectPath = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1397:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1397 |         BSTR strObjectPath = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1428:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1428 |         BSTR strSuperclass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1435:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1435 |         BSTR strSuperclass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1442:33: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1442 |         BSTR strQueryLanguage = L"WQL",
      |                                 ^~~~~~
/usr/share/mingw-w64/include/wbemdisp.h:1450:33: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1450 |         BSTR strQueryLanguage = L"WQL",
      |                                 ^~~~~~
/usr/share/mingw-w64/include/wbemdisp.h:1457:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1457 |         BSTR strAssocClass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1458:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1458 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1459:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1459 |         BSTR strResultRole = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1460:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1460 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1463:42: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1463 |         BSTR strRequiredAssocQualifier = L"",
      |                                          ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1464:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1464 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1472:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1472 |         BSTR strAssocClass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1473:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1473 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1474:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1474 |         BSTR strResultRole = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1475:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1475 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1478:42: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1478 |         BSTR strRequiredAssocQualifier = L"",
      |                                          ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1479:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1479 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1486:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1486 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1487:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1487 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1490:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1490 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1498:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1498 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1499:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1499 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1502:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1502 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:1509:33: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1509 |         BSTR strQueryLanguage = L"WQL",
      |                                 ^~~~~~
/usr/share/mingw-w64/include/wbemdisp.h:1517:33: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 1517 |         BSTR strQueryLanguage = L"WQL",
      |                                 ^~~~~~
/usr/share/mingw-w64/include/wbemdisp.h:2349:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2349 |         BSTR strAssocClass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2350:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2350 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2351:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2351 |         BSTR strResultRole = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2352:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2352 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2355:42: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2355 |         BSTR strRequiredAssocQualifier = L"",
      |                                          ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2356:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2356 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2363:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2363 |         BSTR strAssocClass = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2364:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2364 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2365:30: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2365 |         BSTR strResultRole = L"",
      |                              ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2366:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2366 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2369:42: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2369 |         BSTR strRequiredAssocQualifier = L"",
      |                                          ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2370:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2370 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2376:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2376 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2377:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2377 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2380:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2380 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2387:31: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2387 |         BSTR strResultClass = L"",
      |                               ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2388:24: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2388 |         BSTR strRole = L"",
      |                        ^~~
/usr/share/mingw-w64/include/wbemdisp.h:2391:37: warning: ISO C++ forbids converting a string constant to 'BSTR' {aka 'wchar_t*'} [-Wwrite-strings]
 2391 |         BSTR strRequiredQualifier = L"",
      |                                     ^~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comutil.h:427:3: warning: converting '_variant_t' to a base class 'VARIANT' {aka 'tagVARIANT'} will never use a type conversion operator [-Wclass-conversion]
  427 |   operator VARIANT() const throw();
      |   ^~~~~~~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comutil.h: In constructor '_variant_t::_variant_t(VARIANT&, bool)':
/usr/share/mingw-w64/include/comutil.h:15:69: warning: 'void* memcpy(void*, const void*, size_t)' writing to an object of type 'class _variant_t' with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Wclass-memaccess]
   15 | #define _COM_MEMCPY_S(dest,destsize,src,count) memcpy(dest,src,count)
      |                                                                     ^
/usr/share/mingw-w64/include/comutil.h:492:5: note: in expansion of macro '_COM_MEMCPY_S'
  492 |     _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
      |     ^~~~~~~~~~~~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comutil.h:388:7: note: 'class _variant_t' declared here
  388 | class _variant_t : public ::tagVARIANT {
      |       ^~~~~~~~~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comutil.h: In member function 'void _variant_t::Attach(VARIANT&)':
/usr/share/mingw-w64/include/comutil.h:15:69: warning: 'void* memcpy(void*, const void*, size_t)' writing to an object of type 'class _variant_t' with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Wclass-memaccess]
   15 | #define _COM_MEMCPY_S(dest,destsize,src,count) memcpy(dest,src,count)
      |                                                                     ^
/usr/share/mingw-w64/include/comutil.h:1156:3: note: in expansion of macro '_COM_MEMCPY_S'
 1156 |   _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
      |   ^~~~~~~~~~~~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comutil.h:388:7: note: 'class _variant_t' declared here
  388 | class _variant_t : public ::tagVARIANT {
      |       ^~~~~~~~~~
In file included from /usr/share/mingw-w64/include/comdef.h:19,
                 from main.cpp:2:
/usr/share/mingw-w64/include/comdef.h: In member function 'const TCHAR* _com_error::ErrorMessage() const':
/usr/share/mingw-w64/include/comutil.h:23:52: error: 'sprintf_s' was not declared in this scope; did you mean 'wsprintfW'?
   23 | #define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1)
      |                                                    ^~~~~~~~~
/usr/share/mingw-w64/include/comutil.h:23:52: note: in definition of macro '_COM_PRINTF_S_1'
   23 | #define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1)
      |                                                    ^~~~~~~~~
/usr/share/mingw-w64/include/comutil.h:23:52: error: 'sprintf_s' was not declared in this scope; did you mean 'wsprintfW'?
   23 | #define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1)
      |                                                    ^~~~~~~~~
/usr/share/mingw-w64/include/comutil.h:23:52: note: in definition of macro '_COM_PRINTF_S_1'
   23 | #define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1)
      |                                                    ^~~~~~~~~
make: *** [Makefile:29: main.o] Error 1

2024-10-29

I built the code on Linux and made some changes, but there was no output. I continued debugging to find the reason and ended up removing all the code, attempting to print a simple 'Hello World,' but still got no output. It seems there may be an issue with the cross-compiling setup in my environment.

2024-10-30

I was able to solve the previous issue that I reported. The Hello World program worked as expected when I added the static flag. Then, I tried to build the project into the main code, but I was having issues because of the compiler. In my local tests using x86_64-w64-mingw32-g++, I had to update some libraries because Linux was case-sensitive, which was expected. However, when I tried to integrate with the sysinfo code using i686-w64-mingw32-g++, I started to encounter new issues that need to be fixed.

2024-10-31

I was able to build the sysinfo with the APIs using i686-w64-mingw32-g++, but when I tested it on Windows 10 and Windows 11, it did not work as expected. I installed the new package, and while the agent can stay alive, the inventory for Windows updates/packages doesn't show any data, indicating that something is not functioning correctly.

To build, I had to install Wine from source. I used:

git clone https://gitlab.winehq.org/wine/wine.git -b wine-9.20 --depth 1

Extra required code:

To fix the following error:

In file included from /usr/share/mingw-w64/include/windows.h:9,
                 from /usr/share/mingw-w64/include/winsock2.h:23,
                 from /usr/share/mingw-w64/include/ws2tcpip.h:17,
                 from /root/wazuh/wazuh/src/data_provider/src/network/networkInterfaceWindows.cpp:12:
/usr/share/mingw-w64/include/unknwnbase.h: In member function 'HRESULT IUnknown::QueryInterface(Q**)':
/usr/share/mingw-w64/include/unknwnbase.h:84:29: error: '__mingw_uuidof' was not declared in this scope; did you mean '__mingw_wcstof'?
   84 |       return QueryInterface(__uuidof(Q), (void **)pp);
      |                             ^~~~~~~~
/usr/share/mingw-w64/include/unknwnbase.h:84:29: error: expected primary-expression before '__typeof'
   84 |       return QueryInterface(__uuidof(Q), (void **)pp);
      |                             ^~~~~~~~
/usr/share/mingw-w64/include/unknwnbase.h: At global scope:
/usr/share/mingw-w64/include/unknwnbase.h:89:1: error: '__mingw_uuidof_s' is not a class template
   89 | __CRT_UUID_DECL(IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46)
      | ^~~~~~~~~~~~~~~
/usr/share/mingw-w64/include/unknwnbase.h:89:1: error: explicit specialization of non-template '__mingw_uuidof_s'
   89 | __CRT_UUID_DECL(IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46)

I removed the use of uuidof by defining GUIDs manually

+// Define GUIDs manually for IUpdateSearcher and UpdateSearcher
+DEFINE_GUID(IID_IUpdateSearcher, 0xAFC35F85, 0xB8C4, 0x4B1B, 0xAA, 0x3E, 0xC5, 0x4D, 0xBC, 0x56, 0x4E, 0xFB);
+DEFINE_GUID(IID_IWbemLocator, 0xdc12a687, 0x737f, 0x11cf, 0x88,0x4d, 0x00,0xaa,0x00,0x4b,0x2e,0x24);
+DEFINE_GUID(CLSID_WbemLocator, 0x4590f811,0x1d3a,0x11d0,0x89,0x1f,0x00,0xaa,0x00,0x4b,0x2e,0x24);
+DEFINE_GUID(CLSID_WbemStatusCode, 0xeb87e1bd,0x3233,0x11d2,0xae,0xc9,0x00,0xc0,0x4f,0xb6,0x88,0x20);
+DEFINE_GUID(CLSID_UpdateSearcher, 0x5A2A5E6E, 0xD633, 0x4C3A, 0x8A, 0x7E, 0x69, 0x4D, 0xBF, 0x9E, 0xCE, 0xD4);

To avoid this other issue:

/usr/share/mingw-w64/include/comutil.h:278: undefined reference to `_com_util::ConvertStringToBSTR(char const*)@4'

I added the following code:

namespace _com_util {
    BSTR ConvertStringToBSTR(const char* str) {
        int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
        BSTR bstr = SysAllocStringLen(0, len);
        MultiByteToWideChar(CP_ACP, 0, str, -1, bstr, len);
        return bstr;
    }
}

With these changes, I was able to build the code, but as I mentioned, it is not working yet. Once I have this working, I would like to improve the solution.

@lchico
Copy link
Member

lchico commented Nov 2, 2024

Update

Finally, I built a separate code and tested it on Windows. Everything appears to be working fine. I couldn't identify the issue with the code embedded in syscollector, but I am now confident that we can build the APIs on Linux and have them work on Windows.

Code The following code was built in a Linux environment and successfully tested on Windows 10.
#include <wbemidl.h>
#include <stdio.h>
#include <comdef.h>
#include "/usr/local/include/wine/windows/wuapi.h"
#include <set>
#include <iostream>
#include <regex>
#include <codecvt>

// Define GUIDs manually
DEFINE_GUID(IID_IUpdateSearcher, 0xAFC35F85, 0xB8C4, 0x4B1B, 0xAA, 0x3E, 0xC5, 0x4D, 0xBC, 0x56, 0x4E, 0xFB);
DEFINE_GUID(IID_IWbemLocator, 0xdc12a687, 0x737f, 0x11cf, 0x88,0x4d, 0x00,0xaa,0x00,0x4b,0x2e,0x24);
DEFINE_GUID(CLSID_WbemLocator, 0x4590f811,0x1d3a,0x11d0,0x89,0x1f,0x00,0xaa,0x00,0x4b,0x2e,0x24);
DEFINE_GUID(CLSID_WbemStatusCode, 0xeb87e1bd,0x3233,0x11d2,0xae,0xc9,0x00,0xc0,0x4f,0xb6,0x88,0x20);
DEFINE_GUID(CLSID_UpdateSearcher, 0x5A2A5E6E, 0xD633, 0x4C3A, 0x8A, 0x7E, 0x69, 0x4D, 0xBF, 0x9E, 0xCE, 0xD4);

std::string BstrToString(BSTR bstr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    std::wstring wstr(bstr, SysStringLen(bstr));
    return converter.to_bytes(wstr);
}

namespace _com_util {
    BSTR ConvertStringToBSTR(const char* str) {
        int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
        BSTR bstr = SysAllocStringLen(0, len);
        MultiByteToWideChar(CP_ACP, 0, str, -1, bstr, len);
        return bstr;
    }
}

void QueryWMIHotFixes(std::set<std::string>& hotfixSet) {
    HRESULT hres;
    IWbemLocator* pLoc = NULL;
    IWbemServices* pSvc = NULL;
    std::cout << "Querying hotfixes using WMI..." << std::endl;

    hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
    if (FAILED(hres)) {
        std::cout << "Error creating IWbemLocator. Code: " << std::hex << hres << std::endl;
        return;
    }

    hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, 0, 0, 0, &pSvc);
    if (FAILED(hres)) {
        std::cout << "Error connecting to WMI. Code: " << std::hex << hres << std::endl;
        pLoc->Release();
        return;
    }

    hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    if (FAILED(hres)) {
        std::cout << "Error setting security on WMI. Code: " << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();
        return;
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_QuickFixEngineering"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    if (FAILED(hres)) {
        std::cout << "Error executing WMI query. Code: " << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();
        return;
    }

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator) {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
        if (0 == uReturn) {
            break;
        }

        VARIANT vtProp;
        hr = pclsObj->Get(L"HotFixID", 0, &vtProp, 0, 0);
        if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
            std::string hotfix = BstrToString(vtProp.bstrVal);
            if (hotfixSet.find(hotfix) == hotfixSet.end()) {
                hotfixSet.insert(hotfix);
                std::cout << "New HotFix found: " << hotfix << std::endl; // Debugging
            }
        }
        VariantClear(&vtProp);
        pclsObj->Release();
    }

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
}

void QueryWUHotFixes(std::set<std::string>& hotfixSet) {
    HRESULT hres;
    IUpdateSearcher* pUpdateSearcher = NULL;
    IUpdateHistoryEntryCollection* pHistory = NULL;
    std::regex hotfixRegex("KB[0-9]+");
    std::cout << "Querying hotfixes using Windows Update API..." << std::endl;

    hres = CoCreateInstance(CLSID_UpdateSearcher, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSearcher, (LPVOID*)&pUpdateSearcher);
    if (FAILED(hres)) {
        std::cout << "Error creating IUpdateSearcher. Code: " << std::hex << hres << std::endl;
        return;
    }

    LONG count;
    hres = pUpdateSearcher->GetTotalHistoryCount(&count);
    if (FAILED(hres)) {
        std::cout << "Error getting total update history count. Code: " << std::hex << hres << std::endl;
        pUpdateSearcher->Release();
        return;
    }

    std::cout << "Total number of updates in history: " << count << std::endl;

    hres = pUpdateSearcher->QueryHistory(0, count, &pHistory);
    if (FAILED(hres)) {
        std::cout << "Error querying update history. Code: " << std::hex << hres << std::endl;
        pUpdateSearcher->Release();
        return;
    }

    LONG historyCount;
    pHistory->get_Count(&historyCount);

    for (LONG i = 0; i < historyCount; ++i) {
        IUpdateHistoryEntry* pEntry = NULL;
        pHistory->get_Item(i, &pEntry);
        BSTR title;
        pEntry->get_Title(&title);
        std::string titleStr = BstrToString(title);

        std::smatch match;
        if (std::regex_search(titleStr, match, hotfixRegex)) {
            std::string hotfix = match[0];
            if (hotfixSet.find(hotfix) == hotfixSet.end()) {
                hotfixSet.insert(hotfix);
                std::cout << "New HotFix found: " << hotfix << std::endl; // Debugging
            }
        }
        pEntry->Release();
        SysFreeString(title);
    }

    pHistory->Release();
    pUpdateSearcher->Release();
}


int main()
{
    std::set<std::string> hotfixes;

    // Initialize COM
    HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres)) {
        std::wcout << L"Error initializing COM. Code: " << std::hex << hres << std::endl;
	return 1;
    }
    // Query hotfixes using WMI
    QueryWMIHotFixes(hotfixes);

    // Query hotfixes using Windows Update API
    QueryWUHotFixes(hotfixes);

    // Uninitialize COM
    CoUninitialize();

    // Display collected hotfixes
    std::wcout << L"List of installed hotfixes:" << std::endl;
    int totalHotfixes = 0;
    for (const auto& hotfix : hotfixes) {
        std::cout << "- " << hotfix << std::endl;
        ++totalHotfixes;
    }
    std::cout << "Total number of installed hotfixes: " << totalHotfixes << std::endl;

    return 0;
}

The command line used to build:

docker build -t build_hotfix .
docker run -v $(pwd):/root -t build_hotfix i686-w64-mingw32-g++-posix -Wall -Wextra -Wshadow  -Wcast-align -o /root/test.exe /root/test_hotfix.cpp -lwbemuuid  -luuid -lwuguid -lole32 -loleaut32  -L/root/lib -static

Note: wmi_wua_apis.zip you have everything you need to reproduce it. (Dockerfile, libs, code)

Test on Windows

image

2024-11-4

  • Fixed: Resolved the library issue and successfully integrated with syscollector.
  • Tested: Verified functionality on Windows 10 and compared the results with version 4.8.1. Identified 6 new hotfixes.
    Screenshot from 2024-11-04 13-14-14
Wazuh Agent 4.8.1 Using APIs
After Right After Left
  • Initiated code improvement and created a draft PR.

2024-11-5

  • Improve the code.
  • Fix some checks.
  • Create the PR and leave it ready for review.

2024-11-6

  • Review and improve the code.
  • I attempted to add a debug message for new hotfixes but was unsuccessful.
  • Investigate the reasons for five failing checks and work on the fix.

2024-11-7

  • Fixed the five failing checks.
  • Addressed @MarcelKemp's suggestions.
  • Implemented code improvements.

@lchico
Copy link
Member

lchico commented Nov 26, 2024

2024-11-25

  • Rebased the PR and resolved some differences.
  • Created a local package and tested it on Windows 10, confirming it works as expected.

Check the logs, there are no errors: ossec.log

  • Also tested on Windows Server 2008. In the previous test, where the try and catch code was integrated for both APIs (WMI and WUA), we now have two separate try and catch blocks for each API. However, the result remains the same: no new hotfixes were found.

Screenshot from 2024-11-26 00-34-54

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment