Skip to content

Instantly share code, notes, and snippets.

@kbridge
Created September 23, 2023 16:05
Show Gist options
  • Save kbridge/ec56ef93fed44483e74259a29b71bec2 to your computer and use it in GitHub Desktop.
Save kbridge/ec56ef93fed44483e74259a29b71bec2 to your computer and use it in GitHub Desktop.
Query Installed Anti-Virus Software on Windows
// https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
// https://source.chromium.org/chromium/chromium/src/+/main:base/win/scoped_com_initializer.h
// https://source.chromium.org/chromium/chromium/src/+/main:base/win/scoped_bstr.h
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/services/util_win/av_products.cc (FillAntiVirusProductsFromWSC)
// C
#include <cassert>
#include <clocale>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <string_view>
// Windows
#define _WIN32_WINNT _WIN32_WINNT_WIN10
#define NOMINMAX
#include <iwscapi.h>
#include <windows.h>
#include <wrl/client.h>
#include <wscapi.h>
void Die(std::string_view reason)
{
std::cerr << "ERROR" << reason << "\n";
exit(1);
}
namespace std
{
std::string to_string(WSC_SECURITY_PRODUCT_STATE state)
{
switch (state) {
case WSC_SECURITY_PRODUCT_STATE_ON:
return "ON";
case WSC_SECURITY_PRODUCT_STATE_OFF:
return "OFF";
case WSC_SECURITY_PRODUCT_STATE_SNOOZED:
return "SNOOZED";
case WSC_SECURITY_PRODUCT_STATE_EXPIRED:
return "EXPIRED";
default:
{
std::stringstream ss;
ss << "UNKNOWN (" << state << ")";
return ss.str();
}
}
}
}
class ScopedCOMInitializer final
{
public:
ScopedCOMInitializer()
: hr_(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))
{
}
~ScopedCOMInitializer()
{
if (Succeeded()) {
CoUninitialize();
}
}
bool Succeeded() const
{
return SUCCEEDED(hr_);
}
ScopedCOMInitializer(const ScopedCOMInitializer &) = delete;
ScopedCOMInitializer &operator=(const ScopedCOMInitializer &) = delete;
private:
HRESULT hr_;
};
class ScopedBSTR final
{
public:
ScopedBSTR() = default;
explicit ScopedBSTR(std::wstring_view wsv)
: bstr_(AllocateBSTROrDie(wsv))
{
}
// SysFreeString() handles null.
~ScopedBSTR()
{
SysFreeString(bstr_);
}
BSTR Get() const
{
return bstr_;
}
void Reset(BSTR bstr)
{
if (bstr != bstr_) {
SysFreeString(bstr_);
bstr_ = bstr;
}
}
BSTR Release()
{
BSTR bstr = bstr_;
bstr_ = nullptr;
return bstr_;
}
BSTR Allocate(std::wstring_view wsv)
{
Reset(AllocateBSTROrDie(wsv));
return bstr_;
}
BSTR AllocateBytes(size_t bytes)
{
Reset(AllocateBSTRBytesOrDie(bytes));
return bstr_;
}
BSTR *Receive()
{
assert(bstr_ == nullptr);
return &bstr_;
}
size_t Length() const
{
return SysStringLen(bstr_);
}
size_t ByteLength() const
{
return SysStringByteLen(bstr_);
}
bool operator==(const ScopedBSTR &other) const = delete;
bool operator!=(const ScopedBSTR &other) const = delete;
private:
BSTR bstr_ = nullptr;
static UINT CheckedCastToUINT(size_t n)
{
assert(n <= std::numeric_limits<UINT>::max()); // must define NOMINMAX
return static_cast<UINT>(n);
}
static BSTR AllocateBSTROrDie(std::wstring_view wsv)
{
BSTR result = SysAllocStringLen(wsv.data(), CheckedCastToUINT(wsv.length()));
if (result == nullptr) {
abort();
}
return result;
}
static BSTR AllocateBSTRBytesOrDie(size_t num_bytes)
{
BSTR result = SysAllocStringByteLen(nullptr, CheckedCastToUINT(num_bytes));
if (result == nullptr) {
abort();
}
return result;
}
};
int main()
{
setlocale(LC_ALL, "en_US.UTF-8");
ScopedCOMInitializer com_initializer;
if (!com_initializer.Succeeded())
Die("com initialization failed");
Microsoft::WRL::ComPtr<IWSCProductList> product_list;
{
HRESULT hr = CoCreateInstance(
__uuidof(WSCProductList),
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&product_list));
if (FAILED(hr))
Die("create instance failed");
}
if (FAILED(product_list->Initialize(WSC_SECURITY_PROVIDER_ANTIVIRUS)))
Die("IWSCProductList::Initialize() failed");
LONG product_count;
if (FAILED(product_list->get_Count(&product_count)))
Die("IWSCProductList::get_Count() failed");
std::cout << "total " << product_count << "\n";
for (LONG i = 0; i < product_count; i++) {
std::cout << "\n";
std::cout << "-- item " << i << "\n";
Microsoft::WRL::ComPtr<IWscProduct> product;
if (FAILED(product_list->get_Item(i, &product)))
Die("IWSCProductList::get_Item() failed");
WSC_SECURITY_PRODUCT_STATE product_state;
if (FAILED(product->get_ProductState(&product_state)))
Die("IWSCProduct:get_ProductState() failed");
std::cout << "product state: " << std::to_string(product_state) << "\n";
std::wstring product_name;
{
ScopedBSTR bstr;
if (FAILED(product->get_ProductName(bstr.Receive())))
Die("IWSCProduct::get_ProductName() failed");
product_name.assign(bstr.Get(), bstr.Length());
}
std::wcout << "product name: " << product_name << "\n";
std::wstring remediation_path;
{
ScopedBSTR bstr;
if (FAILED(product->get_RemediationPath(bstr.Receive())))
Die("IWSCProduct::get_RemediationPath() failed");
remediation_path.assign(bstr.Get(), bstr.Length());
}
std::wcout << "remediation path: " << remediation_path << "\n";
}
std::cout << "\n";
std::cout << "done\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment