├── shell.ico ├── VCEnhancedKeyClear ├── resource.h ├── Resource.rc ├── stdafx.cpp ├── targetver.h ├── stdafx.h ├── Installer.h ├── defines.h ├── VCEnhancedKeyClear.vcxproj.filters ├── VCEnhancedKeyClear.cpp ├── VCEnhancedKeyClear.vcxproj └── Installer.cpp ├── VCEnhancedKeyClear.sln ├── README.md └── .gitignore /shell.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineOwningSoftware/VCEnhancedKeyClear/HEAD/shell.ico -------------------------------------------------------------------------------- /VCEnhancedKeyClear/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineOwningSoftware/VCEnhancedKeyClear/HEAD/VCEnhancedKeyClear/resource.h -------------------------------------------------------------------------------- /VCEnhancedKeyClear/Resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineOwningSoftware/VCEnhancedKeyClear/HEAD/VCEnhancedKeyClear/Resource.rc -------------------------------------------------------------------------------- /VCEnhancedKeyClear/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // VCEnhancedKeyClear.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/Installer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class CInstaller 6 | { 7 | private: 8 | 9 | std::wstring m_szExePath; 10 | std::wstring m_szTargetPath; 11 | 12 | std::wstring GetTargetExecutable(); 13 | 14 | HRESULT GetTaskFolderAndService(void** ppTaskFolder, void** ppTaskService); 15 | 16 | DWORD UninstallFiles(); 17 | 18 | DWORD UninstallTask(); 19 | 20 | public: 21 | 22 | std::wstring& GetTargetPath(bool Create = false); 23 | 24 | DWORD Install(); 25 | 26 | DWORD Uninstall(); 27 | 28 | CInstaller(const wchar_t* szExePath); 29 | 30 | }; -------------------------------------------------------------------------------- /VCEnhancedKeyClear/defines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #pragma comment(lib, "Wtsapi32.lib") 5 | #pragma comment(lib, "Advapi32.lib") 6 | #pragma comment(lib, "taskschd.lib") 7 | #pragma comment(lib, "comsupp.lib") 8 | #pragma comment(lib, "credui.lib") 9 | 10 | // VeraCrypt defines 11 | #define TC_SYSTEM_FAVORITES_SERVICE_NAME _T("VeraCryptSystemFavorites") 12 | #define VC_DRIVER_CONFIG_CLEAR_KEYS_ON_NEW_DEVICE_INSERTION 0x400 13 | #define VC_SERVICE_CONTROL_BUILD_DEVICE_LIST 128 14 | 15 | // VCEKC defines 16 | #define VCEKC_CLASSNAME _T("VCEnhancedKeyClear_WndClass") 17 | #define VCEKC_WINDOWNAME _T("VCEnhancedKeyClear_Wnd") 18 | #define VCEKC_MSGTITLE _T("VeraCrypt Enhanced Key Clear") 19 | #define VCEKC_TOOLTIPMSG _T("VeraCrypt Enhanced Key Clear is active. Right-click to exit.") 20 | #define VCEKC_MUTEX _T("VCEnhancedKeyClear_Mutex") 21 | #define VCEKC_INSTALLPATH _T("VeraCryptEnhancedKeyClear") 22 | #define VCEKC_EXENAME _T("VCEnhancedKeyClear.exe") 23 | #define VCEKC_TASKNAME _T("VeraCrypt Enhanced Key Clear") 24 | #define VCEKC_SHELLICONMSG 0xBEFC 25 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCEnhancedKeyClear", "VCEnhancedKeyClear\VCEnhancedKeyClear.vcxproj", "{249E8898-07BC-4438-95E4-EF16B2BCE943}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Debug|x64.ActiveCfg = Debug|x64 17 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Debug|x64.Build.0 = Debug|x64 18 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Debug|x86.ActiveCfg = Debug|Win32 19 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Debug|x86.Build.0 = Debug|Win32 20 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Release|x64.ActiveCfg = Release|x64 21 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Release|x64.Build.0 = Release|x64 22 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Release|x86.ActiveCfg = Release|Win32 23 | {249E8898-07BC-4438-95E4-EF16B2BCE943}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/VCEnhancedKeyClear.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;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 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | 49 | 50 | Resource Files 51 | 52 | 53 | 54 | 55 | Resource Files 56 | 57 | 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # # **[VCEnhancedKeyClear](https://github.com/EngineOwningSoftware/VCEnhancedKeyClear)** for [VeraCrypt](https://www.veracrypt.fr/en/Home.html) 2 | 3 | While Direct Memory Access (DMA) attacks gained some [recognition in the game hacking scene](https://github.com/EngineOwningSoftware/pcileech-webradar) they were initially used for data extraction from encrypted computers. Tools exist to grab encryption keys for full disk encryption from RAM to fully recover drive contents if a DMA device can be inserted to the running system. 4 | 5 | 6 | # Protection 7 | 8 | The widely used TrueCrypt fork **VeraCrypt** is equipped with an option called *Clear encryption keys from memory if a new device is inserted* since version 1.24. While this is an efficient way to protect against key extraction via DMA it has some drawbacks: 9 | 10 | - The option has to be re-enabled manually after every computer restart 11 | - Whenever a new device is inserted while this option is enabled (USB sticks, monitors, etc) the system will hang and eventually bluescreen because Windows can't access system files anymore. 12 | 13 | 14 | # Tradeoff 15 | 16 | VCEnhancedKeyClear was developed to have a tradeoff between the mentioned drawbacks and the valueable protection of that mechanism. The small tool registers a notification when the computers lock-state changes using the WinAPI function *[WTSRegisterSessionNotification()](https://docs.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsregistersessionnotification)* and switches the *Clear encryption keys from memory if a new device is inserted* option on demand so it is only enabled while the system is locked. 17 | 18 | Also a small installer is ~planned~ **implemented** (see below) so the tool can be automatically started when a user logs on. 19 | Additionally it features a tray icon so you can disable it at any time. 20 | 21 | # Update 0.2 22 | 23 | Since VeraCrypt version 1.26.7 when you turn on *Clear encryption keys from memory if a new device is inserted*, it will build a whitelist of known devices which are allowed to reconnect. VCEnhancedKeyClear has been updated to notify the VeraCrypt service to rebuild the device list when you lock the station. 24 | Therefore displays that wake up from sleep, network interruptions etc. do not cause system crashes anymore making this tool as usable as ever! 25 | Also you can now run VCEnhancedKeyClear with the *--install* command line parameter (as admin!) which will copy itself to your *Program Files* folder and create a scheduled task to automatically launch VCEnhancedKeyClear on logon. 26 | You can use *--uninstall* to remove the file and scheduled task again. 27 | Please note: multi user support has not been tested nor is it expected to work without issues at this time. 28 | 29 | # Download 30 | 31 | A precompiled build of this software can be found at [Releases](https://github.com/EngineOwningSoftware/VCEnhancedKeyClear/releases). 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*[.json, .xml, .info] 146 | 147 | # Visual Studio code coverage results 148 | *.coverage 149 | *.coveragexml 150 | 151 | # NCrunch 152 | _NCrunch_* 153 | .*crunch*.local.xml 154 | nCrunchTemp_* 155 | 156 | # MightyMoose 157 | *.mm.* 158 | AutoTest.Net/ 159 | 160 | # Web workbench (sass) 161 | .sass-cache/ 162 | 163 | # Installshield output folder 164 | [Ee]xpress/ 165 | 166 | # DocProject is a documentation generator add-in 167 | DocProject/buildhelp/ 168 | DocProject/Help/*.HxT 169 | DocProject/Help/*.HxC 170 | DocProject/Help/*.hhc 171 | DocProject/Help/*.hhk 172 | DocProject/Help/*.hhp 173 | DocProject/Help/Html2 174 | DocProject/Help/html 175 | 176 | # Click-Once directory 177 | publish/ 178 | 179 | # Publish Web Output 180 | *.[Pp]ublish.xml 181 | *.azurePubxml 182 | # Note: Comment the next line if you want to checkin your web deploy settings, 183 | # but database connection strings (with potential passwords) will be unencrypted 184 | *.pubxml 185 | *.publishproj 186 | 187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 188 | # checkin your Azure Web App publish settings, but sensitive information contained 189 | # in these scripts will be unencrypted 190 | PublishScripts/ 191 | 192 | # NuGet Packages 193 | *.nupkg 194 | # NuGet Symbol Packages 195 | *.snupkg 196 | # The packages folder can be ignored because of Package Restore 197 | **/[Pp]ackages/* 198 | # except build/, which is used as an MSBuild target. 199 | !**/[Pp]ackages/build/ 200 | # Uncomment if necessary however generally it will be regenerated when needed 201 | #!**/[Pp]ackages/repositories.config 202 | # NuGet v3's project.json files produces more ignorable files 203 | *.nuget.props 204 | *.nuget.targets 205 | 206 | # Microsoft Azure Build Output 207 | csx/ 208 | *.build.csdef 209 | 210 | # Microsoft Azure Emulator 211 | ecf/ 212 | rcf/ 213 | 214 | # Windows Store app package directories and files 215 | AppPackages/ 216 | BundleArtifacts/ 217 | Package.StoreAssociation.xml 218 | _pkginfo.txt 219 | *.appx 220 | *.appxbundle 221 | *.appxupload 222 | 223 | # Visual Studio cache files 224 | # files ending in .cache can be ignored 225 | *.[Cc]ache 226 | # but keep track of directories ending in .cache 227 | !?*.[Cc]ache/ 228 | 229 | # Others 230 | ClientBin/ 231 | ~$* 232 | *~ 233 | *.dbmdl 234 | *.dbproj.schemaview 235 | *.jfm 236 | *.pfx 237 | *.publishsettings 238 | orleans.codegen.cs 239 | 240 | # Including strong name files can present a security risk 241 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 242 | #*.snk 243 | 244 | # Since there are multiple workflows, uncomment next line to ignore bower_components 245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 246 | #bower_components/ 247 | 248 | # RIA/Silverlight projects 249 | Generated_Code/ 250 | 251 | # Backup & report files from converting an old project file 252 | # to a newer Visual Studio version. Backup files are not needed, 253 | # because we have git ;-) 254 | _UpgradeReport_Files/ 255 | Backup*/ 256 | UpgradeLog*.XML 257 | UpgradeLog*.htm 258 | ServiceFabricBackup/ 259 | *.rptproj.bak 260 | 261 | # SQL Server files 262 | *.mdf 263 | *.ldf 264 | *.ndf 265 | 266 | # Business Intelligence projects 267 | *.rdl.data 268 | *.bim.layout 269 | *.bim_*.settings 270 | *.rptproj.rsuser 271 | *- [Bb]ackup.rdl 272 | *- [Bb]ackup ([0-9]).rdl 273 | *- [Bb]ackup ([0-9][0-9]).rdl 274 | 275 | # Microsoft Fakes 276 | FakesAssemblies/ 277 | 278 | # GhostDoc plugin setting file 279 | *.GhostDoc.xml 280 | 281 | # Node.js Tools for Visual Studio 282 | .ntvs_analysis.dat 283 | node_modules/ 284 | 285 | # Visual Studio 6 build log 286 | *.plg 287 | 288 | # Visual Studio 6 workspace options file 289 | *.opt 290 | 291 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 292 | *.vbw 293 | 294 | # Visual Studio LightSwitch build output 295 | **/*.HTMLClient/GeneratedArtifacts 296 | **/*.DesktopClient/GeneratedArtifacts 297 | **/*.DesktopClient/ModelManifest.xml 298 | **/*.Server/GeneratedArtifacts 299 | **/*.Server/ModelManifest.xml 300 | _Pvt_Extensions 301 | 302 | # Paket dependency manager 303 | .paket/paket.exe 304 | paket-files/ 305 | 306 | # FAKE - F# Make 307 | .fake/ 308 | 309 | # CodeRush personal settings 310 | .cr/personal 311 | 312 | # Python Tools for Visual Studio (PTVS) 313 | __pycache__/ 314 | *.pyc 315 | 316 | # Cake - Uncomment if you are using it 317 | # tools/** 318 | # !tools/packages.config 319 | 320 | # Tabs Studio 321 | *.tss 322 | 323 | # Telerik's JustMock configuration file 324 | *.jmconfig 325 | 326 | # BizTalk build output 327 | *.btp.cs 328 | *.btm.cs 329 | *.odx.cs 330 | *.xsd.cs 331 | 332 | # OpenCover UI analysis results 333 | OpenCover/ 334 | 335 | # Azure Stream Analytics local run output 336 | ASALocalRun/ 337 | 338 | # MSBuild Binary and Structured Log 339 | *.binlog 340 | 341 | # NVidia Nsight GPU debugger configuration file 342 | *.nvuser 343 | 344 | # MFractors (Xamarin productivity tool) working folder 345 | .mfractor/ 346 | 347 | # Local History for Visual Studio 348 | .localhistory/ 349 | 350 | # BeatPulse healthcheck temp database 351 | healthchecksdb 352 | 353 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 354 | MigrationBackup/ 355 | 356 | # Ionide (cross platform F# VS Code tools) working folder 357 | .ionide/ 358 | 359 | # Fody - auto-generated XML schema 360 | FodyWeavers.xsd 361 | 362 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/VCEnhancedKeyClear.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "resource.h" 3 | #include "defines.h" 4 | #include "Installer.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | NOTIFYICONDATA nid{}; 11 | 12 | bool VeraCryptBuildDeviceList() 13 | { 14 | SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 15 | bool bRet = false; 16 | 17 | if (hSCManager != NULL) 18 | { 19 | SC_HANDLE hService = OpenService(hSCManager, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS); 20 | 21 | if (hService != NULL) 22 | { 23 | SERVICE_STATUS serviceStatus{}; 24 | 25 | if (ControlService(hService, VC_SERVICE_CONTROL_BUILD_DEVICE_LIST, &serviceStatus)) 26 | { 27 | bRet = true; 28 | } 29 | 30 | CloseServiceHandle(hService); 31 | } 32 | 33 | CloseServiceHandle(hSCManager); 34 | } 35 | 36 | return bRet; 37 | } 38 | 39 | bool SetClearKeysFlag(bool state) 40 | { 41 | HKEY hkey = NULL; 42 | DWORD configMap = 0; 43 | DWORD type = 0; 44 | DWORD size = sizeof(DWORD); 45 | 46 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\veracrypt"), 0, KEY_READ | KEY_WRITE, &hkey) != ERROR_SUCCESS) 47 | { 48 | return false; 49 | } 50 | 51 | if (RegQueryValueEx(hkey, _T("VeraCryptConfig"), NULL, &type, reinterpret_cast(&configMap), &size) != ERROR_SUCCESS) 52 | { 53 | RegCloseKey(hkey); 54 | return false; 55 | } 56 | 57 | if (state) 58 | configMap |= VC_DRIVER_CONFIG_CLEAR_KEYS_ON_NEW_DEVICE_INSERTION; 59 | else 60 | configMap &= ~VC_DRIVER_CONFIG_CLEAR_KEYS_ON_NEW_DEVICE_INSERTION; 61 | 62 | bool result = true; 63 | 64 | if (RegSetValueEx(hkey, _T("VeraCryptConfig"), NULL, type, reinterpret_cast(&configMap), size) != ERROR_SUCCESS) 65 | { 66 | result = false; 67 | } 68 | 69 | RegCloseKey(hkey); 70 | return result; 71 | } 72 | 73 | LRESULT CALLBACK VcekcWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 74 | { 75 | switch (message) 76 | { 77 | case WM_WTSSESSION_CHANGE: 78 | { 79 | bool resSetConfig = true; 80 | bool resBuildDeviceList = true; 81 | 82 | switch (wParam) 83 | { 84 | default: break; 85 | case WTS_SESSION_UNLOCK: 86 | resSetConfig = SetClearKeysFlag(false); 87 | break; 88 | case WTS_SESSION_LOCK: 89 | resBuildDeviceList = VeraCryptBuildDeviceList(); 90 | resSetConfig = SetClearKeysFlag(true); 91 | break; 92 | } 93 | 94 | if (!resSetConfig) 95 | { 96 | MessageBox(NULL, _T("Failed to change VC_DRIVER_CONFIG_CLEAR_KEYS_ON_NEW_DEVICE_INSERTION"), VCEKC_MSGTITLE, MB_ICONEXCLAMATION | MB_OK); 97 | } 98 | 99 | if (!resBuildDeviceList) 100 | { 101 | MessageBox(NULL, _T("Failed to send VC_SERVICE_CONTROL_BUILD_DEVICE_LIST"), VCEKC_MSGTITLE, MB_ICONEXCLAMATION | MB_OK); 102 | } 103 | 104 | break; 105 | } 106 | case VCEKC_SHELLICONMSG: 107 | { 108 | switch (lParam) 109 | { 110 | case WM_RBUTTONDOWN: 111 | case WM_CONTEXTMENU: 112 | if (MessageBox(NULL, _T("Are you sure you want to quit VeraCrypt Enhanced Key Clear?"), VCEKC_MSGTITLE, MB_ICONQUESTION | MB_YESNO) == IDYES) 113 | { 114 | PostQuitMessage(0); 115 | } 116 | break; 117 | } 118 | 119 | break; 120 | } 121 | case WM_DESTROY: 122 | { 123 | Shell_NotifyIcon(NIM_DELETE, &nid); 124 | break; 125 | } 126 | } 127 | 128 | return DefWindowProc(hWnd, message, wParam, lParam); 129 | } 130 | 131 | int wWinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, PWSTR lpCmdLine, int /* nShowCmd */) 132 | { 133 | // Handle install/uninstall command line parameters 134 | int argc = 0; 135 | auto argv = CommandLineToArgvW(lpCmdLine, &argc); 136 | 137 | if (argv != nullptr) 138 | { 139 | TCHAR OwnPath[MAX_PATH]{}; 140 | GetModuleFileName(NULL, OwnPath, _countof(OwnPath)); 141 | 142 | CInstaller installer(OwnPath); 143 | 144 | for (int i = 0; i < argc; i++) 145 | { 146 | DWORD dwStatus = ERROR_SUCCESS; 147 | 148 | if (!_wcsicmp(argv[i], L"--install")) 149 | { 150 | dwStatus = installer.Install(); 151 | if (dwStatus == ERROR_SUCCESS) 152 | { 153 | wprintf(L"Successfully installed VeraCryptEnhancedKeyClear to %s\n", installer.GetTargetPath().c_str()); 154 | return 0; 155 | } 156 | 157 | wprintf(L"Failed to install VeraCryptEnhancedKeyClear: 0x%X\n", dwStatus); 158 | return dwStatus; 159 | } 160 | else if (!_wcsicmp(argv[i], L"--uninstall")) 161 | { 162 | dwStatus = installer.Uninstall(); 163 | if (dwStatus == ERROR_SUCCESS) 164 | { 165 | wprintf(L"Successfully removed VeraCryptEnhancedKeyClear\n"); 166 | return 0; 167 | } 168 | 169 | wprintf(L"Failed to uninstall VeraCryptEnhancedKeyClear: 0x%X\n", dwStatus); 170 | return dwStatus; 171 | } 172 | else if (!_wcsicmp(argv[i], L"--autorun")) 173 | { 174 | STARTUPINFOW startupInfo{}; 175 | PROCESS_INFORMATION processInfo{}; 176 | 177 | startupInfo.cb = sizeof(startupInfo); 178 | 179 | if (CreateProcessW(NULL, OwnPath, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) 180 | { 181 | CloseHandle(processInfo.hThread); 182 | CloseHandle(processInfo.hProcess); 183 | return ERROR_SUCCESS; 184 | } 185 | 186 | return GetLastError(); 187 | } 188 | } 189 | 190 | LocalFree(argv); 191 | } 192 | 193 | // Check if another instance is running 194 | SetLastError(0); 195 | auto mutex = CreateMutex(NULL, TRUE, VCEKC_MUTEX); 196 | if (GetLastError() == ERROR_ALREADY_EXISTS) 197 | { 198 | MessageBox(NULL, _T("Another instance of this program is already running. Make sure to close it first."), VCEKC_MSGTITLE, MB_ICONEXCLAMATION); 199 | return -1; 200 | } 201 | 202 | // Create hidden window 203 | WNDCLASS wndclass{}; 204 | wndclass.style = CS_DBLCLKS | CS_PARENTDC; 205 | wndclass.lpfnWndProc = VcekcWndProc; 206 | wndclass.cbClsExtra = 0; 207 | wndclass.cbWndExtra = 0; 208 | wndclass.hInstance = hInstance; 209 | wndclass.hIcon = NULL; 210 | wndclass.hCursor = LoadCursor(NULL, (LPTSTR)IDC_IBEAM); 211 | wndclass.hbrBackground = NULL; 212 | wndclass.lpszMenuName = NULL; 213 | wndclass.lpszClassName = VCEKC_CLASSNAME; 214 | 215 | if (!RegisterClass(&wndclass)) 216 | { 217 | MessageBox(NULL, _T("RegisterClass() failed"), VCEKC_MSGTITLE, MB_ICONERROR | MB_OK); 218 | return -1; 219 | } 220 | 221 | auto hwnd = CreateWindowEx( 222 | 0, 223 | VCEKC_CLASSNAME, 224 | VCEKC_WINDOWNAME, 225 | 0, 226 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 227 | NULL, 228 | NULL, 229 | hInstance, 230 | NULL 231 | ); 232 | 233 | if (hwnd == NULL) 234 | { 235 | UnregisterClass(VCEKC_CLASSNAME, hInstance); 236 | MessageBox(NULL, _T("CreateWindowEx() failed"), VCEKC_MSGTITLE, MB_ICONERROR | MB_OK); 237 | return -1; 238 | } 239 | 240 | // Make sure to receive session notifications 241 | if (!WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_ALL_SESSIONS)) 242 | { 243 | DestroyWindow(hwnd); 244 | UnregisterClass(VCEKC_CLASSNAME, hInstance); 245 | MessageBox(NULL, _T("WTSRegisterSessionNotification() failed"), VCEKC_MSGTITLE, MB_ICONERROR | MB_OK); 246 | return -1; 247 | } 248 | 249 | // Add shell icon 250 | nid.cbSize = sizeof(nid); 251 | nid.uCallbackMessage = VCEKC_SHELLICONMSG; 252 | nid.hWnd = hwnd; 253 | nid.uID = 15; 254 | nid.uVersion = NOTIFYICON_VERSION; 255 | nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; 256 | nid.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); 257 | StringCchCopy(nid.szTip, sizeof(nid.szTip) / sizeof(nid.szTip[0]), VCEKC_TOOLTIPMSG); 258 | 259 | BOOL IconCreated = FALSE; 260 | int IconCreateTries = 0; 261 | 262 | do 263 | { 264 | IconCreated = Shell_NotifyIcon(NIM_ADD, &nid); 265 | Sleep(500); // xd 266 | } while (!IconCreated && ++IconCreateTries < 120); 267 | // If we didn't manage to create the icon, fuck it. better to run anyway 268 | 269 | // Message loop 270 | MSG msg{}; 271 | while (GetMessage(&msg, NULL, 0, 0) > 0) 272 | { 273 | TranslateMessage(&msg); 274 | DispatchMessage(&msg); 275 | } 276 | 277 | DestroyWindow(hwnd); 278 | UnregisterClass(VCEKC_CLASSNAME, hInstance); 279 | 280 | return 0; 281 | } 282 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/VCEnhancedKeyClear.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 | {249E8898-07BC-4438-95E4-EF16B2BCE943} 23 | Win32Proj 24 | VCEnhancedKeyClear 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | 92 | 93 | Windows 94 | true 95 | RequireAdministrator 96 | 97 | 98 | 99 | 100 | 101 | 102 | Level3 103 | Disabled 104 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | 106 | 107 | Windows 108 | true 109 | RequireAdministrator 110 | 111 | 112 | 113 | 114 | Level3 115 | 116 | 117 | MaxSpeed 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | 122 | 123 | Windows 124 | true 125 | true 126 | true 127 | RequireAdministrator 128 | 129 | 130 | 131 | 132 | Level3 133 | 134 | 135 | MaxSpeed 136 | true 137 | true 138 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 139 | 140 | 141 | Windows 142 | true 143 | true 144 | true 145 | RequireAdministrator 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /VCEnhancedKeyClear/Installer.cpp: -------------------------------------------------------------------------------- 1 | #include "Installer.h" 2 | #include "defines.h" 3 | #include 4 | #include 5 | #include 6 | 7 | std::wstring CInstaller::GetTargetExecutable() 8 | { 9 | auto& TargetPath = GetTargetPath(true); 10 | 11 | if (TargetPath.empty()) 12 | { 13 | return L""; 14 | } 15 | 16 | return TargetPath + L"\\" VCEKC_EXENAME; 17 | } 18 | 19 | HRESULT CInstaller::GetTaskFolderAndService(void** ppTaskFolder, void** ppTaskService) 20 | { 21 | // https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/TaskSchd/time-trigger-example--c---.md 22 | HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 23 | 24 | if (FAILED(hr)) 25 | { 26 | return hr; 27 | } 28 | 29 | hr = CoInitializeSecurity( 30 | NULL, 31 | -1, 32 | NULL, 33 | NULL, 34 | RPC_C_AUTHN_LEVEL_PKT_PRIVACY, 35 | RPC_C_IMP_LEVEL_IMPERSONATE, 36 | NULL, 37 | 0, 38 | NULL); 39 | 40 | if (FAILED(hr)) 41 | { 42 | CoUninitialize(); 43 | return hr; 44 | } 45 | 46 | 47 | // ------------------------------------------------------ 48 | // Create an instance of the Task Service. 49 | ITaskService* pService = NULL; 50 | hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService); 51 | 52 | if (FAILED(hr)) 53 | { 54 | CoUninitialize(); 55 | return hr; 56 | } 57 | 58 | // Connect to the task service. 59 | hr = pService->Connect(VARIANT(), VARIANT(), VARIANT(), VARIANT()); 60 | 61 | if (FAILED(hr)) 62 | { 63 | pService->Release(); 64 | CoUninitialize(); 65 | return hr; 66 | } 67 | 68 | // ------------------------------------------------------ 69 | // ------------------------------------------------------ 70 | // Get the pointer to the root task folder. This folder will hold the 71 | // new task that is registered. 72 | ITaskFolder* pRootFolder = NULL; 73 | hr = pService->GetFolder(L"\\", &pRootFolder); 74 | if (FAILED(hr)) 75 | { 76 | pService->Release(); 77 | CoUninitialize(); 78 | return hr; 79 | } 80 | 81 | *ppTaskFolder = pRootFolder; 82 | *ppTaskService = pService; 83 | 84 | return hr; 85 | } 86 | 87 | DWORD CInstaller::UninstallFiles() 88 | { 89 | if ((GetFileAttributesW(GetTargetPath().c_str()) & FILE_ATTRIBUTE_DIRECTORY) == 0) 90 | { 91 | return ERROR_PATH_NOT_FOUND; 92 | } 93 | 94 | auto TargetExecutable = GetTargetExecutable(); 95 | DWORD dwError = ERROR_SUCCESS; 96 | 97 | if (!DeleteFileW(TargetExecutable.c_str())) 98 | { 99 | dwError = GetLastError(); 100 | } 101 | 102 | auto& TargetDir = GetTargetPath(); 103 | 104 | if (!RemoveDirectoryW(TargetDir.c_str())) 105 | { 106 | dwError = GetLastError(); 107 | } 108 | 109 | return dwError; 110 | } 111 | 112 | DWORD CInstaller::UninstallTask() 113 | { 114 | ITaskFolder* pRootFolder = NULL; 115 | ITaskService* pService = NULL; 116 | HRESULT hr = GetTaskFolderAndService(reinterpret_cast(&pRootFolder), reinterpret_cast(&pService)); 117 | 118 | if (FAILED(hr)) 119 | { 120 | return HRESULT_CODE(hr); 121 | } 122 | 123 | hr = pRootFolder->DeleteTask(VCEKC_TASKNAME, 0); 124 | 125 | pRootFolder->Release(); 126 | pService->Release(); 127 | 128 | return HRESULT_CODE(hr); 129 | } 130 | 131 | std::wstring& CInstaller::GetTargetPath(bool Create /* = false */) 132 | { 133 | if (m_szTargetPath.empty()) 134 | { 135 | wchar_t TargetPath[MAX_PATH]{}; 136 | 137 | if (SHGetFolderPathAndSubDir(NULL, CSIDL_PROGRAM_FILES | (Create ? CSIDL_FLAG_CREATE : CSIDL_FLAG_DONT_VERIFY), NULL, SHGFP_TYPE_CURRENT, VCEKC_INSTALLPATH, TargetPath) == S_OK) 138 | { 139 | m_szTargetPath = TargetPath; 140 | } 141 | } 142 | 143 | return m_szTargetPath; 144 | } 145 | 146 | DWORD CInstaller::Install() 147 | { 148 | // Resolve target executable path 149 | auto TargetExecutable = GetTargetExecutable(); 150 | 151 | if (TargetExecutable.empty()) 152 | { 153 | return ERROR_PATH_NOT_FOUND; 154 | } 155 | 156 | // Copy current executable to target path 157 | if (!CopyFileExW(m_szExePath.c_str(), TargetExecutable.c_str(), nullptr, nullptr, nullptr, 0)) 158 | { 159 | return GetLastError(); 160 | } 161 | 162 | // Create scheduled task 163 | ITaskFolder* pRootFolder = NULL; 164 | ITaskService* pService = NULL; 165 | HRESULT hr = GetTaskFolderAndService(reinterpret_cast(&pRootFolder), reinterpret_cast(&pService)); 166 | 167 | if (FAILED(hr)) 168 | { 169 | return HRESULT_CODE(hr); 170 | } 171 | 172 | // If the same task exists, remove it. 173 | pRootFolder->DeleteTask(VCEKC_TASKNAME, 0); 174 | 175 | // Create the task definition object to create the task. 176 | ITaskDefinition* pTask = NULL; 177 | hr = pService->NewTask(0, &pTask); 178 | 179 | pService->Release(); // COM clean up. Pointer is no longer used. 180 | if (FAILED(hr)) 181 | { 182 | pRootFolder->Release(); 183 | CoUninitialize(); 184 | return HRESULT_CODE(hr); 185 | } 186 | 187 | // ------------------------------------------------------ 188 | // Get the registration info for setting the identification. 189 | IRegistrationInfo* pRegInfo = NULL; 190 | hr = pTask->get_RegistrationInfo(&pRegInfo); 191 | if (FAILED(hr)) 192 | { 193 | pRootFolder->Release(); 194 | pTask->Release(); 195 | CoUninitialize(); 196 | return HRESULT_CODE(hr); 197 | } 198 | 199 | hr = pRegInfo->put_Author(VCEKC_TASKNAME); 200 | pRegInfo->Release(); 201 | 202 | if (FAILED(hr)) 203 | { 204 | pRootFolder->Release(); 205 | pTask->Release(); 206 | CoUninitialize(); 207 | return HRESULT_CODE(hr); 208 | } 209 | 210 | // ------------------------------------------------------ 211 | // Create the principal for the task - these credentials 212 | // are overwritten with the credentials passed to RegisterTaskDefinition 213 | IPrincipal* pPrincipal = NULL; 214 | hr = pTask->get_Principal(&pPrincipal); 215 | if (FAILED(hr)) 216 | { 217 | pRootFolder->Release(); 218 | pTask->Release(); 219 | CoUninitialize(); 220 | return HRESULT_CODE(hr); 221 | } 222 | 223 | // Set up principal logon type to interactive logon 224 | hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); 225 | if (FAILED(hr)) 226 | { 227 | pPrincipal->Release(); 228 | pRootFolder->Release(); 229 | pTask->Release(); 230 | CoUninitialize(); 231 | return HRESULT_CODE(hr); 232 | } 233 | 234 | // Set up principal logon type to interactive logon 235 | hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST); 236 | pPrincipal->Release(); 237 | if (FAILED(hr)) 238 | { 239 | pRootFolder->Release(); 240 | pTask->Release(); 241 | CoUninitialize(); 242 | return HRESULT_CODE(hr); 243 | } 244 | 245 | // ------------------------------------------------------ 246 | // Create the settings for the task 247 | ITaskSettings* pSettings = NULL; 248 | hr = pTask->get_Settings(&pSettings); 249 | if (FAILED(hr)) 250 | { 251 | pRootFolder->Release(); 252 | pTask->Release(); 253 | CoUninitialize(); 254 | return HRESULT_CODE(hr); 255 | } 256 | 257 | // Set setting values for the task. 258 | hr = pSettings->put_StartWhenAvailable(VARIANT_TRUE); 259 | pSettings->Release(); 260 | if (FAILED(hr)) 261 | { 262 | pRootFolder->Release(); 263 | pTask->Release(); 264 | CoUninitialize(); 265 | return HRESULT_CODE(hr); 266 | } 267 | 268 | // Set the idle settings for the task. 269 | IIdleSettings* pIdleSettings = NULL; 270 | hr = pSettings->get_IdleSettings(&pIdleSettings); 271 | if (FAILED(hr)) 272 | { 273 | pRootFolder->Release(); 274 | pTask->Release(); 275 | CoUninitialize(); 276 | return HRESULT_CODE(hr); 277 | } 278 | 279 | hr = pIdleSettings->put_WaitTimeout(L"PT5M"); 280 | pIdleSettings->Release(); 281 | if (FAILED(hr)) 282 | { 283 | pRootFolder->Release(); 284 | pTask->Release(); 285 | CoUninitialize(); 286 | return HRESULT_CODE(hr); 287 | } 288 | 289 | 290 | // ------------------------------------------------------ 291 | // Get the trigger collection to insert the time trigger. 292 | ITriggerCollection* pTriggerCollection = NULL; 293 | hr = pTask->get_Triggers(&pTriggerCollection); 294 | if (FAILED(hr)) 295 | { 296 | pRootFolder->Release(); 297 | pTask->Release(); 298 | CoUninitialize(); 299 | return HRESULT_CODE(hr); 300 | } 301 | 302 | // Add the time trigger to the task. 303 | ITrigger* pTrigger = NULL; 304 | hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); 305 | pTriggerCollection->Release(); 306 | if (FAILED(hr)) 307 | { 308 | pRootFolder->Release(); 309 | pTask->Release(); 310 | CoUninitialize(); 311 | return HRESULT_CODE(hr); 312 | } 313 | 314 | ILogonTrigger* pLogonTrigger = NULL; 315 | hr = pTrigger->QueryInterface(IID_ILogonTrigger, (void**)&pLogonTrigger); 316 | pTrigger->Release(); 317 | 318 | if (FAILED(hr)) 319 | { 320 | pRootFolder->Release(); 321 | pTask->Release(); 322 | CoUninitialize(); 323 | return HRESULT_CODE(hr); 324 | } 325 | 326 | pLogonTrigger->put_Id(L"LogonTrigger"); 327 | pLogonTrigger->put_Enabled(VARIANT_TRUE); 328 | 329 | // ------------------------------------------------------ 330 | // Add an action to the task. This task will execute notepad.exe. 331 | IActionCollection* pActionCollection = NULL; 332 | 333 | // Get the task action collection pointer. 334 | hr = pTask->get_Actions(&pActionCollection); 335 | if (FAILED(hr)) 336 | { 337 | pRootFolder->Release(); 338 | pTask->Release(); 339 | CoUninitialize(); 340 | return HRESULT_CODE(hr); 341 | } 342 | 343 | // Create the action, specifying that it is an executable action. 344 | IAction* pAction = NULL; 345 | hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); 346 | pActionCollection->Release(); 347 | if (FAILED(hr)) 348 | { 349 | pRootFolder->Release(); 350 | pTask->Release(); 351 | CoUninitialize(); 352 | return HRESULT_CODE(hr); 353 | } 354 | 355 | IExecAction* pExecAction = NULL; 356 | // QI for the executable task pointer. 357 | hr = pAction->QueryInterface( 358 | IID_IExecAction, (void**)&pExecAction); 359 | pAction->Release(); 360 | if (FAILED(hr)) 361 | { 362 | pRootFolder->Release(); 363 | pTask->Release(); 364 | CoUninitialize(); 365 | return HRESULT_CODE(hr); 366 | } 367 | 368 | // Set the path of the executable to notepad.exe. 369 | hr = pExecAction->put_Path(BSTR(TargetExecutable.c_str())); 370 | pExecAction->put_Arguments(L"--autorun"); 371 | pExecAction->Release(); 372 | if (FAILED(hr)) 373 | { 374 | pRootFolder->Release(); 375 | pTask->Release(); 376 | CoUninitialize(); 377 | return HRESULT_CODE(hr); 378 | } 379 | 380 | // ------------------------------------------------------ 381 | // Save the task in the root folder. 382 | IRegisteredTask* pRegisteredTask = NULL; 383 | hr = pRootFolder->RegisterTaskDefinition( 384 | VCEKC_TASKNAME, 385 | pTask, 386 | TASK_CREATE_OR_UPDATE, 387 | VARIANT(), 388 | VARIANT(), 389 | TASK_LOGON_INTERACTIVE_TOKEN, 390 | VARIANT(), 391 | &pRegisteredTask); 392 | if (FAILED(hr)) 393 | { 394 | pRootFolder->Release(); 395 | pTask->Release(); 396 | CoUninitialize(); 397 | return HRESULT_CODE(hr); 398 | } 399 | 400 | // Run the task 401 | IRunningTask* pRunningTask = NULL; 402 | hr = pRegisteredTask->Run(VARIANT(), &pRunningTask); 403 | 404 | if (!FAILED(hr)) 405 | { 406 | pRunningTask->Release(); 407 | } 408 | 409 | // Clean up. 410 | pRootFolder->Release(); 411 | pTask->Release(); 412 | pRegisteredTask->Release(); 413 | CoUninitialize(); 414 | 415 | if (FAILED(hr)) 416 | return HRESULT_CODE(hr); 417 | 418 | return ERROR_SUCCESS; 419 | } 420 | 421 | DWORD CInstaller::Uninstall() 422 | { 423 | // Attempt to uninstall everything even if one step fails 424 | auto dwErr1 = UninstallFiles(); 425 | auto dwErr2 = UninstallTask(); 426 | 427 | if (dwErr1 != ERROR_SUCCESS) 428 | return dwErr1; 429 | 430 | return dwErr2; 431 | } 432 | 433 | CInstaller::CInstaller(const wchar_t* szExePath) : m_szExePath{ szExePath } 434 | { 435 | } 436 | --------------------------------------------------------------------------------