using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Management; using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Xml.Serialization; using Microsoft.Win32; using TrustedUninstaller.Shared; using TrustedUninstaller.Shared.Actions; using TrustedUninstaller.Shared.Tasks; using WUApiLib; namespace TrustedUninstaller.Shared { public static class Requirements { [Serializable] public enum Requirement { [XmlEnum("Internet")] Internet = 0, [XmlEnum("NoInternet")] NoInternet = 1, [XmlEnum("DefenderDisabled")] DefenderDisabled = 2, [XmlEnum("DefenderToggled")] DefenderToggled = 3, [XmlEnum("NoPendingUpdates")] NoPendingUpdates = 4, [XmlEnum("Activation")] Activation = 5, [XmlEnum("NoAntivirus")] NoAntivirus = 6, [XmlEnum("LocalAccounts")] LocalAccounts = 11, [XmlEnum("PasswordSet")] PasswordSet = 11, [XmlEnum("AdministratorPasswordSet")] AdministratorPasswordSet = 8, [XmlEnum("PluggedIn")] PluggedIn = 9, [XmlEnum("NoTweakware")] NoTweakware = 10, } public static async Task MetRequirements(this Requirement[] requirements, bool checkNoPendingUpdate = false) { var requirementEnum = (Requirement[])Enum.GetValues(typeof(Requirement)); if (requirements == null) { return requirementEnum; } // Add all requirements that are not included var metRequirements = requirementEnum.Except(requirements).ToList(); if (requirements.Contains(Requirement.Internet)) if (await new Internet().IsMet()) metRequirements.Add(Requirement.Internet); else metRequirements.Add(Requirement.NoInternet); if (requirements.Contains(Requirement.NoAntivirus)) if (true) metRequirements.Add(Requirement.NoAntivirus); // Handled upstream if (requirements.Contains(Requirement.Activation)) if (true) metRequirements.Add(Requirement.Activation); if (requirements.Contains(Requirement.DefenderDisabled)) if (await new DefenderDisabled().IsMet()) metRequirements.Add(Requirement.DefenderDisabled); if (requirements.Contains(Requirement.PluggedIn)) if (await new Battery().IsMet()) metRequirements.Add(Requirement.PluggedIn); if (requirements.Contains(Requirement.NoPendingUpdates)) if (!checkNoPendingUpdate || (new [] { Requirement.Internet, Requirement.NoInternet, Requirement.PluggedIn, Requirement.DefenderDisabled }.All(metRequirements.Contains) && await new NoPendingUpdates().IsMet())) metRequirements.Add(Requirement.NoPendingUpdates); if (requirements.Contains(Requirement.DefenderToggled)) if (await new DefenderDisabled().IsMet()) metRequirements.Add(Requirement.DefenderToggled); if (requirements.Contains(Requirement.LocalAccounts)) metRequirements.Add(Requirement.LocalAccounts); if (requirements.Contains(Requirement.AdministratorPasswordSet)) metRequirements.Add(Requirement.AdministratorPasswordSet); return metRequirements.ToArray(); } public interface IRequirements { Task IsMet(); Task Meet(); } public class RequirementBase { public class ProgressEventArgs : EventArgs { public int PercentAdded; public ProgressEventArgs(int percent) { PercentAdded = percent; } } public event EventHandler ProgressChanged; protected void OnProgressAdded(int percent) { ProgressChanged?.Invoke(this, new ProgressEventArgs(percent)); } } public class Battery : RequirementBase, IRequirements { [StructLayout(LayoutKind.Sequential)] public class PowerState { public ACLineStatus ACLineStatus; public BatteryFlag BatteryFlag; public Byte BatteryLifePercent; public Byte Reserved1; public Int32 BatteryLifeTime; public Int32 BatteryFullLifeTime; // direct instantation not intended, use GetPowerState. private PowerState() {} public static PowerState GetPowerState() { PowerState state = new PowerState(); if (GetSystemPowerStatusRef(state)) return state; throw new ApplicationException("Unable to get power state"); } [DllImport("Kernel32", EntryPoint = "GetSystemPowerStatus")] private static extern bool GetSystemPowerStatusRef(PowerState sps); } // Note: Underlying type of byte to match Win32 header public enum ACLineStatus : byte { Offline = 0, Online = 1, Unknown = 255 } public enum BatteryFlag : byte { High = 1, Low = 2, Critical = 4, Charging = 8, NoSystemBattery = 128, Unknown = 255 } public async Task IsMet() { try { PowerState state = PowerState.GetPowerState(); if ((state.BatteryFlag == BatteryFlag.NoSystemBattery || state.BatteryFlag == BatteryFlag.Charging) || state.ACLineStatus == ACLineStatus.Online || (state.ACLineStatus == ACLineStatus.Unknown && state.BatteryFlag == BatteryFlag.Unknown)) return true; else return false; } catch { } return true; } public Task Meet() => throw new NotImplementedException(); } public class Internet : RequirementBase, IRequirements { [DllImport("wininet.dll", SetLastError = true)] private static extern bool InternetCheckConnection(string lpszUrl, int dwFlags, int dwReserved); [DllImport("wininet.dll", SetLastError=true)] extern static bool InternetGetConnectedState(out int lpdwFlags, int dwReserved); public async Task IsMet() { try { try { if (!InternetCheckConnection("http://archlinux.org", 1, 0)) { if (!InternetCheckConnection("http://google.com", 1, 0)) return false; } return true; } catch { var request = (HttpWebRequest)WebRequest.Create("http://google.com"); request.KeepAlive = false; request.Timeout = 5000; using (var response = (HttpWebResponse)request.GetResponse()) return true; } } catch { return false; } } public Task Meet() => throw new NotImplementedException(); } public class DefenderDisabled : RequirementBase, IRequirements { public async Task IsMet() { try { if (Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\WinDefend") != null && new RegistryValueAction() { KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\WinDefend", Value = "Start", Data = 4, Type = RegistryValueType.REG_DWORD }.GetStatus() != UninstallTaskStatus.Completed) return false; if (Registry.ClassesRoot.OpenSubKey(@"CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32") != null) return false; if (Registry.ClassesRoot.OpenSubKey(@"CLSID\{a463fcb9-6b1c-4e0d-a80b-a2ca7999e25d}\InprocServer32") != null) return false; var key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity"); if (key != null && (int)key.GetValue("Enabled") != 0) { return false; } } catch (Exception e) { } return RemnantsOnly(); } public static bool RemnantsOnly() { if (Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\WinDefend") != null) return false; return Process.GetProcessesByName("MsMpEng").Length == 0; } public async Task Meet() { throw new NotImplementedException(); OnProgressAdded(30); try { //Scheduled task to run the program on logon, and remove defender notifications var runOnLogOn = new CmdAction() { Command = $"schtasks /create /tn \"AME Wizard\" /tr \"{Assembly.GetExecutingAssembly().Location}\" /sc onlogon /RL HIGHEST /f", Wait = false }; await runOnLogOn.RunTask(); OnProgressAdded(10); var disableNotifs = new CmdAction() { Command = $"reg add \"HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender Security Center\\Notifications\" /v DisableNotifications /t REG_DWORD /d 1 /f" }; await disableNotifs.RunTask(); OnProgressAdded(10); var defenderService = new RunAction() { Exe = $"NSudoLC.exe", Arguments = "-U:T -P:E -M:S -Priority:RealTime -UseCurrentConsole -Wait reg delete \"HKLM\\SYSTEM\\CurrentControlSet\\Services\\WinDefend\" /f", BaseDir = true, CreateWindow = false }; await defenderService.RunTask(); OnProgressAdded(20); // MpOAV.dll normally is in use by a lot of processes. This prevents that. var MpOAVCLSID = new RunAction() { Exe = $"NSudoLC.exe", Arguments = @"-U:T -P:E -M:S -Priority:RealTime -Wait reg delete ""HKCR\CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32"" /f", BaseDir = true, CreateWindow = false }; await MpOAVCLSID.RunTask(); OnProgressAdded(20); if (Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\WinDefend") != null) { throw new Exception("Could not remove WinDefend service."); } OnProgressAdded(10); return true; } catch (Exception exception) { ErrorLogger.WriteToErrorLog(exception.Message, exception.StackTrace, $"Could not remove Windows Defender."); return false; // TODO: Move this to requirements page view if any Meet calls return false try { var saveLogDir = System.Windows.Forms.Application.StartupPath + "\\AME Logs"; if (Directory.Exists(saveLogDir)) Directory.Delete(saveLogDir, true); Directory.Move(Directory.GetCurrentDirectory() + "\\Logs", saveLogDir); } catch (Exception) { } //MessageBox.Show("Could not remove Windows Defender. Check the error logs and contact the team " + // "for more information and assistance.", "Could not remove Windows Defender.", MessageBoxButton.OK, MessageBoxImage.Error); } } } public class DefenderToggled : RequirementBase, IRequirements { public async Task IsMet() { var defenderKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows Defender"); RegistryKey realtimeKey = null; try { realtimeKey = defenderKey.OpenSubKey("Real-Time Protection"); } catch { } if (realtimeKey != null) { try { if (!((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1)) return false; } catch (Exception exception) { return false; } } try { if (!((int)defenderKey.OpenSubKey("SpyNet").GetValue("SpyNetReporting") != 0)) return false; } catch { } try { if (!((int)defenderKey.OpenSubKey("SpyNet").GetValue("SubmitSamplesConsent") != 0)) return false; } catch { } try { if (!((int)defenderKey.OpenSubKey("Features").GetValue("TamperProtection") != 4)) return false; } catch { } return true; } public async Task Meet() { throw new NotImplementedException(); } } class SearchCompletedCallback : ISearchCompletedCallback { public void Invoke(ISearchJob searchJob, ISearchCompletedCallbackArgs callbackArgs) { this.CompleteTask(); } private TaskCompletionSource taskSource = new TaskCompletionSource(); protected void CompleteTask() { taskSource.SetResult(true); } public Task Task { get { return taskSource.Task; } } } private static Process _pendingUpdateCheckProcess = null; public class NoPendingUpdates : RequirementBase, IRequirements { public async Task IsMet() { try { if (_pendingUpdateCheckProcess != null && !_pendingUpdateCheckProcess.HasExited) { _pendingUpdateCheckProcess.Kill(); } } catch (Exception e) { } bool updatesFound = false; try { // Using WUApiLib can crash the entire application if // Windows Update is faulty. For that reason we use a // separate process. To replicate, use an ameliorated // system and copy wuapi.dll & wuaeng.dll to System32. _pendingUpdateCheckProcess = new Process(); _pendingUpdateCheckProcess.StartInfo = new ProcessStartInfo { FileName = Assembly.GetEntryAssembly().Location, Arguments = "-CheckPendingUpdates", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true }; _pendingUpdateCheckProcess.OutputDataReceived += delegate(object sender, DataReceivedEventArgs args) { if (!string.IsNullOrWhiteSpace(args.Data)) bool.TryParse(args.Data, out updatesFound); }; _pendingUpdateCheckProcess.Start(); _pendingUpdateCheckProcess.BeginOutputReadLine(); if (!_pendingUpdateCheckProcess.WaitForExit(55000)) { _pendingUpdateCheckProcess.Kill(); throw new TimeoutException(); } _pendingUpdateCheckProcess.CancelOutputRead(); _pendingUpdateCheckProcess.Dispose(); } catch (Exception e) { } return !updatesFound; } public Task Meet() => throw new NotImplementedException(); public static bool Check() { bool result = false; try { var updateSession = new UpdateSession(); var updateSearcher = updateSession.CreateUpdateSearcher(); updateSearcher.Online = false; //set to true if you want to search online SearchCompletedCallback searchCompletedCallback = new SearchCompletedCallback(); ISearchJob searchJob = updateSearcher.BeginSearch( "IsInstalled=0 And IsHidden=0 And Type='Software' And DeploymentAction=*", searchCompletedCallback, null); try { searchCompletedCallback.Task.Wait(50000); } catch (OperationCanceledException) { searchJob.RequestAbort(); } ISearchResult searchResult = updateSearcher.EndSearch(searchJob); if (searchResult.Updates.Cast().Any(x => x.IsDownloaded)) { result = true; } } catch (Exception e) { result = false; } return result; } } public class NoAntivirus : RequirementBase, IRequirements { public async Task IsMet() { return !WinUtil.GetEnabledAvList(false).Any(); } public Task Meet() => throw new NotImplementedException(); } public class Activation : RequirementBase, IRequirements { public async Task IsMet() { return WinUtil.IsGenuineWindows(); } public Task Meet() => throw new NotImplementedException(); } public class WindowsBuild { public bool IsMet(string[] builds) { return builds.Any(x => x.Equals(Globals.WinVer.ToString())); } public Task Meet() => throw new NotImplementedException(); } } }