├── SG_PersistantService ├── stdafx.cpp ├── SG_PersistantService.vcxproj.user ├── SG_PersistantService.vcxproj.filters ├── SG_PersistantService.h ├── stdafx.h ├── SG_PersistantService.vcxproj └── SG_PersistantService.cpp ├── persistant service.gif ├── SampleApp └── SampleApp │ ├── SampleApp.h │ ├── small.ico │ ├── SampleApp.cpp │ ├── SampleApp.ico │ ├── SampleApp.rc │ ├── SampleApp.vcxproj.user │ ├── targetver.h │ ├── framework.h │ ├── Resource.h │ ├── SampleApp.vcxproj.filters │ └── SampleApp.vcxproj ├── uninstall.bat ├── .gitignore ├── README.md ├── SG_PersistantService.sln └── LICENSE /SG_PersistantService/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /persistant service.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/persistant service.gif -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/SampleApp/SampleApp/SampleApp.h -------------------------------------------------------------------------------- /SampleApp/SampleApp/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/SampleApp/SampleApp/small.ico -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/SampleApp/SampleApp/SampleApp.cpp -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/SampleApp/SampleApp/SampleApp.ico -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedglobe/PersistantService/HEAD/SampleApp/SampleApp/SampleApp.rc -------------------------------------------------------------------------------- /uninstall.bat: -------------------------------------------------------------------------------- 1 | sc stop sg_persistantservice 2 | sc delete sg_persistantservice 3 | taskkill /f /im sampleapp.exe 4 | taskkill /f /im sg_persistantservice.exe -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SG_PersistantService/SG_PersistantService.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SampleApp/SampleApp/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // // Including SDKDDKVer.h defines the highest available Windows platform. 4 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 5 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 6 | #include 7 | -------------------------------------------------------------------------------- /SampleApp/SampleApp/framework.h: -------------------------------------------------------------------------------- 1 | // header.h : include file for standard system include files, 2 | // or project specific include files 3 | // 4 | 5 | #pragma once 6 | 7 | #include "targetver.h" 8 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 9 | // Windows Header Files 10 | #include 11 | // C RunTime Header Files 12 | #include 13 | #include 14 | #include 15 | #include 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | /.vs 34 | /bin/x64/Release 35 | /SG_PersistantService/.vs/SG_RevealerService/v17 36 | /_intermediate/x64 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PersistantService 2 | ![](persistant%20service.gif) 3 | 4 | A persistent Windows Service Proof of Concept, where the Service will run after Restart or Shutdown, and invoke a given software executable. 5 | 6 | 1. The service is installed. 7 | 2. The service starts the Sample App (unless it's already running). That's the 'Watch dog' mechanism. 8 | 3. If you shut down SampleApp.exe, the service will restart it, whilst keeping it running. 9 | 4. If you reboot, the service will start, wait for the first user to log in and then start SampleApp.exe under the logged-on user's session. 10 | 5. The service is uninstalled using the uninstall 11 | -------------------------------------------------------------------------------- /SampleApp/SampleApp/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by SampleApp.rc 4 | 5 | #define IDS_APP_TITLE 103 6 | 7 | #define IDR_MAINFRAME 128 8 | #define IDD_ABOUTBOX 103 9 | #define IDM_ABOUT 104 10 | #define IDM_EXIT 105 11 | #define IDI_SAMPLEAPP 107 12 | #define IDI_SMALL 108 13 | #define IDC_SAMPLEAPP 109 14 | #define IDC_MYICON 2 15 | #ifndef IDC_STATIC 16 | #define IDC_STATIC -1 17 | #endif 18 | // Next default values for new objects 19 | // 20 | #ifdef APSTUDIO_INVOKED 21 | #ifndef APSTUDIO_READONLY_SYMBOLS 22 | 23 | #define _APS_NO_MFC 130 24 | #define _APS_NEXT_RESOURCE_VALUE 129 25 | #define _APS_NEXT_COMMAND_VALUE 32771 26 | #define _APS_NEXT_CONTROL_VALUE 1000 27 | #define _APS_NEXT_SYMED_VALUE 110 28 | #endif 29 | #endif 30 | -------------------------------------------------------------------------------- /SG_PersistantService/SG_PersistantService.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Source Files 6 | 7 | 8 | Source Files 9 | 10 | 11 | 12 | 13 | Header Files 14 | 15 | 16 | Header Files 17 | 18 | 19 | 20 | 21 | {8c48a4a7-b230-4488-aa2d-e9b176eca8d7} 22 | 23 | 24 | {db8678ad-7319-460d-9789-7c1652acff04} 25 | 26 | 27 | -------------------------------------------------------------------------------- /SG_PersistantService/SG_PersistantService.h: -------------------------------------------------------------------------------- 1 | /* 2 | SG_PersistantService 3 | by Michael Haephrati haephrati@gmail.com 4 | Secured Globe Persistant Windows Service 5 | ©2019-2022 Secured Globe, Inc. 6 | https://www.securedglobe.net 7 | 8 | Explained in https://www.codeproject.com/Articles/5345258/Thank-You-for-Your-Service-Creating-a-Persistent-I 9 | 10 | version 2.0 Nov 2022 11 | */ 12 | 13 | #pragma once 14 | 15 | // Customizable values 16 | #define SERVICE_NAME _T("SG_PersistantService")// Service name 17 | #define SERVICE_COMMAND_INSTALL L"Install" // The command line argument for installing the service 18 | 19 | #define SERVICE_COMMAND_Launcher L"ServiceIsLauncher" // Launcher command for NT service 20 | #define MAIN_CLASS_NAME L"ServiceClass" // Window class name for service client 21 | 22 | #define MAIN_TIMER_ID 2001 23 | 24 | 25 | void WriteToLog(LPCTSTR lpText, ...); 26 | 27 | void ReportServiceStatus(DWORD, DWORD, DWORD); 28 | void WINAPI InstallService(); 29 | void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args); 30 | std::wstring GetLoggedInUser(); 31 | void WINAPI ServiceMain(DWORD dwArgCount, LPTSTR lpszArgValues[]); 32 | DWORD WINAPI CtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pEventData, LPVOID pUserData); 33 | DWORD WINAPI AppMainFunction(); 34 | BOOL RunHost(LPWSTR HostExePath,LPWSTR CommandLineArguments); 35 | LRESULT CALLBACK S_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 36 | 37 | 38 | -------------------------------------------------------------------------------- /SG_PersistantService/stdafx.h: -------------------------------------------------------------------------------- 1 | /* 2 | SG_PersistantService 3 | by Michael Haephrati haephrati@gmail.com 4 | Secured Globe Persistant Windows Service 5 | ©2019-2022 Secured Globe, Inc. 6 | https://www.securedglobe.net 7 | 8 | Explained in https://www.codeproject.com/Articles/5345258/Thank-You-for-Your-Service-Creating-a-Persistent-I 9 | 10 | version 2.0 Nov 2022 11 | */ 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | // Common Standard Headers 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | // Common Windows Headers 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include 58 | #include 59 | 60 | #include 61 | #include 62 | #include // _open_osfhandle 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | 73 | #define _CRT_SECURE_NO_WARNINGS 74 | -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | Resource Files 39 | 40 | 41 | 42 | 43 | Resource Files 44 | 45 | 46 | Resource Files 47 | 48 | 49 | -------------------------------------------------------------------------------- /SG_PersistantService.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32825.248 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "SampleApp\SampleApp\SampleApp.vcxproj", "{FD6E6A1A-1925-4773-BCC1-102E2529D03F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SG_PersistantService", "SG_PersistantService\SG_PersistantService.vcxproj", "{5F47CDB7-9048-4D11-B8C8-497B88720C3E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Debug|x64.ActiveCfg = Debug|x64 19 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Debug|x64.Build.0 = Debug|x64 20 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Debug|x86.ActiveCfg = Debug|Win32 21 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Debug|x86.Build.0 = Debug|Win32 22 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Release|x64.ActiveCfg = Release|x64 23 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Release|x64.Build.0 = Release|x64 24 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Release|x86.ActiveCfg = Release|Win32 25 | {FD6E6A1A-1925-4773-BCC1-102E2529D03F}.Release|x86.Build.0 = Release|Win32 26 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Debug|x64.ActiveCfg = Debug|x64 27 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Debug|x64.Build.0 = Debug|x64 28 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Debug|x86.ActiveCfg = Debug|Win32 29 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Debug|x86.Build.0 = Debug|Win32 30 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Release|x64.ActiveCfg = Release|x64 31 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Release|x64.Build.0 = Release|x64 32 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Release|x86.ActiveCfg = Release|Win32 33 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {01633459-E09B-4822-B98B-0FD41AAD0FCC} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /SampleApp/SampleApp/SampleApp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {fd6e6a1a-1925-4773-bcc1-102e2529d03f} 25 | SampleApp 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 75 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 79 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 83 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 87 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 94 | true 95 | MultiThreadedDebug 96 | 97 | 98 | Windows 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | true 107 | true 108 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 109 | true 110 | MultiThreaded 111 | 112 | 113 | Windows 114 | true 115 | true 116 | true 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 124 | true 125 | MultiThreadedDebug 126 | 127 | 128 | Windows 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | true 136 | true 137 | true 138 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 139 | true 140 | MultiThreaded 141 | 142 | 143 | Windows 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /SG_PersistantService/SG_PersistantService.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {5F47CDB7-9048-4D11-B8C8-497B88720C3E} 23 | Win32Proj 24 | SGSrvWin 25 | 10.0 26 | SG_PersistantService 27 | 28 | 29 | 30 | Application 31 | true 32 | $(DefaultPlatformToolset) 33 | Unicode 34 | 35 | 36 | Application 37 | true 38 | $(DefaultPlatformToolset) 39 | Unicode 40 | 41 | 42 | Application 43 | false 44 | $(DefaultPlatformToolset) 45 | true 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | $(DefaultPlatformToolset) 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | true 73 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 74 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 75 | 76 | 77 | true 78 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 79 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 84 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 85 | 86 | 87 | false 88 | $(SolutionDir)bin\$(Platform)\$(Configuration)\ 89 | $(SolutionDir)_intermediate\$(Platform)\$(Configuration)\$(ProjectName)\ 90 | 91 | 92 | 93 | NotUsing 94 | Level3 95 | Disabled 96 | SG_SERVICE;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);CONSOLE 97 | MultiThreadedDebug 98 | $(ProjectDir);$(ProjectDir)filterdrv_user\;$(SolutionDir)common\;$(SolutionDir)common\SG_PersistantUtils\;%(AdditionalIncludeDirectories) 99 | stdcpplatest 100 | 101 | 102 | Windows 103 | true 104 | fltLib.lib;shlwapi.lib;version.lib;wtsapi32.lib;userenv.lib;psapi.lib;Setupapi.lib;Wininet.lib;Winmm.lib;%(AdditionalDependencies) 105 | RequireAdministrator 106 | $(SolutionDir)lib\$(Platform)\$(Configuration)\;$(SolutionDir)$(Platform)\$(Configuration)\;$(VCToolsInstallDir)\lib\$(PlatformShortName);$(VCToolsInstallDir)atlmfc\lib\$(PlatformShortName) 107 | /FORCE:MULTIPLE %(AdditionalOptions) 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | NotUsing 117 | Level3 118 | Disabled 119 | SG_SERVICE;X64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);CONSOLE 120 | MultiThreadedDebug 121 | $(ProjectDir);$(ProjectDir)filterdrv_user\;$(SolutionDir)common\;$(SolutionDir)common\SG_PersistantUtils\;%(AdditionalIncludeDirectories) 122 | stdcpplatest 123 | 124 | 125 | Windows 126 | true 127 | fltLib.lib;shlwapi.lib;version.lib;wtsapi32.lib;userenv.lib;psapi.lib;Setupapi.lib;Wininet.lib;Winmm.lib;%(AdditionalDependencies) 128 | RequireAdministrator 129 | $(SolutionDir)lib\$(Platform)\$(Configuration)\;$(SolutionDir)$(Platform)\$(Configuration)\;$(VCToolsInstallDir)\lib\$(PlatformShortName);$(VCToolsInstallDir)atlmfc\lib\$(PlatformShortName) 130 | /FORCE:MULTIPLE %(AdditionalOptions) 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | Level3 140 | NotUsing 141 | MinSpace 142 | true 143 | true 144 | SG_SERVICE;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);CONSOLE 145 | MultiThreaded 146 | Size 147 | $(ProjectDir);$(ProjectDir)filterdrv_user\;$(SolutionDir)common\;$(SolutionDir)common\SG_PersistantUtils\;%(AdditionalIncludeDirectories) 148 | stdcpplatest 149 | 150 | 151 | Windows 152 | false 153 | true 154 | true 155 | fltLib.lib;shlwapi.lib;version.lib;wtsapi32.lib;userenv.lib;psapi.lib;Setupapi.lib;Wininet.lib;Winmm.lib;%(AdditionalDependencies) 156 | $(OutDir)$(TargetName)$(TargetExt) 157 | RequireAdministrator 158 | $(SolutionDir)lib\$(Platform)\$(Configuration)\;$(SolutionDir)$(Platform)\$(Configuration)\;$(VCToolsInstallDir)\lib\$(PlatformShortName);$(VCToolsInstallDir)atlmfc\lib\$(PlatformShortName) 159 | 160 | /FORCE:MULTIPLE %(AdditionalOptions) 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | Level3 170 | NotUsing 171 | MinSpace 172 | true 173 | true 174 | SG_SERVICE;X64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);CONSOLE 175 | MultiThreaded 176 | Size 177 | $(ProjectDir);$(ProjectDir)filterdrv_user\;$(SolutionDir)common\;$(SolutionDir)common\SG_PersistantUtils\;%(AdditionalIncludeDirectories) 178 | stdcpplatest 179 | 180 | 181 | Windows 182 | false 183 | true 184 | true 185 | fltLib.lib;shlwapi.lib;version.lib;wtsapi32.lib;userenv.lib;psapi.lib;Setupapi.lib;Wininet.lib;Winmm.lib;%(AdditionalDependencies) 186 | RequireAdministrator 187 | $(SolutionDir)lib\$(Platform)\$(Configuration)\;$(SolutionDir)$(Platform)\$(Configuration)\;$(VCToolsInstallDir)\lib\$(PlatformShortName);$(VCToolsInstallDir)atlmfc\lib\$(PlatformShortName) 188 | /FORCE:MULTIPLE %(AdditionalOptions) 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | NotUsing 206 | 207 | 208 | Create 209 | Create 210 | NotUsing 211 | Create 212 | 213 | 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /SG_PersistantService/SG_PersistantService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SG_PersistantService 3 | by Michael Haephrati haephrati@gmail.com 4 | Secured Globe Persistant Windows Service 5 | ©2019-2022 Secured Globe, Inc. 6 | https://www.securedglobe.net 7 | 8 | Explained in https://www.codeproject.com/Articles/5345258/Thank-You-for-Your-Service-Creating-a-Persistent-I 9 | 10 | version 2.0 Nov 2022 11 | */ 12 | #include "stdafx.h" 13 | #include "SG_PersistantService.h" 14 | #pragma comment(lib, "wevtapi.lib") 15 | 16 | 17 | #define BUFFER_SIZE 1024 18 | #define DATETIME_BUFFER_SIZE 80 19 | #define SERVICE_REG_KEY L"SOFTWARE\\SG_PersistantService" 20 | #define SERVICE_KEY_NAME L"Path" 21 | #define EVENT_SUBSCRIBE_PATH L"Security" 22 | #define EVENT_SUBSCRIBE_QUERY L"Event/System[EventID=4624]" 23 | #define LOG_FILE_NAME L"log.txt" 24 | 25 | 26 | SERVICE_STATUS serviceStatus; 27 | SERVICE_STATUS_HANDLE hServiceStatus; 28 | HWND hWnd = NULL; 29 | HANDLE hPrevAppProcess = NULL; 30 | HANDLE ghSvcStopEvent = NULL; 31 | 32 | std::wstring m_szExeToFind{L""};//The executable file name without the path (to be found in the process list) 33 | std::wstring m_szExeToRun{L""}; //The executable full path to be launched by the Service 34 | bool g_bLoggedIn = false; // Is there a logged in user? 35 | 36 | 37 | 38 | // A class for handling subscription to the logon event and waiting for the user to log in 39 | class UserLoginListener 40 | { 41 | HANDLE hWait = NULL; 42 | HANDLE hSubscription = NULL; 43 | 44 | public: 45 | ~UserLoginListener() 46 | { 47 | CloseHandle(hWait); 48 | EvtClose(hSubscription); 49 | } 50 | 51 | UserLoginListener() 52 | { 53 | const wchar_t* pwsPath = EVENT_SUBSCRIBE_PATH; 54 | const wchar_t* pwsQuery = EVENT_SUBSCRIBE_QUERY; 55 | 56 | hWait = CreateEvent(NULL, FALSE, FALSE, NULL); 57 | 58 | hSubscription = EvtSubscribe(NULL, NULL, 59 | pwsPath, pwsQuery, 60 | NULL, 61 | hWait, 62 | (EVT_SUBSCRIBE_CALLBACK)UserLoginListener::SubscriptionCallback, 63 | EvtSubscribeToFutureEvents); 64 | if (hSubscription == NULL) 65 | { 66 | DWORD status = GetLastError(); 67 | 68 | if (ERROR_EVT_CHANNEL_NOT_FOUND == status) 69 | WriteToLog(L"Channel %s was not found.\n", pwsPath); 70 | else if (ERROR_EVT_INVALID_QUERY == status) 71 | WriteToLog(L"The query \"%s\" is not valid.\n", pwsQuery); 72 | else 73 | WriteToLog(L"EvtSubscribe failed with %lu.\n", status); 74 | 75 | CloseHandle(hWait); 76 | } 77 | } 78 | 79 | // Wait until a user logs in 80 | void WaitForUserToLogIn() 81 | { 82 | WriteToLog(L"Waiting for a user to log in..."); 83 | 84 | // Check if there are events already available 85 | EVT_HANDLE hEvents[1]; 86 | DWORD dwReturned; 87 | if (EvtNext(hSubscription, 1, hEvents, INFINITE, 0, &dwReturned)) 88 | { 89 | // Events are already available, indicating a user has logged in 90 | WriteToLog(L"Received a Logon event - a user has already logged in"); 91 | EvtClose(hEvents[0]); // Close the event handle 92 | return; 93 | } 94 | 95 | // Wait for events 96 | WaitForSingleObject(hWait, INFINITE); 97 | WriteToLog(L"Received a Logon event - a user has logged in"); 98 | } 99 | 100 | // The subscription callback function 101 | static DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent) 102 | { 103 | if (action == EvtSubscribeActionDeliver) 104 | { 105 | WriteToLog(L"SubscriptionCallback invoked."); 106 | HANDLE Handle = (HANDLE)(LONG_PTR)pContext; 107 | SetEvent(Handle); 108 | } 109 | 110 | return ERROR_SUCCESS; 111 | } 112 | }; 113 | 114 | 115 | // A helper function to redirect output from printf / wprintf to the Console 116 | void enableConsole() 117 | { 118 | //debug console 119 | AllocConsole(); 120 | AttachConsole(GetCurrentProcessId()); 121 | HWND Handle = GetConsoleWindow(); 122 | // Make the Console window transparent 123 | SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_LAYERED); 124 | // Opacity = 0.5 = (255/2) 125 | SetLayeredWindowAttributes(Handle, 0, 170, LWA_ALPHA); 126 | 127 | freopen("CON", "w", stdout); 128 | } 129 | 130 | /** 131 | * GetExePath() - returns the full path of the current executable. 132 | * 133 | * @param values - none. 134 | * @return a std::wstring containing the full path of the current executable. 135 | */ 136 | std::wstring GetExePath() 137 | { 138 | wchar_t buffer[65536]; 139 | GetModuleFileName(NULL, buffer, sizeof(buffer) / sizeof(*buffer)); 140 | int pos = -1; 141 | int index = 0; 142 | while (buffer[index]) 143 | { 144 | if (buffer[index] == L'\\' || buffer[index] == L'/') 145 | { 146 | pos = index; 147 | } 148 | index++; 149 | } 150 | buffer[pos + 1] = 0; 151 | return buffer; 152 | } 153 | 154 | /** 155 | * WriteToLog() - writes formatted text into a log file, and on screen (console) 156 | * 157 | * @param values - formatted text, such as L"The result is %d",result. 158 | * @return - none 159 | */ 160 | void WriteToLog(LPCTSTR lpText, ...) 161 | { 162 | FILE *fp; 163 | wchar_t log_file[MAX_PATH]{L""}; 164 | if(wcscmp(log_file,L"") == NULL) 165 | { 166 | wcscpy_s(log_file,GetExePath().c_str()); 167 | wcscat_s(log_file,LOG_FILE_NAME); 168 | } 169 | // find gmt time, and store in buf_time 170 | time_t rawtime; 171 | struct tm* ptm; 172 | wchar_t buf_time[DATETIME_BUFFER_SIZE]; 173 | time(&rawtime); 174 | ptm = gmtime(&rawtime); 175 | wcsftime(buf_time, sizeof(buf_time) / sizeof(*buf_time), L"%d.%m.%Y %H:%M", ptm); 176 | 177 | // store passed messsage (lpText) to buffer_in 178 | wchar_t buffer_in[BUFFER_SIZE]; 179 | 180 | va_list ptr; 181 | va_start(ptr, lpText); 182 | 183 | vswprintf(buffer_in, BUFFER_SIZE, lpText, ptr); 184 | va_end(ptr); 185 | 186 | 187 | // store output message to buffer_out - enabled multiple parameters in swprintf 188 | wchar_t buffer_out[BUFFER_SIZE]; 189 | 190 | swprintf(buffer_out, BUFFER_SIZE, L"%s %s\n", buf_time, buffer_in); 191 | 192 | _wfopen_s(&fp, log_file, L"a,ccs=UTF-8"); 193 | if (fp) 194 | { 195 | fwprintf(fp, L"%s\n", buffer_out); 196 | fclose(fp); 197 | } 198 | wcscat_s(buffer_out,L"\n");HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE); 199 | if (stdOut != NULL && stdOut != INVALID_HANDLE_VALUE) 200 | { 201 | DWORD written = 0; 202 | WriteConsole(stdOut, buffer_out,(DWORD)wcslen(buffer_out),&written, NULL); 203 | } 204 | } 205 | 206 | /* 207 | * Create Key in registry hive 208 | * @param hKeyParent Parent registry key store under which registry key needs to be created. ex. HKEY_LOCAL_MACHINE 209 | * @param subkey String value to specify exact location where key needs to be created ex. SOFTWARE\\SG_PersistantService 210 | * @return Status of operation, TRUE if success and FALSE in case of failure 211 | */ 212 | BOOL CreateRegistryKey(HKEY hKeyParent, PWCHAR subkey) 213 | { 214 | DWORD dwDisposition; //It verify new key is created or open existing key 215 | HKEY hKey; 216 | DWORD Ret; 217 | Ret = 218 | RegCreateKeyEx( 219 | hKeyParent, 220 | subkey, 221 | 0, 222 | NULL, 223 | REG_OPTION_NON_VOLATILE, 224 | KEY_ALL_ACCESS, 225 | NULL, 226 | &hKey, 227 | &dwDisposition); 228 | if (Ret != ERROR_SUCCESS) 229 | { 230 | WriteToLog(L"Error opening or creating new key\n"); 231 | return FALSE; 232 | } 233 | RegCloseKey(hKey); //close the key 234 | return TRUE; 235 | } 236 | 237 | /* 238 | * Sets the string data of a specified value under a registry key. 239 | * @param hKeyParent registy key under which subkey to be written ex. HKEY_LOCAL_MACHINE 240 | * @param subkey The name of the registry subkey to be opened 241 | * @param valueName The name of the value to be set 242 | * @param strData The data to be stored. 243 | * @return Status of operation, TRUE if success and FALSE in case of failure 244 | */ 245 | BOOL writeStringInRegistry(HKEY hKeyParent, PWCHAR subkey, PWCHAR valueName, PWCHAR strData) 246 | { 247 | DWORD Ret; 248 | HKEY hKey; 249 | //Check if the registry exists 250 | Ret = RegOpenKeyEx( 251 | hKeyParent, 252 | subkey, 253 | 0, 254 | KEY_WRITE, 255 | &hKey 256 | ); 257 | if (Ret == ERROR_SUCCESS) 258 | { 259 | if (ERROR_SUCCESS != 260 | RegSetValueEx( 261 | hKey, 262 | valueName, 263 | 0, 264 | REG_SZ, 265 | (LPBYTE)(strData), 266 | ((((DWORD)lstrlen(strData) + 1)) * 2))) 267 | { 268 | RegCloseKey(hKey); 269 | return FALSE; 270 | } 271 | RegCloseKey(hKey); 272 | return TRUE; 273 | } 274 | return FALSE; 275 | } 276 | 277 | LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue) 278 | { 279 | strValue = strDefaultValue; 280 | TCHAR szBuffer[MAX_PATH]; 281 | DWORD dwBufferSize = sizeof(szBuffer); 282 | ULONG nError; 283 | nError = RegQueryValueEx(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize); 284 | if (nError == ERROR_SUCCESS) 285 | { 286 | strValue = szBuffer; 287 | if (strValue.front() == _T('"') && strValue.back() == _T('"')) 288 | { 289 | strValue.erase(0, 1); // erase the first character 290 | strValue.erase(strValue.size() - 1); // erase the last character 291 | } 292 | } 293 | return nError; 294 | } 295 | 296 | /* 297 | * @param hKeyParent registy key under which subkey to be written ex. HKEY_LOCAL_MACHINE 298 | * @param subkey The name of the registry subkey to be opened 299 | * @param valueName The name of the value to read 300 | * @param readData wide string data to read from specified registry valueName 301 | * @return Status of operation, TRUE if success and FALSE in case of failure 302 | */ 303 | BOOL readStringFromRegistry(HKEY hKeyParent, PWCHAR subkey, PWCHAR valueName, std::wstring& readData) 304 | { 305 | HKEY hKey; 306 | DWORD len = 1024; 307 | DWORD readDataLen = len; 308 | PWCHAR readBuffer = (PWCHAR)malloc(sizeof(PWCHAR) * len); 309 | if (readBuffer == NULL) 310 | return FALSE; 311 | //Check if the registry exists 312 | DWORD Ret = RegOpenKeyEx( 313 | hKeyParent, 314 | subkey, 315 | 0, 316 | KEY_READ, 317 | &hKey 318 | ); 319 | if (Ret == ERROR_SUCCESS) 320 | { 321 | Ret = RegQueryValueEx( 322 | hKey, 323 | valueName, 324 | NULL, 325 | NULL, 326 | (BYTE*)readBuffer, 327 | &readDataLen 328 | ); 329 | while (Ret == ERROR_MORE_DATA) 330 | { 331 | // Get a buffer that is big enough. 332 | len += 1024; 333 | readBuffer = (PWCHAR)realloc(readBuffer, len); 334 | readDataLen = len; 335 | Ret = RegQueryValueEx( 336 | hKey, 337 | valueName, 338 | NULL, 339 | NULL, 340 | (BYTE*)readBuffer, 341 | &readDataLen 342 | ); 343 | } 344 | if (Ret != ERROR_SUCCESS) 345 | { 346 | RegCloseKey(hKey); 347 | return false;; 348 | } 349 | readData = readBuffer; 350 | RegCloseKey(hKey); 351 | return true; 352 | } 353 | else 354 | { 355 | return false; 356 | } 357 | } 358 | /*! 359 | Service main routine. 360 | 361 | SG_WinService.exe Install - Service installation 362 | SG_WinService.exe ServiceIsLauncher - Start the client 363 | */ 364 | 365 | 366 | // 367 | int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow) 368 | { 369 | LPWSTR command = (LPTSTR)L""; 370 | int argc; 371 | std::wstring w_szLogFileName; 372 | wchar_t **argv = CommandLineToArgvW(::GetCommandLineW(), &argc); 373 | if (argc > 1) 374 | command = argv[1]; 375 | 376 | enableConsole(); 377 | 378 | WriteToLog(L"SG_PersistantService Windows Service: command = '%s'\n\n", command); 379 | if (::wcsstr(command, SERVICE_COMMAND_INSTALL) != NULL) 380 | { 381 | // Obtaining the full path of the service and adding the special service name quotations 382 | TCHAR szPath[MAX_PATH] = { 0 }; 383 | BOOL status; 384 | GetModuleFileName(NULL, szPath, MAX_PATH); 385 | 386 | WriteToLog(L"Option 1 - Install"); 387 | // parse argument for get module path 388 | wchar_t* real_path = wcschr(command, L'#'); 389 | if (real_path) 390 | { 391 | real_path++; 392 | m_szExeToRun = real_path; 393 | } 394 | if(PathFileExists(m_szExeToRun.c_str())) 395 | { 396 | WriteToLog(L"[WatchDog] Install module path: %s\n", m_szExeToRun.c_str()); 397 | 398 | status = CreateRegistryKey(HKEY_LOCAL_MACHINE, (PWCHAR)SERVICE_REG_KEY); //create key 399 | if (status != TRUE) 400 | WriteToLog(L"Failed to create registry"); 401 | //RunHost((LPWSTR)m_szExeToRun.c_str(),(LPWSTR)L""); 402 | } 403 | else 404 | { 405 | WriteToLog(L"App to run '%s' doesn't exist",m_szExeToRun.c_str()); 406 | } 407 | InstallService(); 408 | 409 | } 410 | else if (::wcsstr(command, SERVICE_COMMAND_Launcher) != NULL) 411 | { 412 | WriteToLog(L"ServiceIsLauncher\n"); 413 | AppMainFunction(); 414 | } 415 | else // called with no args 416 | { 417 | WriteToLog(L"No args\n"); 418 | 419 | SERVICE_TABLE_ENTRY serviceTableEntry[] = 420 | { 421 | { 422 | (LPWSTR)SERVICE_NAME,ServiceMain 423 | }, 424 | { 425 | NULL, NULL 426 | } 427 | }; 428 | StartServiceCtrlDispatcher(serviceTableEntry); 429 | } 430 | 431 | return 0; 432 | } 433 | 434 | 435 | DWORD GetServiceProcessID(SC_HANDLE hService) 436 | { 437 | SERVICE_STATUS_PROCESS serviceStatus; 438 | DWORD dwBytesNeeded; 439 | 440 | DWORD result = ::QueryServiceStatusEx(hService 441 | , SC_STATUS_PROCESS_INFO 442 | , reinterpret_cast(&serviceStatus) 443 | , sizeof(SERVICE_STATUS_PROCESS) 444 | , &dwBytesNeeded); 445 | 446 | return (result != 0) ? serviceStatus.dwProcessId : 0; 447 | } 448 | 449 | /*! 450 | Service installation 451 | */ 452 | void WINAPI InstallService() 453 | { 454 | 455 | 456 | // Obtaining the full path of the service and adding the special service name quotations 457 | TCHAR szServicePath[MAX_PATH] = { _T("\"") }; 458 | TCHAR szPath[MAX_PATH] = { 0 }; 459 | GetModuleFileName(NULL, szPath, MAX_PATH); 460 | lstrcat(szServicePath, szPath); 461 | lstrcat(szServicePath, _T("\"")); 462 | 463 | SC_HANDLE hSCManager = NULL; 464 | SC_HANDLE hService = NULL; 465 | 466 | hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 467 | 468 | if (!hSCManager) 469 | { 470 | return; 471 | } 472 | 473 | 474 | hService = CreateService(hSCManager, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS 475 | | SERVICE_USER_DEFINED_CONTROL | READ_CONTROL 476 | | WRITE_DAC | WRITE_OWNER, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, 477 | szServicePath, NULL, NULL, NULL, NULL, _T("")); 478 | 479 | if (hService == NULL) 480 | { 481 | // Service already installed, just open it 482 | hService = OpenService(hSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); 483 | if (hService == NULL) 484 | { 485 | CloseServiceHandle(hSCManager); 486 | return; 487 | } 488 | return; 489 | } 490 | 491 | SERVICE_DESCRIPTION description = { (LPTSTR)_T("Secured Globe Windows Service")}; 492 | ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &description); 493 | 494 | // Starting the service 495 | if (!StartService(hService, 0, NULL)) 496 | { 497 | WriteToLog(L"Error %d\n", ::GetLastError()); 498 | } 499 | else 500 | { 501 | } 502 | 503 | CloseServiceHandle(hService); 504 | CloseServiceHandle(hSCManager); 505 | } 506 | 507 | 508 | /*! 509 | */ 510 | void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) 511 | { 512 | static DWORD dwCheckPoint = 1; 513 | 514 | serviceStatus.dwCurrentState = dwCurrentState; 515 | serviceStatus.dwWin32ExitCode = dwWin32ExitCode; 516 | serviceStatus.dwWaitHint = dwWaitHint; 517 | 518 | if (dwCurrentState == SERVICE_START_PENDING) 519 | serviceStatus.dwControlsAccepted = 0; 520 | else 521 | serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE; 522 | 523 | if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) 524 | serviceStatus.dwCheckPoint = 0; 525 | else 526 | serviceStatus.dwCheckPoint = dwCheckPoint++; 527 | 528 | if (dwCurrentState == SERVICE_START_PENDING) 529 | serviceStatus.dwControlsAccepted = 0; 530 | else 531 | { 532 | serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; 533 | serviceStatus.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE; 534 | } 535 | 536 | if ((dwCurrentState == SERVICE_RUNNING) || 537 | (dwCurrentState == SERVICE_STOPPED)) 538 | serviceStatus.dwCheckPoint = 0; 539 | else serviceStatus.dwCheckPoint = dwCheckPoint++; 540 | 541 | // Report the status of the service to the SCM. 542 | SetServiceStatus(hServiceStatus, &serviceStatus); 543 | } 544 | 545 | //Function to run a process as active user from windows service 546 | void ImpersonateActiveUserAndRun() 547 | { 548 | DWORD session_id = -1; 549 | DWORD session_count = 0; 550 | WTS_SESSION_INFOW *pSession = NULL; 551 | 552 | if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count)) 553 | { 554 | WriteToLog(L"WTSEnumerateSessions - success"); 555 | } 556 | else 557 | { 558 | WriteToLog(L"WTSEnumerateSessions - failed. Error %d",GetLastError()); 559 | return; 560 | } 561 | TCHAR szCurModule[MAX_PATH] = { 0 }; 562 | 563 | GetModuleFileName(NULL, szCurModule, MAX_PATH); 564 | 565 | 566 | for (size_t i = 0; i < session_count; i++) 567 | { 568 | session_id = pSession[i].SessionId; 569 | WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected; 570 | WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL; 571 | DWORD bytes_returned = 0; 572 | if (::WTSQuerySessionInformation( 573 | WTS_CURRENT_SERVER_HANDLE, 574 | session_id, 575 | WTSConnectState, 576 | reinterpret_cast(&ptr_wts_connect_state), 577 | &bytes_returned)) 578 | { 579 | wts_connect_state = *ptr_wts_connect_state; 580 | ::WTSFreeMemory(ptr_wts_connect_state); 581 | if (wts_connect_state != WTSActive) continue; 582 | } 583 | else 584 | { 585 | continue; 586 | } 587 | 588 | HANDLE hImpersonationToken; 589 | if (!WTSQueryUserToken(session_id, &hImpersonationToken)) 590 | { 591 | continue; 592 | } 593 | 594 | //Get the actual token from impersonation one 595 | DWORD neededSize1 = 0; 596 | HANDLE *realToken = new HANDLE; 597 | if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1)) 598 | { 599 | CloseHandle(hImpersonationToken); 600 | hImpersonationToken = *realToken; 601 | } 602 | else 603 | { 604 | continue; 605 | } 606 | HANDLE hUserToken; 607 | if (!DuplicateTokenEx(hImpersonationToken, 608 | TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED, 609 | NULL, 610 | SecurityImpersonation, 611 | TokenPrimary, 612 | &hUserToken)) 613 | { 614 | continue; 615 | } 616 | 617 | 618 | // Get user name of this process 619 | WCHAR* pUserName; 620 | DWORD user_name_len = 0; 621 | if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len)) 622 | { 623 | //Now we got the user name stored in pUserName 624 | } 625 | // Free allocated memory 626 | if (pUserName) WTSFreeMemory(pUserName); 627 | ImpersonateLoggedOnUser(hUserToken); 628 | STARTUPINFOW StartupInfo; 629 | GetStartupInfoW(&StartupInfo); 630 | StartupInfo.cb = sizeof(STARTUPINFOW); 631 | PROCESS_INFORMATION processInfo; 632 | SECURITY_ATTRIBUTES Security1; 633 | Security1.nLength = sizeof SECURITY_ATTRIBUTES; 634 | SECURITY_ATTRIBUTES Security2; 635 | Security2.nLength = sizeof SECURITY_ATTRIBUTES; 636 | void* lpEnvironment = NULL; 637 | 638 | // Obtain all needed necessary environment variables of the logged in user. 639 | // They will then be passed to the new process we create. 640 | 641 | BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE); 642 | if (!resultEnv) 643 | { 644 | WriteToLog(L"CreateEnvironmentBlock - failed. Error %d",GetLastError()); 645 | continue; 646 | } 647 | std::wstring commandLine; 648 | commandLine.reserve(1024); 649 | commandLine += L"\""; 650 | commandLine += szCurModule; 651 | commandLine += L"\" \""; 652 | commandLine += SERVICE_COMMAND_Launcher; 653 | commandLine += L"\""; 654 | WCHAR PP[1024]; //path and parameters 655 | ZeroMemory(PP, 1024 * sizeof WCHAR); 656 | wcscpy_s(PP, commandLine.c_str()); 657 | 658 | // Next we impersonate - by starting the process as if the current logged in user, has started it 659 | BOOL result = CreateProcessAsUserW(hUserToken, 660 | NULL, 661 | PP, 662 | NULL, 663 | NULL, 664 | FALSE, 665 | NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, 666 | NULL, 667 | NULL, 668 | &StartupInfo, 669 | &processInfo); 670 | 671 | if (!result) 672 | { 673 | WriteToLog(L"CreateProcessAsUser - failed. Error %d",GetLastError()); 674 | } 675 | else 676 | { 677 | WriteToLog(L"CreateProcessAsUser - success"); 678 | } 679 | DestroyEnvironmentBlock(lpEnvironment); 680 | CloseHandle(hImpersonationToken); 681 | CloseHandle(hUserToken); 682 | CloseHandle(realToken); 683 | RevertToSelf(); 684 | } 685 | WTSFreeMemory(pSession); 686 | } 687 | std::wstring GetLoggedInUser() 688 | { 689 | std::wstring user{L""}; 690 | WTS_SESSION_INFO *SessionInfo; 691 | unsigned long SessionCount; 692 | unsigned long ActiveSessionId = -1; 693 | 694 | //std::cout<<"Active Console Session Id : "<LinkedToken; 817 | break; 818 | } 819 | CloseHandle(userToken); 820 | } 821 | else 822 | { 823 | DWORD error = GetLastError(); 824 | { 825 | LPVOID lpMsgBuf; 826 | DWORD bufLen = FormatMessage( 827 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 828 | FORMAT_MESSAGE_FROM_SYSTEM | 829 | FORMAT_MESSAGE_IGNORE_INSERTS, 830 | NULL, 831 | error, 832 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 833 | (LPTSTR)&lpMsgBuf, 834 | 0, NULL); 835 | } 836 | } 837 | } 838 | if (hToken == 0) 839 | { 840 | HANDLE systemToken; 841 | OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &systemToken); 842 | DuplicateTokenEx(systemToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hToken); 843 | CloseHandle(systemToken); 844 | int i; 845 | for (i = 0; i < (int)cnt; i++) 846 | { 847 | if (si[i].SessionId == 0)continue; 848 | if (SetTokenInformation(hToken, TokenSessionId, &si[i].SessionId, sizeof(DWORD))) 849 | { 850 | break; 851 | } 852 | } 853 | } 854 | WTSFreeMemory(si); 855 | 856 | 857 | STARTUPINFO startupInfo = {}; 858 | startupInfo.cb = sizeof(STARTUPINFO); 859 | 860 | startupInfo.lpDesktop = (LPWSTR)L"..."; 861 | 862 | LPVOID pEnv = NULL; 863 | CreateEnvironmentBlock(&pEnv, hToken, TRUE); 864 | 865 | PROCESS_INFORMATION processInfo = {}; 866 | PROCESS_INFORMATION processInfo32 = {}; 867 | 868 | TCHAR szCurModule[MAX_PATH] = { 0 }; 869 | GetModuleFileName(NULL, szCurModule, MAX_PATH); 870 | 871 | BOOL bRes = FALSE; 872 | 873 | { 874 | std::wstring commandLine; 875 | commandLine.reserve(1024); 876 | 877 | commandLine += L"\""; 878 | commandLine += szCurModule; 879 | commandLine += L"\" \""; 880 | commandLine += SERVICE_COMMAND_Launcher; 881 | commandLine += L"\""; 882 | 883 | 884 | bRes = CreateProcessAsUserW(hToken, NULL, &commandLine[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | 885 | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE, pEnv, 886 | NULL, &startupInfo, &processInfo); 887 | 888 | if (bRes == FALSE) 889 | { 890 | DWORD dwLastError = ::GetLastError(); 891 | TCHAR lpBuffer[256] = _T("?"); 892 | if (dwLastError != 0) // Don't want to see a "operation done successfully" error ;-) 893 | ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, // It磗 a system error 894 | NULL, // No string to be formatted needed 895 | dwLastError, // Hey Windows: Please explain this error! 896 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Do it in the standard language 897 | lpBuffer, // Put the message here 898 | 255, // Number of bytes to store the message 899 | NULL); 900 | } 901 | else 902 | { 903 | } 904 | } 905 | } 906 | 907 | /*! 908 | */ 909 | DWORD WINAPI CtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pEventData, LPVOID pUserData) 910 | { 911 | switch (dwControl) 912 | { 913 | case SERVICE_CONTROL_SHUTDOWN: 914 | case SERVICE_CONTROL_STOP: 915 | { 916 | if (dwControl == SERVICE_CONTROL_SHUTDOWN) 917 | WriteToLog(L"SERVICE_CONTROL_SHUTDOWN"); 918 | else 919 | WriteToLog(L"SERVICE_CONTROL_STOP"); 920 | // Service stopped by the user 921 | ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); 922 | SetEvent(ghSvcStopEvent); 923 | ReportServiceStatus(serviceStatus.dwCurrentState, NO_ERROR, 0); 924 | } 925 | break; 926 | case SERVICE_CONTROL_PAUSE: 927 | { 928 | WriteToLog(L"SERVICE_CONTROL_PAUSE"); 929 | } 930 | break; 931 | case SERVICE_CONTROL_CONTINUE: 932 | { 933 | WriteToLog(L"SERVICE_CONTROL_CONTINUE"); 934 | } 935 | break; 936 | case SERVICE_CONTROL_INTERROGATE: 937 | { 938 | WriteToLog(L"SERVICE_CONTROL_INTERROGATE"); 939 | } 940 | break; 941 | case SERVICE_CONTROL_PARAMCHANGE: 942 | { 943 | WriteToLog(L"SERVICE_CONTROL_PARAMCHANGE"); 944 | } 945 | break; 946 | case SERVICE_CONTROL_NETBINDADD: 947 | { 948 | WriteToLog(L"SERVICE_CONTROL_NETBINDADD"); 949 | } 950 | break; 951 | case SERVICE_CONTROL_NETBINDREMOVE: 952 | { 953 | WriteToLog(L"SERVICE_CONTROL_NETBINDREMOVE"); 954 | } 955 | break; 956 | case SERVICE_CONTROL_NETBINDENABLE: 957 | { 958 | WriteToLog(L"SERVICE_CONTROL_NETBINDENABLE"); 959 | } 960 | break; 961 | case SERVICE_CONTROL_NETBINDDISABLE: 962 | { 963 | WriteToLog(L"SERVICE_CONTROL_NETBINDDISABLE"); 964 | } 965 | break; 966 | case SERVICE_CONTROL_DEVICEEVENT: 967 | { 968 | WriteToLog(L"SERVICE_CONTROL_DEVICEEVENT"); 969 | } 970 | break; 971 | case SERVICE_CONTROL_HARDWAREPROFILECHANGE: 972 | { 973 | WriteToLog(L"SERVICE_CONTROL_HARDWAREPROFILECHANGE"); 974 | } 975 | break; 976 | case SERVICE_CONTROL_POWEREVENT: 977 | { 978 | WriteToLog(L"SERVICE_CONTROL_POWEREVENT"); 979 | } 980 | break; 981 | case SERVICE_CONTROL_SESSIONCHANGE: 982 | { 983 | WriteToLog(L"SERVICE_CONTROL_SESSIONCHANGE"); 984 | switch (dwEventType) 985 | { 986 | case WTS_CONSOLE_CONNECT: 987 | { 988 | WriteToLog(L"WTS_CONSOLE_CONNECT"); 989 | } 990 | break; 991 | case WTS_CONSOLE_DISCONNECT: 992 | { 993 | WriteToLog(L"WTS_CONSOLE_DISCONNECT"); 994 | } 995 | break; 996 | case WTS_REMOTE_CONNECT: 997 | { 998 | WriteToLog(L"WTS_REMOTE_CONNECT"); 999 | } 1000 | break; 1001 | case WTS_REMOTE_DISCONNECT: 1002 | { 1003 | WriteToLog(L"WTS_REMOTE_DISCONNECT"); 1004 | } 1005 | break; 1006 | case WTS_SESSION_LOGON: 1007 | { 1008 | // User logon, startup the client app 1009 | WriteToLog(L"WTS_SESSION_LOGON"); 1010 | ImpersonateActiveUserAndRun(); 1011 | } 1012 | break; 1013 | case WTS_SESSION_LOGOFF: 1014 | { 1015 | WriteToLog(L"WTS_SESSION_LOGOFF"); 1016 | // User logoff, the client app has been closed, reset hPrevAppProcess 1017 | hPrevAppProcess = NULL; 1018 | } 1019 | break; 1020 | case WTS_SESSION_LOCK: 1021 | { 1022 | WriteToLog(L"WTS_SESSION_LOCK"); 1023 | } 1024 | break; 1025 | case WTS_SESSION_UNLOCK: 1026 | { 1027 | WriteToLog(L"WTS_SESSION_UNLOCK"); 1028 | } 1029 | break; 1030 | case WTS_SESSION_REMOTE_CONTROL: 1031 | { 1032 | WriteToLog(L"WTS_SESSION_REMOTE_CONTROL"); 1033 | } 1034 | break; 1035 | case WTS_SESSION_CREATE: 1036 | { 1037 | WriteToLog(L"WTS_SESSION_CREATE"); 1038 | } 1039 | break; 1040 | case WTS_SESSION_TERMINATE: 1041 | { 1042 | WriteToLog(L"WTS_SESSION_TERMINATE"); 1043 | } 1044 | break; 1045 | } 1046 | } 1047 | break; 1048 | case SERVICE_CONTROL_PRESHUTDOWN: 1049 | { 1050 | WriteToLog(L"SERVICE_CONTROL_PRESHUTDOWN"); 1051 | } 1052 | break; 1053 | case SERVICE_CONTROL_TIMECHANGE: 1054 | { 1055 | WriteToLog(L"SERVICE_CONTROL_TIMECHANGE"); 1056 | } 1057 | break; 1058 | case SERVICE_CONTROL_TRIGGEREVENT: 1059 | { 1060 | WriteToLog(L"SERVICE_CONTROL_TRIGGEREVENT"); 1061 | } 1062 | break; 1063 | default: 1064 | return ERROR_CALL_NOT_IMPLEMENTED; 1065 | } 1066 | 1067 | ReportServiceStatus(serviceStatus.dwCurrentState, NO_ERROR, 0); 1068 | return NO_ERROR; 1069 | } 1070 | 1071 | 1072 | void MyRegisterClass(HINSTANCE hInstance) 1073 | { 1074 | WNDCLASSEX wcex = { sizeof(wcex) }; 1075 | wcex.style = CS_HREDRAW | CS_VREDRAW; 1076 | wcex.lpfnWndProc = S_WndProc; 1077 | wcex.hInstance = hInstance; 1078 | wcex.hIcon = NULL; 1079 | wcex.hCursor = NULL; 1080 | wcex.hbrBackground = NULL; 1081 | wcex.lpszMenuName = NULL; 1082 | wcex.lpszClassName = MAIN_CLASS_NAME; 1083 | RegisterClassEx(&wcex); 1084 | } 1085 | 1086 | /*! 1087 | Service client main application 1088 | */ 1089 | 1090 | DWORD WINAPI AppMainFunction() 1091 | { 1092 | //HRESULT w_hRet = S_OK; 1093 | // AppMainFunction start 1094 | WriteToLog(L"AppMainFunction start\n"); 1095 | 1096 | HINSTANCE hInstance = GetModuleHandle(NULL); 1097 | 1098 | // Setting the working directory to the currect 1099 | // application folder rather than System32 1100 | TCHAR szDirPath[MAX_PATH] = { 0 }; 1101 | GetModuleFileName(NULL, szDirPath, MAX_PATH); 1102 | PathRemoveFileSpec(szDirPath); 1103 | SetCurrentDirectory(szDirPath); 1104 | 1105 | 1106 | // Registering the main window class 1107 | MyRegisterClass(hInstance); 1108 | 1109 | // Creating the main window 1110 | hWnd = CreateWindow(MAIN_CLASS_NAME, _T(""), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 1111 | CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 1112 | 1113 | if (hWnd) 1114 | { 1115 | g_bLoggedIn = true; 1116 | SetTimer(hWnd, MAIN_TIMER_ID, 10000, NULL); 1117 | // SG Persistant Service [%S %S] has started 1118 | WriteToLog(L"SG Persistant Service [%S %S] has started\n", 1119 | __DATE__, 1120 | __TIME__); 1121 | } 1122 | else 1123 | { 1124 | // CreateWindow failed 1125 | WriteToLog(L"CreateWindow failed\n"); 1126 | } 1127 | 1128 | 1129 | MSG msg; 1130 | while (GetMessage(&msg, NULL, 0, 0)) 1131 | { 1132 | TranslateMessage(&msg); 1133 | DispatchMessage(&msg); 1134 | } 1135 | hWnd = NULL; 1136 | 1137 | 1138 | return (DWORD)msg.wParam; 1139 | } 1140 | 1141 | 1142 | 1143 | /* 1144 | RunHost 1145 | */ 1146 | 1147 | BOOL RunHost(LPWSTR HostExePath,LPWSTR CommandLineArguments) 1148 | { 1149 | WriteToLog(L"RunHost '%s'",HostExePath); 1150 | 1151 | STARTUPINFO startupInfo = {}; 1152 | startupInfo.cb = sizeof(STARTUPINFO); 1153 | startupInfo.lpDesktop = (LPTSTR)_T("winsta0\\default"); 1154 | 1155 | HANDLE hToken = 0; 1156 | BOOL bRes = FALSE; 1157 | 1158 | LPVOID pEnv = NULL; 1159 | CreateEnvironmentBlock(&pEnv, hToken, TRUE); 1160 | 1161 | PROCESS_INFORMATION processInfoAgent = {}; 1162 | PROCESS_INFORMATION processInfoHideProcess = {}; 1163 | PROCESS_INFORMATION processInfoHideProcess32 = {}; 1164 | 1165 | if (PathFileExists(HostExePath)) 1166 | { 1167 | std::wstring commandLine; 1168 | commandLine.reserve(1024); 1169 | 1170 | 1171 | commandLine += L"\""; 1172 | commandLine += HostExePath; 1173 | commandLine += L"\" \""; 1174 | commandLine += CommandLineArguments; 1175 | commandLine += L"\""; 1176 | 1177 | WriteToLog(L"launch host with CreateProcessAsUser ... %s", commandLine.c_str()); 1178 | 1179 | bRes = CreateProcessAsUserW(hToken, NULL, &commandLine[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | 1180 | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE, pEnv, 1181 | NULL, &startupInfo, &processInfoAgent); 1182 | if (bRes == FALSE) 1183 | { 1184 | DWORD dwLastError = ::GetLastError(); 1185 | TCHAR lpBuffer[256] = _T("?"); 1186 | if (dwLastError != 0) // Don't want to see a "operation done successfully" error ;-) 1187 | { 1188 | ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, // It´s a system error 1189 | NULL, // No string to be formatted needed 1190 | dwLastError, // Hey Windows: Please explain this error! 1191 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Do it in the standard language 1192 | lpBuffer, // Put the message here 1193 | 255, // Number of bytes to store the message 1194 | NULL); 1195 | } 1196 | WriteToLog(L"CreateProcessAsUser failed - Command Line = %s Error : %s",commandLine, lpBuffer); 1197 | } 1198 | else 1199 | { 1200 | if (!writeStringInRegistry(HKEY_LOCAL_MACHINE, (PWCHAR)SERVICE_REG_KEY, (PWCHAR)SERVICE_KEY_NAME, HostExePath)) 1201 | { 1202 | WriteToLog(L"Failed to write registry"); 1203 | } 1204 | 1205 | } 1206 | } 1207 | else 1208 | { 1209 | WriteToLog(L"RunHost failed because path '%s' does not exists",HostExePath); 1210 | } 1211 | hPrevAppProcess = processInfoAgent.hProcess; 1212 | 1213 | CloseHandle(hToken); 1214 | WriteToLog(L"Run host end!"); 1215 | 1216 | return bRes; 1217 | } 1218 | 1219 | /*! 1220 | Service client message loop 1221 | */ 1222 | LRESULT CALLBACK S_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 1223 | { 1224 | //int wmId, wmEvent; 1225 | std::wstring drive; 1226 | static HDEVNOTIFY hDeviceNotify; 1227 | static bool is_running{ false }; 1228 | 1229 | switch (message) 1230 | { 1231 | case WM_ENDSESSION: 1232 | case WM_QUERYENDSESSION: 1233 | { 1234 | WriteToLog(L"Logging off\n"); // Logging off 1235 | KillTimer(hWnd, MAIN_TIMER_ID); 1236 | g_bLoggedIn = false; 1237 | //Suspend_FltDrv(); 1238 | return 0; 1239 | } 1240 | 1241 | case WM_TIMER: 1242 | { 1243 | if (is_running) break; 1244 | WriteToLog(L"Timer event"); 1245 | is_running = true; 1246 | is_running = true; 1247 | std::wstring szPath = L""; 1248 | 1249 | WriteToLog(L"Checking if '%s' is running...", m_szExeToFind.c_str()); 1250 | 1251 | if (readStringFromRegistry(HKEY_LOCAL_MACHINE, (PWCHAR)SERVICE_REG_KEY, (PWCHAR)SERVICE_KEY_NAME, szPath)) 1252 | { 1253 | m_szExeToFind = szPath.substr(szPath.find_last_of(L"/\\") + 1); // The process name is the executable name only 1254 | m_szExeToRun = szPath; // The executable to run is the full path 1255 | } 1256 | else 1257 | { 1258 | WriteToLog(L"Error reading ExeToFind from the Registry"); 1259 | is_running = false; 1260 | return 1; 1261 | } 1262 | 1263 | // Initialize a flag to check if the program is already running 1264 | bool programRunning = false; 1265 | 1266 | HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 1267 | if (hProcessSnap == INVALID_HANDLE_VALUE) 1268 | { 1269 | WriteToLog(L"Failed to call CreateToolhelp32Snapshot(). Error code %d", GetLastError()); 1270 | is_running = false; 1271 | return 1; 1272 | } 1273 | 1274 | PROCESSENTRY32 pe32; 1275 | pe32.dwSize = sizeof(PROCESSENTRY32); 1276 | 1277 | if (Process32First(hProcessSnap, &pe32)) 1278 | { 1279 | do 1280 | { 1281 | if (_wcsicmp(m_szExeToFind.c_str(), pe32.szExeFile) == 0) 1282 | { 1283 | // The program is running 1284 | WriteToLog(L"%s is running", m_szExeToFind.c_str()); 1285 | programRunning = true; 1286 | break; // Exit the loop as we found the program 1287 | } 1288 | } 1289 | while (Process32Next(hProcessSnap, &pe32)); 1290 | } 1291 | 1292 | CloseHandle(hProcessSnap); 1293 | 1294 | if (!programRunning) 1295 | { 1296 | WriteToLog(L"'%s' is not running. Need to start it", m_szExeToFind.c_str()); 1297 | if (!m_szExeToRun.empty()) // Watch Dog start the host app 1298 | { 1299 | if (!g_bLoggedIn) 1300 | { 1301 | WriteToLog(L"WatchDog isn't starting '%s' because the user isn't logged in", m_szExeToFind.c_str()); 1302 | return 1; 1303 | } 1304 | ImpersonateActiveUserAndRun(); 1305 | 1306 | RunHost((LPWSTR)m_szExeToRun.c_str(), (LPWSTR)L""); 1307 | 1308 | } 1309 | else 1310 | { 1311 | WriteToLog(L"m_szExeToRun is empty"); 1312 | } 1313 | } 1314 | 1315 | is_running = false; 1316 | 1317 | 1318 | } 1319 | default: 1320 | is_running=false; 1321 | return DefWindowProc(hWnd, message, wParam, lParam); 1322 | 1323 | } 1324 | 1325 | return 0; 1326 | } 1327 | --------------------------------------------------------------------------------