diff --git a/HidHide.sln.DotSettings b/HidHide.sln.DotSettings index 8a86275..0c97bbd 100644 --- a/HidHide.sln.DotSettings +++ b/HidHide.sln.DotSettings @@ -1,7 +1,11 @@  + True True + True True True True True - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/Watchdog/App.cpp b/Watchdog/App.cpp index 84cca10..4e1f3cc 100644 --- a/Watchdog/App.cpp +++ b/Watchdog/App.cpp @@ -1,8 +1,14 @@ #include "App.hpp" -#include "Util.h" #include #include +#include +#include +#include + +#include +#include + #pragma warning(disable: 26800) #include #include @@ -27,67 +33,6 @@ class WatchdogTask : public Poco::Task { bool _isInteractive; - static DWORD CheckServiceStatus(const std::wstring& serviceName, unsigned long& serviceState) - { - SC_HANDLE sch = nullptr; - SC_HANDLE svc = nullptr; - DWORD error = ERROR_SUCCESS; - - __try - { - sch = OpenSCManager( - nullptr, - nullptr, - SC_MANAGER_ALL_ACCESS - ); - if (sch == nullptr) - { - error = GetLastError(); - __leave; - } - - svc = OpenService( - sch, - serviceName.c_str(), - SC_MANAGER_ALL_ACCESS - ); - if (svc == nullptr) - { - error = GetLastError(); - __leave; - } - - SERVICE_STATUS_PROCESS stat; - DWORD needed = 0; - BOOL ret = QueryServiceStatusEx( - svc, - SC_STATUS_PROCESS_INFO, - (BYTE*)&stat, - sizeof stat, - &needed - ); - if (ret == 0) - { - error = GetLastError(); - __leave; - } - - serviceState = stat.dwCurrentState; - - error = ERROR_SUCCESS; - __leave; - } - __finally - { - if (svc) - CloseServiceHandle(svc); - if (sch) - CloseServiceHandle(sch); - } - - return error; - } - public: explicit WatchdogTask(const std::string& name, const bool isInteractive) : Task(name) @@ -105,71 +50,95 @@ class WatchdogTask : public Poco::Task do { - const auto serviceName = L"HidHide"; - unsigned long winError = 0, serviceStatus = 0; + const std::wstring serviceName = L"HidHide"; + + const auto serviceStatus = nefarius::winapi::services::GetServiceStatus(serviceName); // check if driver service is healthy - if ((winError = CheckServiceStatus(serviceName, serviceStatus)) != ERROR_SUCCESS) + if (!serviceStatus) { - spdlog::error("Failed to query service status, error {}", winError); + logger->error("Failed to query service status, error {}", serviceStatus.error().getErrorMessageA()); continue; } // expecting service to be running as an indicator that driver is loaded - if (serviceStatus != SERVICE_RUNNING) + if (serviceStatus.value().dwCurrentState != SERVICE_RUNNING) { - spdlog::error("Driver service not detected running, removing filter entries"); + logger->error("Driver service not detected running, removing filter entries"); // // Prevents bricked HID devices // - RemoveDeviceClassFilter(&GUID_DEVCLASS_HIDCLASS, - serviceName, util::DeviceClassFilterPosition::Upper); - RemoveDeviceClassFilter(&GUID_DEVCLASS_XNACOMPOSITE, - serviceName, util::DeviceClassFilterPosition::Upper); - RemoveDeviceClassFilter(&GUID_DEVCLASS_XBOXCOMPOSITE, - serviceName, util::DeviceClassFilterPosition::Upper); + auto removeResult = RemoveDeviceClassFilter(&GUID_DEVCLASS_HIDCLASS, + serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper); + + if (!removeResult) + { + logger->error("Removal from GUID_DEVCLASS_HIDCLASS failed with {}", + removeResult.error().getErrorMessageA()); + } + + removeResult = RemoveDeviceClassFilter(&GUID_DEVCLASS_XNACOMPOSITE, + serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper); + + if (!removeResult) + { + logger->error("Removal from GUID_DEVCLASS_XNACOMPOSITE failed with {}", + removeResult.error().getErrorMessageA()); + } + + removeResult = RemoveDeviceClassFilter(&GUID_DEVCLASS_XBOXCOMPOSITE, + serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper); + + if (!removeResult) + { + logger->error("Removal from GUID_DEVCLASS_XBOXCOMPOSITE failed with {}", + removeResult.error().getErrorMessageA()); + } continue; } // filter value or entry not present - if (bool found = false; !HasDeviceClassFilter(&GUID_DEVCLASS_HIDCLASS, serviceName, - util::DeviceClassFilterPosition::Upper, found) || !found) + if (!HasDeviceClassFilter(&GUID_DEVCLASS_HIDCLASS, serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper).value_or(false)) { - spdlog::warn("Filter missing for HIDClass, adding"); + logger->warn("Filter missing for HIDClass, adding"); if (!AddDeviceClassFilter(&GUID_DEVCLASS_HIDCLASS, serviceName, - util::DeviceClassFilterPosition::Upper)) + nefarius::devcon::DeviceClassFilterPosition::Upper)) { - spdlog::error("Failed to add upper filters entry for HIDClass"); + logger->error("Failed to add upper filters entry for HIDClass"); } } // filter value or entry not present - if (bool found = false; !HasDeviceClassFilter(&GUID_DEVCLASS_XNACOMPOSITE, serviceName, - util::DeviceClassFilterPosition::Upper, found) || !found) + if (!HasDeviceClassFilter(&GUID_DEVCLASS_XNACOMPOSITE, serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper).value_or(false)) { - spdlog::warn("Filter missing for XnaComposite, adding"); + logger->warn("Filter missing for XnaComposite, adding"); if (!AddDeviceClassFilter(&GUID_DEVCLASS_XNACOMPOSITE, serviceName, - util::DeviceClassFilterPosition::Upper)) + nefarius::devcon::DeviceClassFilterPosition::Upper)) { - spdlog::error("Failed to add upper filters entry for XnaComposite"); + logger->error("Failed to add upper filters entry for XnaComposite"); } } // filter value or entry not present - if (bool found = false; !HasDeviceClassFilter(&GUID_DEVCLASS_XBOXCOMPOSITE, serviceName, - util::DeviceClassFilterPosition::Upper, found) || !found) + if (!HasDeviceClassFilter(&GUID_DEVCLASS_XBOXCOMPOSITE, serviceName, + nefarius::devcon::DeviceClassFilterPosition::Upper).value_or(false)) { - spdlog::warn("Filter missing for XboxComposite, adding"); + logger->warn("Filter missing for XboxComposite, adding"); if (!AddDeviceClassFilter(&GUID_DEVCLASS_XBOXCOMPOSITE, serviceName, - util::DeviceClassFilterPosition::Upper)) + nefarius::devcon::DeviceClassFilterPosition::Upper)) { - spdlog::error("Failed to add upper filters entry for XboxComposite"); + logger->error("Failed to add upper filters entry for XboxComposite"); } } } @@ -211,9 +180,11 @@ int App::main(const std::vector& args) console->info("Application started"); - const bool isAdmin = util::IsAdmin(); +#if !defined(_DEBUG) + const auto isAdmin = nefarius::winapi::security::IsAppRunningAsAdminMode(); - if (isAdmin) + if (isAdmin.value_or(false)) +#endif { Poco::TaskManager tm; tm.start(new WatchdogTask("HidHideWatchdog", this->isInteractive())); @@ -221,12 +192,18 @@ int App::main(const std::vector& args) tm.cancelAll(); tm.joinAll(); } +#if !defined(_DEBUG) else { errLogger->error("App need administrative permissions to run"); } +#endif console->info("Exiting application"); +#if !defined(_DEBUG) return isAdmin ? EXIT_OK : EXIT_TEMPFAIL; +#else + return EXIT_OK; +#endif } diff --git a/Watchdog/AppIcon.rc b/Watchdog/AppIcon.rc new file mode 100644 index 0000000..6b75efe Binary files /dev/null and b/Watchdog/AppIcon.rc differ diff --git a/Watchdog/Util.cpp b/Watchdog/Util.cpp deleted file mode 100644 index 134d3b5..0000000 --- a/Watchdog/Util.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include "Util.h" -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - - -bool util::AddDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position) -{ - auto key = SetupDiOpenClassRegKey(classGuid, KEY_ALL_ACCESS); - - if (INVALID_HANDLE_VALUE == key) - { - spdlog::error("SetupDiOpenClassRegKey failed with error code {}", GetLastError()); - return false; - } - - LPCWSTR filterValue = (position == DeviceClassFilterPosition::Lower) ? L"LowerFilters" : L"UpperFilters"; - DWORD type, size; - std::vector filters; - - auto status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - nullptr, - &size - ); - - // - // Value exists already, read it with returned buffer size - // - if (status == ERROR_SUCCESS) - { - std::vector temp(size / sizeof(wchar_t)); - - status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - reinterpret_cast(&temp[0]), - &size - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegQueryValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - size_t index = 0; - size_t len = wcslen(&temp[0]); - while (len > 0) - { - filters.emplace_back(&temp[index]); - index += len + 1; - len = wcslen(&temp[index]); - } - - // - // Filter not there yet, add - // - if (std::ranges::find(filters, filterName) == filters.end()) - { - filters.emplace_back(filterName); - } - - const std::vector multiString = winreg::winreg_internal::BuildMultiString(filters); - - const auto& dataSize = multiString.size() * sizeof(wchar_t); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - static_cast(dataSize) - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegSetValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - // - // Value doesn't exist, create and populate - // - if (status == ERROR_FILE_NOT_FOUND) - { - filters.emplace_back(filterName); - - const std::vector multiString = winreg::winreg_internal::BuildMultiString(filters); - - const auto dataSize = multiString.size() * sizeof(wchar_t); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - // ReSharper disable once CppRedundantCastExpression - static_cast(dataSize) - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegSetValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - - RegCloseKey(key); - return false; -} - -bool util::RemoveDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position) -{ - auto key = SetupDiOpenClassRegKey(classGuid, KEY_ALL_ACCESS); - - if (INVALID_HANDLE_VALUE == key) - { - spdlog::error("SetupDiOpenClassRegKey failed with error code {}", GetLastError()); - return false; - } - - LPCWSTR filterValue = (position == DeviceClassFilterPosition::Lower) ? L"LowerFilters" : L"UpperFilters"; - DWORD type, size; - std::vector filters; - - auto status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - nullptr, - &size - ); - - // - // Value exists already, read it with returned buffer size - // - if (status == ERROR_SUCCESS) - { - std::vector temp(size / sizeof(wchar_t)); - - status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - reinterpret_cast(&temp[0]), - &size - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegQueryValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - // - // Remove value, if found - // - size_t index = 0; - size_t len = wcslen(&temp[0]); - while (len > 0) - { - if (filterName != &temp[index]) - { - filters.emplace_back(&temp[index]); - } - index += len + 1; - len = wcslen(&temp[index]); - } - - const std::vector multiString = winreg::winreg_internal::BuildMultiString(filters); - - const auto dataSize = multiString.size() * sizeof(wchar_t); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - // ReSharper disable once CppRedundantCastExpression - static_cast(dataSize) - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegSetValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - // - // Value doesn't exist, return - // - if (status == ERROR_FILE_NOT_FOUND) - { - RegCloseKey(key); - return true; - } - - RegCloseKey(key); - return false; -} - -bool util::HasDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position, bool& found) -{ - const auto key = SetupDiOpenClassRegKey(classGuid, KEY_READ); - - if (INVALID_HANDLE_VALUE == key) - { - spdlog::error("SetupDiOpenClassRegKey failed with error code {}", GetLastError()); - return false; - } - - LPCWSTR filterValue = (position == DeviceClassFilterPosition::Lower) ? L"LowerFilters" : L"UpperFilters"; - DWORD type, size; - std::vector filters; - - auto status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - nullptr, - &size - ); - - // - // Value exists already, read it with returned buffer size - // - if (status == ERROR_SUCCESS) - { - std::vector temp(size / sizeof(wchar_t)); - - status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - reinterpret_cast(&temp[0]), - &size - ); - - if (status != ERROR_SUCCESS) - { - spdlog::error("RegQueryValueExW failed with status {}", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - // - // Enumerate values - // - size_t index = 0; - size_t len = wcslen(&temp[0]); - while (len > 0) - { - if (filterName == &temp[index]) - { - found = true; - break; - } - index += len + 1; - len = wcslen(&temp[index]); - } - - RegCloseKey(key); - return true; - } - // - // Value doesn't exist, return - // - if (status == ERROR_FILE_NOT_FOUND) - { - RegCloseKey(key); - return true; - } - - RegCloseKey(key); - return false; -} - -unsigned long util::IsAdminMode(bool& is_admin) -{ - DWORD dwError = ERROR_SUCCESS; - PSID pAdministratorsGroup = nullptr; - BOOL IsAdmin = 0; - - // Allocate and initialize a SID of the administrators group. - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - if (!AllocateAndInitializeSid( - &NtAuthority, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &pAdministratorsGroup)) - { - dwError = GetLastError(); - goto Cleanup; - } - - // Determine whether the SID of administrators group is enabled in - // the primary access token of the process. - if (!CheckTokenMembership(nullptr, pAdministratorsGroup, &IsAdmin)) - { - dwError = GetLastError(); - } - - is_admin = IsAdmin > 0; - -Cleanup: - // Centralized cleanup for all allocated resources. - if (pAdministratorsGroup) - { - FreeSid(pAdministratorsGroup); - pAdministratorsGroup = nullptr; - } - - return dwError; -} - -bool util::IsAdmin() -{ - bool isAdmin = false; - - if (IsAdminMode(isAdmin) != ERROR_SUCCESS) - { - return false; - } - - if (!isAdmin) - { - return false; - } - - return true; -} diff --git a/Watchdog/Util.h b/Watchdog/Util.h deleted file mode 100644 index 7d7a31f..0000000 --- a/Watchdog/Util.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include - -namespace util -{ - struct DeviceClassFilterPosition - { - enum Value - { - Upper, - Lower - }; - }; - - bool AddDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position); - - bool RemoveDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position); - - bool HasDeviceClassFilter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position, bool& found); - - unsigned long IsAdminMode(bool& is_admin); - - bool IsAdmin(); -}; diff --git a/Watchdog/Watchdog.vcxproj b/Watchdog/Watchdog.vcxproj index 954bbf0..073b38b 100644 --- a/Watchdog/Watchdog.vcxproj +++ b/Watchdog/Watchdog.vcxproj @@ -98,7 +98,7 @@ true - true + true true @@ -119,7 +119,8 @@ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp20 + stdcpplatest + /utf-8 %(AdditionalOptions) Console @@ -136,7 +137,8 @@ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) true MultiThreaded - stdcpp20 + stdcpplatest + /utf-8 %(AdditionalOptions) Console @@ -154,7 +156,8 @@ _DEBUG;_WINDOWS;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp20 + stdcpplatest + /utf-8 %(AdditionalOptions) Console @@ -180,7 +183,8 @@ NDEBUG;_WINDOWS;%(PreprocessorDefinitions) true MultiThreaded - stdcpp20 + stdcpplatest + /utf-8 %(AdditionalOptions) Console @@ -201,22 +205,26 @@ - - + + + + + + - + \ No newline at end of file diff --git a/Watchdog/Watchdog.vcxproj.filters b/Watchdog/Watchdog.vcxproj.filters index 9374a80..569c4d2 100644 --- a/Watchdog/Watchdog.vcxproj.filters +++ b/Watchdog/Watchdog.vcxproj.filters @@ -21,9 +21,6 @@ Source Files - - Source Files - @@ -32,7 +29,7 @@ Header Files - + Header Files @@ -40,10 +37,19 @@ + Resource Files + + Resource Files + + + + + Resource Files + \ No newline at end of file diff --git a/Watchdog/favicon.ico b/Watchdog/favicon.ico index 58bc7d4..9d5d585 100644 Binary files a/Watchdog/favicon.ico and b/Watchdog/favicon.ico differ diff --git a/Watchdog/resource1.h b/Watchdog/resource1.h new file mode 100644 index 0000000..13d7ded --- /dev/null +++ b/Watchdog/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AppIcon.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Watchdog/vcpkg-configuration.json b/Watchdog/vcpkg-configuration.json new file mode 100644 index 0000000..ad3204c --- /dev/null +++ b/Watchdog/vcpkg-configuration.json @@ -0,0 +1,15 @@ +{ + "registries": [ + { + "kind": "git", + "repository": "https://github.com/nefarius/nefarius-vcpkg-registry.git", + "baseline": "b82fe0af4c127713acb1d1433e0796199080adce", + "packages": [ "neflib" ] + } + ], + "default-registry": { + "kind": "git", + "repository": "https://github.com/microsoft/vcpkg", + "baseline": "3508985146f1b1d248c67ead13f8f54be5b4f5da" + } +} diff --git a/Watchdog/vcpkg.json b/Watchdog/vcpkg.json index ab25a09..e0c2ac3 100644 --- a/Watchdog/vcpkg.json +++ b/Watchdog/vcpkg.json @@ -7,6 +7,7 @@ "dependencies": [ "poco", "spdlog", - "winreg" + "winreg", + "neflib" ] } diff --git a/appveyor.yml b/appveyor.yml index 87c2ca6..6ab0b79 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,9 @@ version: 1.5.{build}.0 build_cloud: WIN-LKR467JS4GL image: Windows configuration: Release +branches: + only: + - master skip_commits: files: - '**/*.md' @@ -9,8 +12,8 @@ test: off platform: - x64 install: -# manifest mode takes forever to build each commit so use global copy instead -- cmd: vcpkg install poco:%PLATFORM%-windows-static spdlog:%PLATFORM%-windows-static winreg:%PLATFORM%-windows-static +# this junction points to a RAM disk on the CI server significantly speeding up building dependencies +- cmd: mklink /J "%APPVEYOR_BUILD_FOLDER%\Watchdog\vcpkg_installed" "C:\tools\build-cache\HidHide\Watchdog\vcpkg_installed\%PLATFORM%" - ps: Setup-VS2022 build: project: $(APPVEYOR_BUILD_FOLDER)\$(APPVEYOR_PROJECT_NAME).sln