6 Commits

Author SHA1 Message Date
  Styris 63739db83a Update to v0.7.4 5 months ago
  Styris ddfdcccc04 Update to v0.7.3 5 months ago
  Styris 4e275d776c Update to v0.7.2 6 months ago
  Styris 7147425b5d Update to v0.7.1 8 months ago
  Styris 99ef971638 Update registry key 8 months ago
  Styris 32af7e5629 Update to v0.7 8 months ago
40 changed files with 9759 additions and 652 deletions
Split View
  1. +0
    -2
      README.md
  2. +0
    -26
      TrustedUninstaller.CLI/App.config
  3. +219
    -48
      TrustedUninstaller.CLI/CLI.cs
  4. BIN
      TrustedUninstaller.CLI/Properties/resources/CLI-Resources.7z
  5. BIN
      TrustedUninstaller.CLI/Properties/resources/ProcessInformer.7z
  6. +29
    -25
      TrustedUninstaller.CLI/TrustedUninstaller.CLI.csproj
  7. +17
    -5
      TrustedUninstaller.Shared/Actions/AppxAction.cs
  8. +172
    -17
      TrustedUninstaller.Shared/Actions/CmdAction.cs
  9. +124
    -47
      TrustedUninstaller.Shared/Actions/FileAction.cs
  10. +4
    -2
      TrustedUninstaller.Shared/Actions/LanguageAction.cs
  11. +2
    -1
      TrustedUninstaller.Shared/Actions/LineInFileAction.cs
  12. +181
    -17
      TrustedUninstaller.Shared/Actions/PowershellAction.cs
  13. +55
    -3
      TrustedUninstaller.Shared/Actions/RegistryKeyAction.cs
  14. +2
    -1
      TrustedUninstaller.Shared/Actions/RegistryValueAction.cs
  15. +218
    -38
      TrustedUninstaller.Shared/Actions/RunAction.cs
  16. +2
    -1
      TrustedUninstaller.Shared/Actions/ScheduledTaskAction.cs
  17. +230
    -79
      TrustedUninstaller.Shared/Actions/ServiceAction.cs
  18. +2
    -1
      TrustedUninstaller.Shared/Actions/ShortcutAction.cs
  19. +6
    -2
      TrustedUninstaller.Shared/Actions/SystemPackageAction.cs
  20. +288
    -116
      TrustedUninstaller.Shared/Actions/TaskKillAction.cs
  21. +2
    -1
      TrustedUninstaller.Shared/Actions/UpdateAction.cs
  22. +2
    -1
      TrustedUninstaller.Shared/Actions/UserAction.cs
  23. +2
    -1
      TrustedUninstaller.Shared/Actions/WriteStatusAction.cs
  24. +190
    -69
      TrustedUninstaller.Shared/AmeliorationUtil.cs
  25. +3340
    -0
      TrustedUninstaller.Shared/AugmentedProcess.cs
  26. +22
    -0
      TrustedUninstaller.Shared/Debug.cs
  27. +1638
    -0
      TrustedUninstaller.Shared/Defender.cs
  28. +21
    -6
      TrustedUninstaller.Shared/Globals.cs
  29. +351
    -2
      TrustedUninstaller.Shared/Playbook.cs
  30. +506
    -0
      TrustedUninstaller.Shared/ProcessPrivilege.cs
  31. +1
    -0
      TrustedUninstaller.Shared/ProviderStatus.cs
  32. +163
    -17
      TrustedUninstaller.Shared/Requirements.cs
  33. +1
    -0
      TrustedUninstaller.Shared/Tasks/ITaskAction.cs
  34. +22
    -0
      TrustedUninstaller.Shared/Tasks/TaskAction.cs
  35. +18
    -1
      TrustedUninstaller.Shared/Tasks/UninstallTask.cs
  36. +49
    -12
      TrustedUninstaller.Shared/TrustedUninstaller.Shared.csproj
  37. +1721
    -0
      TrustedUninstaller.Shared/Win32.cs
  38. +159
    -111
      TrustedUninstaller.Shared/WinUtil.cs
  39. BIN
      Windows.winmd
  40. BIN
      ameliorated_logo.png

+ 0
- 2
README.md View File

@ -18,8 +18,6 @@ Coming soon.
4. Build TrustedUninstaller.CLI
If you run into reference issues with the Windows namespace, add `Windows.winmd` as a reference.
## License
This tool has an [MIT license](https://en.wikipedia.org/wiki/MIT_License), which waives any requirements or rules governing the source code’s use, removing politics from the equation.


+ 0
- 26
TrustedUninstaller.CLI/App.config View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SQLitePCLRaw.core" publicKeyToken="1488e028ca7ab535" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.7.1395" newVersion="2.0.7.1395" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

+ 219
- 48
TrustedUninstaller.CLI/CLI.cs View File

@ -5,11 +5,13 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using TrustedUninstaller.Shared;
using TrustedUninstaller.Shared.Actions;
using TrustedUninstaller.Shared.Tasks;
namespace TrustedUninstaller.CLI
{
@ -21,6 +23,11 @@ namespace TrustedUninstaller.CLI
//After the auto start up.
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
if (args.Length == 1 && args[0] == "-DisableDefender")
{
return DisableDefender();
}
DualOut.Init();
if (!WinUtil.IsAdministrator())
@ -40,12 +47,11 @@ namespace TrustedUninstaller.CLI
if (args.Length < 1 || !Directory.Exists(args[0]))
{
Console.WriteLine("No Playbook selected: Use the GUI to select a playbook to run.");
Console.WriteLine("No Playbook selected.");
return -1;
}
AmeliorationUtil.Playbook = await AmeliorationUtil.DeserializePlaybook(args[0]);
AmeliorationUtil.Playbook.Path = args[0];
if (!Directory.Exists($"{AmeliorationUtil.Playbook.Path}\\Configuration") || Directory.GetFiles($"{AmeliorationUtil.Playbook.Path}\\Configuration").Length == 0)
{
@ -53,7 +59,10 @@ namespace TrustedUninstaller.CLI
Console.WriteLine($"Current directory: {Directory.GetCurrentDirectory()}");
return -1;
}
ExtractResourceFolder("resources", Directory.GetCurrentDirectory());
if (!WinUtil.IsTrustedInstaller())
{
Console.WriteLine("Checking requirements...\r\n");
@ -61,7 +70,7 @@ namespace TrustedUninstaller.CLI
{
Console.WriteLine("Internet must be connected to run this Playbook.");
}
if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.DefenderDisabled) && Process.GetProcessesByName("MsMpEng").Any())
{
bool first = true;
@ -71,33 +80,91 @@ namespace TrustedUninstaller.CLI
Console.WriteLine("All 4 windows security toggles must be set to off.\r\nNavigate to Windows Security > Virus & threat detection > manage settings.\r\nPress any key to continue...");
Console.ReadKey();
}
Console.WriteLine("The system must be prepared before continuing Your system will restart after preparation\r\nPress any key to continue...");
bool remnantsOnly = Requirements.DefenderDisabled.RemnantsOnly();
Console.WriteLine(remnantsOnly ? "The system must be prepared before continuing.\r\nPress any key to continue..." : "The system must be prepared before continuing. Your system will restart after preparation\r\nPress any key to continue...");
Console.ReadKey();
try
{
WinUtil.PrepareSystemCLI();
CmdAction reboot = new CmdAction()
Console.WriteLine("\r\nPreparing system...");
PrepareSystemCLI();
Console.WriteLine("Preparation Complete");
if (!remnantsOnly)
{
Command = "timeout /t 1 & shutdown /r /t 0",
Wait = false
};
Console.WriteLine("\r\nRestarting system...");
CmdAction reboot = new CmdAction()
{
Command = "timeout /t 1 & shutdown /r /t 0",
Wait = false
};
AmeliorationUtil.SafeRunAction(reboot).Wait();
AmeliorationUtil.SafeRunAction(reboot).Wait();
Environment.Exit(0);
Environment.Exit(0);
}
} catch (Exception e)
{
Console.WriteLine("Error preparing system: " + e.Message);
Environment.Exit(-1);
}
}
if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.Internet) && !await (new Requirements.Internet()).IsMet())
{
Console.WriteLine("Internet must be connected to run this Playbook.");
}
}
if (!File.Exists($"{AmeliorationUtil.Playbook.Path}\\options.txt"))
{
List<string> defaultOptions = new List<string>();
foreach (var page in AmeliorationUtil.Playbook.FeaturePages)
{
if (page.DependsOn != null && !defaultOptions.Contains(page.DependsOn))
continue;
if (page.GetType() == typeof(Playbook.CheckboxPage))
{
foreach (var option in ((Playbook.CheckboxPage)page).Options.Where(x => ((Playbook.CheckboxPage.CheckboxOption)x).IsChecked))
{
defaultOptions.Add(option.Name);
}
}
if (page.GetType() == typeof(Playbook.RadioPage))
defaultOptions.Add(((Playbook.RadioPage)page).DefaultOption);
if (page.GetType() == typeof(Playbook.RadioImagePage))
defaultOptions.Add(((Playbook.RadioImagePage)page).DefaultOption);
}
AmeliorationUtil.Playbook.Options = defaultOptions;
}
if (!AmeliorationUtil.Playbook.UseKernelDriver.HasValue)
{
if (new RegistryValueAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity",
Value = "Enabled",
Data = 1,
}.GetStatus()
!= UninstallTaskStatus.Completed
&&
new RegistryValueAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Control\CI\Config",
Value = "VulnerableDriverBlocklistEnable",
Data = 0,
}.GetStatus()
== UninstallTaskStatus.Completed && (await GetDefenderToggles()).All(toggleOn => !toggleOn))
{
AmeliorationUtil.UseKernelDriver = true;
}
}
else
AmeliorationUtil.UseKernelDriver = AmeliorationUtil.Playbook.UseKernelDriver.Value;
try
{
@ -107,31 +174,34 @@ namespace TrustedUninstaller.CLI
ExtractResourceFolder("resources", Directory.GetCurrentDirectory());
ExtractArchive(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"), AppDomain.CurrentDomain.BaseDirectory);
if (AmeliorationUtil.UseKernelDriver) ExtractArchive(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ProcessInformer.7z"), AppDomain.CurrentDomain.BaseDirectory);
try
{
File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"));
File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ProcessInformer.7z"));
} catch (Exception e)
{
}
catch (Exception e) { }
}
}
catch (Exception e)
} catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message,
e.StackTrace, "Error extracting resources.");
Console.WriteLine($":AME-Fatal Error: Error extracting resources.");
return -1;
}
await AmeliorationUtil.StartAmelioration();
return 0;
}
public static void ExtractArchive(string file, string targetDir)
{
RunCommand($"x \"{file}\" -o\"{targetDir}\" -p\"wizard\" -y -aos");
}
private static void RunCommand(string command)
{
var proc = new Process();
@ -144,15 +214,15 @@ namespace TrustedUninstaller.CLI
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "7za.exe"),
RedirectStandardError = true,
};
proc.StartInfo = startInfo;
proc.Start();
StringBuilder errorOutput = new StringBuilder("");
proc.ErrorDataReceived += (sender, args) => { errorOutput.Append("\r\n" + args.Data); };
proc.BeginErrorReadLine();
proc.WaitForExit();
proc.CancelErrorRead();
@ -162,7 +232,8 @@ namespace TrustedUninstaller.CLI
if (proc.ExitCode > 1)
throw new ArgumentOutOfRangeException("Error running 7zip: " + errorOutput.ToString());
}
public static void ExtractResourceFolder(string resource, string dir, bool overwrite = false)
public static void ExtractResourceFolder(string resource, string dir, bool overwrite = false)
{
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
@ -179,7 +250,7 @@ namespace TrustedUninstaller.CLI
var file = dir + $"\\{obj.Substring($"TrustedUninstaller.CLI.Properties.{resource}.".Length).Replace("---", "\\")}";
if (file.EndsWith(".gitkeep")) continue;
var fileDir = Path.GetDirectoryName(file);
if (fileDir != null && !Directory.Exists(fileDir)) Directory.CreateDirectory(fileDir);
@ -189,8 +260,7 @@ namespace TrustedUninstaller.CLI
try
{
File.Delete(file);
}
catch (Exception e)
} catch (Exception e)
{
if (!Directory.Exists(Directory.GetCurrentDirectory() + "\\Logs"))
Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\Logs");
@ -200,6 +270,7 @@ namespace TrustedUninstaller.CLI
writer.WriteLine("\r\nDate/Time: " + DateTime.Now);
writer.WriteLine("============================================");
}
continue;
}
}
@ -227,8 +298,7 @@ namespace TrustedUninstaller.CLI
}
}
}
public static async Task<List<bool>> GetDefenderToggles()
{
var result = new List<bool>();
@ -245,32 +315,31 @@ namespace TrustedUninstaller.CLI
try
{
realtimePolicy = policiesKey.OpenSubKey("Real-Time Protection");
} catch (Exception e)
{
}
catch (Exception e) { }
if (realtimePolicy != null)
realtimeKey = realtimePolicy;
else
realtimeKey = defenderKey.OpenSubKey("Real-Time Protection");
}
catch
} catch
{
result.Add(false);
}
if (realtimeKey != null)
{
try
{
result.Add((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1);
}
catch (Exception exception)
} catch (Exception exception)
{
try
{
realtimeKey = defenderKey.OpenSubKey("Real-Time Protection");
result.Add((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1);
}
catch (Exception e)
} catch (Exception e)
{
result.Add(true);
}
@ -281,12 +350,13 @@ namespace TrustedUninstaller.CLI
{
RegistryKey spynetPolicy = null;
RegistryKey spynetKey = null;
try
{
spynetPolicy = policiesKey.OpenSubKey("SpyNet");
} catch (Exception e)
{
}
catch (Exception e) { }
if (spynetPolicy != null)
spynetKey = spynetPolicy;
@ -298,19 +368,18 @@ namespace TrustedUninstaller.CLI
try
{
reporting = (int)spynetKey.GetValue("SpyNetReporting");
}
catch (Exception e)
} catch (Exception e)
{
if (spynetPolicy != null)
{
reporting = (int)defenderKey.OpenSubKey("SpyNet").GetValue("SpyNetReporting");
}
}
try
{
consent = (int)spynetKey.GetValue("SubmitSamplesConsent");
}
catch (Exception e)
} catch (Exception e)
{
if (spynetPolicy != null)
{
@ -320,23 +389,125 @@ namespace TrustedUninstaller.CLI
result.Add(reporting != 0);
result.Add(consent != 0 && consent != 2 && consent != 4);
}
catch
} catch
{
result.Add(false);
result.Add(false);
}
try
{
int tamper = (int)defenderKey.OpenSubKey("Features").GetValue("TamperProtection");
result.Add(tamper != 4 && tamper != 0);
}
catch
} catch
{
result.Add(false);
}
});
return result;
}
}
}
private static int DisableDefender()
{
try
{
Defender.Disable();
}
catch (Exception ex)
{
ErrorLogger.WriteToErrorLog(ex.GetType() + ": " + ex.Message, ex.StackTrace,
$"First Defender disable failed from second process.");
Defender.Kill();
try
{
Defender.Disable();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.GetType() + ": " + e.Message, e.StackTrace,
$"Could not disable Windows Defender from second process.");
return 1;
}
}
return 0;
}
public static void PrepareSystemCLI()
{
try
{
if (!Defender.Kill())
{
ErrorLogger.WriteToErrorLog("Unknown reason", null, "Could not kill Defender");
try
{
var process = Defender.StartElevatedProcess(Assembly.GetExecutingAssembly().Location, $@"-DisableDefender");
var exitCode = Defender.WaitForProcessExit(process, 10000);
if (exitCode != 0)
throw new Exception("Exit code was nonzero.");
} catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.GetType() + ": " + e.Message, e.StackTrace, "First Defender disable failed");
Thread.Sleep(1000);
if (!Defender.Kill())
{
Thread.Sleep(3000);
Defender.Kill();
}
try
{
var process = Defender.StartElevatedProcess(Assembly.GetExecutingAssembly().Location, $@"-DisableDefender");
var exitCode = Defender.WaitForProcessExit(process, 10000);
if (exitCode != 0)
throw new Exception("Exit code was nonzero.");
} catch (Exception exception)
{
ErrorLogger.WriteToErrorLog(e.GetType() + ": " + e.Message, e.StackTrace, "Second Defender disable failed");
Defender.Disable();
}
}
}
else
{
try
{
var process = Defender.StartElevatedProcess(Assembly.GetExecutingAssembly().Location, $@"-DisableDefender");
var exitCode = Defender.WaitForProcessExit(process, 15000);
if (exitCode != 0)
throw new Exception("Exit code was nonzero.");
} catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.GetType() + ": " + e.Message, e.StackTrace, "First Defender disable failed");
Defender.Disable();
}
}
} catch
{
}
}
public static async Task UninstallDriver()
{
CmdAction cmdAction = new CmdAction();
try
{
Console.WriteLine("Removing driver...");
cmdAction.Command = Environment.Is64BitOperatingSystem
? $"ProcessHacker\\x64\\ProcessHacker.exe -s -uninstallkph"
: $"ProcessHacker\\x86\\ProcessHacker.exe -s -uninstallkph";
await cmdAction.RunTask();
} catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "ProcessHacker ran into an Error while uninstalling the driver.");
throw;
}
}
}
}

BIN
TrustedUninstaller.CLI/Properties/resources/CLI-Resources.7z View File


BIN
TrustedUninstaller.CLI/Properties/resources/ProcessInformer.7z View File


+ 29
- 25
TrustedUninstaller.CLI/TrustedUninstaller.CLI.csproj View File

@ -32,6 +32,9 @@
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>true</BootstrapperEnabled>
<AllowedReferenceRelatedFileExtensions>
*.xml
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
<PropertyGroup>
<PathMap>$([System.IO.Path]::GetFullPath('$(SolutionDir)'))=./</PathMap>
@ -40,7 +43,7 @@
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<DebugType>embedded</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
@ -60,6 +63,20 @@
<Prefer32Bit>true</Prefer32Bit>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Single File|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<Optimize>true</Optimize>
<DebugType>embedded</DebugType>
<DefineConstants>SINGLE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug Single File|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<Optimize>true</Optimize>
<DebugType>embedded</DebugType>
<DefineConstants>SINGLE;DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>B8F0A67800B779C5CEF49BEAB6E5247E373F9452</ManifestCertificateThumbprint>
</PropertyGroup>
@ -81,12 +98,19 @@
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' != 'Single File|x64' ">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Single File|x64' Or '$(Configuration)|$(Platform)' == 'Debug Single File|x64' ">
<PostBuildEvent>for /f "usebackq delims=" %%A in (`DIR /B /S /A:d "$(SolutionDir)" ^| FINDSTR /R /c:".*\\bin\\.*\\de$" /c:".*\\bin\\.*\\en$" /c:".*\\bin\\.*\\es$" /c:".*\\bin\\.*\\fr$" /c:".*\\bin\\.*\\it$" /c:".*\\bin\\.*\\ja$" /c:".*\\bin\\.*\\ko$" /c:".*\\bin\\.*\\ru$" /c:".*\\bin\\.*\\zh-Hans$" /c:".*\\bin\\.*\\zh-Hant$" /c:".*\\bin\\.*\\pl$" /c:".*\\bin\\.*\\zh-CN$"`) do (RMDIR /Q /S "%%A" &amp; cmd /c "exit /b 0")
PowerShell -NoP -C "Start-Process '$(SolutionDir)\TrustedUninstaller.GUI\gui-builder\ame-builder.exe' -ArgumentList 'CLI','""""x64\$(Configuration)""""' -NoNewWindow -Wait"
</PostBuildEvent>
<AllowedReferenceRelatedFileExtensions>
<!-- Prevent default XML files copied to output.-->
.allowedextension
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' != 'Single File|x64' And '$(Configuration)|$(Platform)' != 'Debug Single File|x64' ">
<PostBuildEvent>for /f "usebackq delims=" %%A in (`DIR /B /S /A:d "$(SolutionDir)" ^| FINDSTR /R /c:".*\\bin\\.*\\de$" /c:".*\\bin\\.*\\en$" /c:".*\\bin\\.*\\es$" /c:".*\\bin\\.*\\fr$" /c:".*\\bin\\.*\\it$" /c:".*\\bin\\.*\\ja$" /c:".*\\bin\\.*\\ko$" /c:".*\\bin\\.*\\ru$" /c:".*\\bin\\.*\\zh-Hans$" /c:".*\\bin\\.*\\zh-Hant$" /c:".*\\bin\\.*\\pl$" /c:".*\\bin\\.*\\zh-CN$"`) do (RMDIR /Q /S "%%A" &amp; cmd /c "exit /b 0")</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Build" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
@ -94,26 +118,12 @@
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Windows">
<HintPath>..\Windows.winmd</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CLI.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
@ -135,18 +145,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="6.0.0" />
<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="SQLitePCLRaw.core" Version="2.0.7" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.CodeDom" Version="6.0.0" />
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
@ -156,7 +160,7 @@
<EmbeddedResource Include="Properties\resources\CLI-Resources.7z" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\resources\NSudoLC.exe" />
<EmbeddedResource Include="Properties\resources\ProcessInformer.7z" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

+ 17
- 5
TrustedUninstaller.Shared/Actions/AppxAction.cs View File

@ -1,6 +1,8 @@
using System;
using System.Linq;
using System.Threading.Tasks;
//using Windows.ApplicationModel;
//using Windows.Management.Deployment;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
using YamlDotNet.Serialization;
@ -11,8 +13,11 @@ using System.Threading;
namespace TrustedUninstaller.Shared.Actions
{
internal class AppxAction : ITaskAction
// Integrate ame-assassin later
internal class AppxAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
public enum AppxOperation
{
Remove = 0,
@ -36,6 +41,9 @@ namespace TrustedUninstaller.Shared.Actions
[YamlMember(typeof(bool), Alias = "verboseOutput")]
public bool Verbose { get; set; } = false;
[YamlMember(typeof(bool), Alias = "unregister")]
public bool Unregister { get; set; } = false;
[YamlMember(typeof(string), Alias = "weight")]
public int ProgressWeight { get; set; } = 30;
public int GetProgressWeight() => ProgressWeight;
@ -66,14 +74,18 @@ namespace TrustedUninstaller.Shared.Actions
InProgress = true;
Console.WriteLine($"Removing APPX {Type.ToString().ToLower()} '{Name}'...");
WinUtil.CheckKph();
string verboseArg = Verbose ? " -Verbose" : "";
string unregisterArg = Unregister ? " -Verbose" : "";
string kernelDriverArg = AmeliorationUtil.UseKernelDriver ? " -UseKernelDriver" : "";
var psi = new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = $@"-{Type.ToString()} ""{Name}""" + verboseArg,
Arguments = $@"-{Type.ToString()} ""{Name}""" + verboseArg + unregisterArg + kernelDriverArg,
FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe",
RedirectStandardOutput = true,
RedirectStandardError = true
@ -95,7 +107,7 @@ namespace TrustedUninstaller.Shared.Actions
bool exited = proc.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && ExeRunning(proc))
while (!exited && ExeRunning("ame-assassin", proc.Id))
{
exited = proc.WaitForExit(30000);
}
@ -118,11 +130,11 @@ namespace TrustedUninstaller.Shared.Actions
if (!write.Equals("Complete!")) Console.WriteLine(write);
}
private static bool ExeRunning(Process process)
private static bool ExeRunning(string name, int id)
{
try
{
return Process.GetProcessesByName(process.ProcessName).Any(x => x.Id == process.Id);
return Process.GetProcessesByName(name).Any(x => x.Id == id);
}
catch (Exception)
{


+ 172
- 17
TrustedUninstaller.Shared/Actions/CmdAction.cs View File

@ -1,6 +1,9 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
@ -8,8 +11,30 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
public class CmdAction : ITaskAction
public class CmdAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread()
{
if (InProgress) throw new TaskInProgressException("Another Cmd action was called while one was in progress.");
InProgress = true;
var privilegeText = RunAs == Privilege.CurrentUser ? " as the current user" : RunAs == Privilege.CurrentUserElevated ? " as the current user elevated" : RunAs == Privilege.System ?
" as the system account" : "";
Console.WriteLine($"Running cmd command '{Command}'{privilegeText}...");
ExitCode = null;
if (RunAs == Privilege.TrustedInstaller)
RunAsProcess();
else
RunAsPrivilegedProcess();
InProgress = false;
}
[YamlMember(typeof(Privilege), Alias = "runas")]
public Privilege RunAs { get; set; } = Privilege.TrustedInstaller;
[YamlMember(typeof(string), Alias = "command")]
public string Command { get; set; }
@ -47,21 +72,20 @@ namespace TrustedUninstaller.Shared.Actions
return ExitCode == null ? UninstallTaskStatus.ToDo: UninstallTaskStatus.Completed;
}
public async Task<bool> RunTask()
public Task<bool> RunTask()
{
if (InProgress) throw new TaskInProgressException("Another Cmd action was called while one was in progress.");
InProgress = true;
Console.WriteLine($"Running cmd command '{Command}'...");
ExitCode = null;
return null;
}
private void RunAsProcess()
{
var process = new Process();
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
Arguments = "/C " + $"\"{Environment.ExpandEnvironmentVariables(this.Command)}\"",
Arguments = "/C " + $"\"{this.Command}\"",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
@ -82,12 +106,128 @@ namespace TrustedUninstaller.Shared.Actions
if (!Wait)
{
process.Dispose();
return true;
return;
}
var error = new StringBuilder();
process.OutputDataReceived += ProcOutputHandler;
process.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs args)
{
if (!String.IsNullOrEmpty(args.Data))
error.AppendLine(args.Data);
else
error.AppendLine();
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (Timeout != null)
{
var exited = process.WaitForExit(Timeout.Value);
if (!exited)
{
process.Kill();
throw new TimeoutException($"Command '{Command}' timeout exceeded.");
}
}
else
{
bool exited = process.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && CmdRunning(process.Id))
{
exited = process.WaitForExit(30000);
}
}
int exitCode = 0;
try
{
exitCode = process.ExitCode;
}
catch (Exception ex)
{
ErrorLogger.WriteToErrorLog("Error fetching process exit code. (1)", null, "CmdAction Error", Command);
}
if (exitCode != 0 && !Command.Contains("ProcessHacker\\x64\\ProcessHacker.exe"))
{
StandardError = error.ToString();
Console.WriteLine($"cmd instance exited with error code: {exitCode}");
if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error message: {StandardError}");
ErrorLogger.WriteToErrorLog("Cmd exited with a non-zero exit code: " + exitCode, null, "CmdAction Error", Command);
this.ExitCode = exitCode;
}
else
{
ExitCode = 0;
}
process.CancelOutputRead();
process.CancelErrorRead();
process.Dispose();
}
private static bool CmdRunning(int id)
{
try
{
return Process.GetProcessesByName("cmd").Any(x => x.Id == id);
}
catch (Exception)
{
return false;
}
}
private void RunAsPrivilegedProcess()
{
var process = new AugmentedProcess.Process();
var startInfo = new AugmentedProcess.ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
Arguments = "/C " + $"{this.Command}",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true
};
if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables";
if (!Wait)
{
startInfo.RedirectStandardError = false;
startInfo.RedirectStandardOutput = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = true;
}
process.StartInfo = startInfo;
ProcessPrivilege.StartPrivilegedTask(process, RunAs);
if (!Wait)
{
process.Dispose();
return;
}
var error = new StringBuilder();
process.OutputDataReceived += PrivilegedProcOutputHandler;
process.ErrorDataReceived += delegate(object sender, AugmentedProcess.DataReceivedEventArgs args)
{
if (!String.IsNullOrEmpty(args.Data))
error.AppendLine(args.Data);
else
error.AppendLine();
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (Timeout != null)
{
@ -104,7 +244,7 @@ namespace TrustedUninstaller.Shared.Actions
if (process.ExitCode != 0)
{
StandardError = process.StandardError.ReadToEnd();
StandardError = error.ToString();
Console.WriteLine($"cmd instance exited with error code: {process.ExitCode}");
if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error message: {StandardError}");
@ -118,14 +258,29 @@ namespace TrustedUninstaller.Shared.Actions
}
process.CancelOutputRead();
process.CancelErrorRead();
process.Dispose();
InProgress = false;
return true;
}
private void PrivilegedProcOutputHandler(object sendingProcess, AugmentedProcess.DataReceivedEventArgs outLine)
{
var outputString = outLine.Data;
private static void ProcOutputHandler(object sendingProcess,
DataReceivedEventArgs outLine)
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
if (outputString.Contains("\\AME"))
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
}
Console.WriteLine(outputString);
}
else
{
Console.WriteLine();
}
}
private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
var outputString = outLine.Data;


+ 124
- 47
TrustedUninstaller.Shared/Actions/FileAction.cs View File

@ -1,21 +1,27 @@
using System;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.ServiceProcess;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
public class FileAction : ITaskAction
public class FileAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "path")]
public string RawPath { get; set; }
@ -71,23 +77,49 @@ namespace TrustedUninstaller.Shared.Actions
return isFile || isDirectory ? UninstallTaskStatus.ToDo : UninstallTaskStatus.Completed;
}
[DllImport("Unlocker.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern bool EzUnlockFileW(string path);
private async Task DeleteFile(string file, bool log = false)
{
if (!TrustedInstaller)
{
try {await Task.Run(() => File.Delete(file));} catch {}
try { File.Delete(file);} catch (Exception e) { }
if (File.Exists(file))
{
try
{
var result = EzUnlockFileW(file);
Testing.WriteLine($"ExUnlock on ({file}) result: " + result);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog($"Error while unlocking file: " + e.Message, e.StackTrace,
$"FileAction Error", file);
}
try {await Task.Run(() => File.Delete(file));} catch (Exception e) {Testing.WriteLine(e, "DeleteFile > File.Delete(File)");}
CmdAction delAction = new CmdAction()
{
Command = $"del /q /f {file}"
Command = $"del /q /f \"{file}\""
};
await delAction.RunTask();
delAction.RunTaskOnMainThread();
}
}
else if (File.Exists("NSudoLC.exe"))
{
try
{
var result = EzUnlockFileW(file);
Testing.WriteLine($"ExUnlock on ({file}) result: " + result);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog($"Error while unlocking file: " + e.Message, e.StackTrace,
$"FileAction Error", file);
}
RunAction tiDelAction = new RunAction()
{
Exe = "NSudoLC.exe",
@ -96,7 +128,7 @@ namespace TrustedUninstaller.Shared.Actions
CreateWindow = false
};
await tiDelAction.RunTask();
tiDelAction.RunTaskOnMainThread();
if (tiDelAction.Output != null)
{
if (log) ErrorLogger.WriteToErrorLog(tiDelAction.Output, Environment.StackTrace,
@ -122,7 +154,7 @@ namespace TrustedUninstaller.Shared.Actions
{
Command = $"rmdir /Q /S \"{dir}\""
};
await deleteDirCmd.RunTask();
deleteDirCmd.RunTaskOnMainThread();
if (deleteDirCmd.StandardError != null)
{
@ -144,7 +176,7 @@ namespace TrustedUninstaller.Shared.Actions
CreateWindow = false
};
await tiDelAction.RunTask();
tiDelAction.RunTaskOnMainThread();
if (tiDelAction.Output != null)
{
@ -189,15 +221,28 @@ namespace TrustedUninstaller.Shared.Actions
var cmdAction = new CmdAction();
Console.WriteLine($"Removing driver service {driverService}...");
// TODO: Replace with win32
try
{
ServiceInstaller ServiceInstallerObj = new ServiceInstaller();
ServiceInstallerObj.Context = new InstallContext();
ServiceInstallerObj.ServiceName = driverService;
ServiceInstallerObj.Uninstall(null);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Service uninstall failed: " + e.Message, e.StackTrace, "FileAction Warning", RawPath);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction stop";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction delete" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction delete";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
}
catch (Exception servException)
{
@ -243,31 +288,38 @@ namespace TrustedUninstaller.Shared.Actions
{
try
{
using var search = new ManagementObjectSearcher($"select * from Win32_Service where ProcessId = '{svchost.Id}'");
foreach (ManagementObject queryObj in search.Get())
foreach (var serviceName in Win32.ServiceEx.GetServicesFromProcessId(svchost.Id))
{
var serviceName = (string)queryObj["Name"]; // Access service name
var serv = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName.Equals(serviceName));
if (serv == null) svcCount++;
else svcCount += serv.DependentServices.Length + 1;
svcCount++;
try
{
var serviceController = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName.Equals(serviceName));
if (serviceController != null)
svcCount += serviceController.DependentServices.Length;
}
catch (Exception e)
{
Console.WriteLine($"\r\nError: Could not get amount of dependent services for {serviceName}.\r\nException: " + e.Message);
}
}
} catch (Exception e)
{
Console.WriteLine($"\r\nError: Could not get amount of services locking file.\r\nException: " + e.Message);
}
}
if (svcCount > 8) Console.WriteLine("Amount of locking services exceeds 8, skipping...");
while (processes.Any() && delay <= 800 && svcCount <= 8)
while (processes.Any() && delay <= 800)
{
Console.WriteLine("Processes locking the file:");
foreach (var process in processes)
{
Console.WriteLine(process.ProcessName);
}
if (svcCount > 10)
{
Console.WriteLine("Amount of locking services exceeds 10, skipping...");
break;
}
foreach (var process in processes)
{
@ -297,7 +349,15 @@ namespace TrustedUninstaller.Shared.Actions
continue;
}
await taskKillAction.RunTask();
try
{
await taskKillAction.RunTask();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace,
$"FileAction Error: Could not kill process {taskKillAction.ProcessName}.");
}
}
// This gives any obstinant processes some time to unlock the file on their own.
@ -321,14 +381,13 @@ namespace TrustedUninstaller.Shared.Actions
if (delay >= 800)
ErrorLogger.WriteToErrorLog($"Could not kill locking processes for file '{file}'. Process termination loop exceeded max cycles (8).",
Environment.StackTrace, "FileAction Error");
await DeleteFile(file, true);
using (var writer = new StreamWriter("Logs\\FileChecklist.txt", true))
if (Path.GetExtension(file).Equals(".exe", StringComparison.OrdinalIgnoreCase))
{
writer.WriteLine($"File Path: {file}\r\nDeleted: {!File.Exists(file)}\r\n" +
$"======================");
await new TaskKillAction() { ProcessName = Path.GetFileNameWithoutExtension(file) }.RunTask();
}
await DeleteFile(file, true);
}
}
//Loop through any subdirectories
@ -388,7 +447,7 @@ namespace TrustedUninstaller.Shared.Actions
};
try
{
await permAction.RunTask();
permAction.RunTaskOnMainThread();
}
catch (Exception e)
{
@ -435,7 +494,7 @@ namespace TrustedUninstaller.Shared.Actions
}
}
}
else if (isFile)
if (isFile)
{
try
{
@ -455,7 +514,7 @@ namespace TrustedUninstaller.Shared.Actions
};
try
{
await permAction.RunTask();
permAction.RunTaskOnMainThread();
}
catch (Exception e)
{
@ -473,15 +532,30 @@ namespace TrustedUninstaller.Shared.Actions
var cmdAction = new CmdAction();
Console.WriteLine($"Removing driver service {driverService}...");
// TODO: Replace with win32
try
{
ServiceInstaller ServiceInstallerObj = new ServiceInstaller();
ServiceInstallerObj.Context = new InstallContext();
ServiceInstallerObj.ServiceName = driverService;
ServiceInstallerObj.Uninstall(null);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Service uninstall failed: " + e.Message, e.StackTrace, "FileAction Warning", RawPath);
}
WinUtil.CheckKph();
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction stop";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction delete" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {driverService} -caction delete";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
}
catch (Exception servException)
{
@ -527,16 +601,19 @@ namespace TrustedUninstaller.Shared.Actions
{
try
{
using var search = new ManagementObjectSearcher($"select * from Win32_Service where ProcessId = '{svchost.Id}'");
foreach (ManagementObject queryObj in search.Get())
foreach (var serviceName in Win32.ServiceEx.GetServicesFromProcessId(svchost.Id))
{
var serviceName = (string)queryObj["Name"]; // Access service name
var serv = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName.Equals(serviceName));
if (serv == null) svcCount++;
else svcCount += serv.DependentServices.Length + 1;
svcCount++;
try
{
var serviceController = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName.Equals(serviceName));
if (serviceController != null)
svcCount += serviceController.DependentServices.Length;
}
catch (Exception e)
{
Console.WriteLine($"\r\nError: Could not get amount of dependent services for {serviceName}.\r\nException: " + e.Message);
}
}
} catch (Exception e)
{
@ -614,6 +691,11 @@ namespace TrustedUninstaller.Shared.Actions
ErrorLogger.WriteToErrorLog($"Could not kill locking processes for file '{realPath}'. Process termination loop exceeded max cycles (8).",
Environment.StackTrace, "FileAction Error");
if (Path.GetExtension(realPath).Equals(".exe", StringComparison.OrdinalIgnoreCase))
{
await new TaskKillAction() { ProcessName = Path.GetFileNameWithoutExtension(realPath) }.RunTask();
}
await DeleteFile(realPath, true);
}
}
@ -622,11 +704,6 @@ namespace TrustedUninstaller.Shared.Actions
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace,
$"FileAction Error: Error while trying to delete {realPath}.");
}
using (var writer = new StreamWriter("Logs\\FileChecklist.txt", true))
{
writer.WriteLine($"File Path: {realPath}\r\nDeleted: {!File.Exists(realPath)}\r\n" +
$"======================");
}
}
else
{


+ 4
- 2
TrustedUninstaller.Shared/Actions/LanguageAction.cs View File

@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -6,8 +7,9 @@ using TrustedUninstaller.Shared.Tasks;
namespace TrustedUninstaller.Shared.Actions
{
class LanguageAction : ITaskAction
class LanguageAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
public int ProgressWeight { get; set; } = 1;
public int GetProgressWeight() => ProgressWeight;


+ 2
- 1
TrustedUninstaller.Shared/Actions/LineInFileAction.cs View File

@ -14,8 +14,9 @@ namespace TrustedUninstaller.Shared.Actions
Delete = 0,
Add = 1
}
internal class LineInFileAction : ITaskAction
internal class LineInFileAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(Alias = "path")]
public string RawPath { get; set; }


+ 181
- 17
TrustedUninstaller.Shared/Actions/PowershellAction.cs View File

@ -2,7 +2,6 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -13,8 +12,31 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
public class PowerShellAction : ITaskAction
public class PowerShellAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread()
{
if (InProgress) throw new TaskInProgressException("Another Powershell action was called while one was in progress.");
InProgress = true;
var privilegeText = RunAs == Privilege.CurrentUser ? " as the current user" : RunAs == Privilege.CurrentUserElevated ? " as the current user elevated" : RunAs == Privilege.System ?
" as the system account" : "";
Console.WriteLine($"Running PowerShel command '{Command}'{privilegeText}...");
WinUtil.CheckKph();
if (RunAs == Privilege.TrustedInstaller)
RunAsProcess();
else
RunAsPrivilegedProcess();
InProgress = false;
return;
}
[YamlMember(typeof(Privilege), Alias = "runas")]
public Privilege RunAs { get; set; } = Privilege.TrustedInstaller;
[YamlMember(typeof(string), Alias = "command")]
public string Command { get; set; }
@ -51,13 +73,13 @@ namespace TrustedUninstaller.Shared.Actions
return ExitCode == null ? UninstallTaskStatus.ToDo: UninstallTaskStatus.Completed;
}
public async Task<bool> RunTask()
public Task<bool> RunTask()
{
if (InProgress) throw new TaskInProgressException("Another Powershell action was called while one was in progress.");
InProgress = true;
Console.WriteLine($"Running PowerShell command '{Command}'...");
return null;
}
private void RunAsProcess()
{
var process = new Process();
var startInfo = new ProcessStartInfo
{
@ -69,7 +91,7 @@ namespace TrustedUninstaller.Shared.Actions
RedirectStandardOutput = true,
CreateNoWindow = true
};
if (ExeDir) startInfo.WorkingDirectory = Directory.GetCurrentDirectory() + "\\Executables";
if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables";
if (!Wait)
{
startInfo.RedirectStandardError = false;
@ -84,7 +106,7 @@ namespace TrustedUninstaller.Shared.Actions
if (!Wait)
{
process.Dispose();
return true;
return;
}
var error = new StringBuilder();
@ -99,6 +121,114 @@ namespace TrustedUninstaller.Shared.Actions
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (Timeout != null)
{
var exited = process.WaitForExit(Timeout.Value);
if (!exited)
{
process.Kill();
throw new TimeoutException($"Command '{Command}' timeout exceeded.");
}
}
else
{
bool exited = process.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && PowerShellRunning(process.Id))
{
exited = process.WaitForExit(30000);
}
}
StandardError = error.ToString();
int exitCode = 0;
try
{
exitCode = process.ExitCode;
}
catch (Exception ex)
{
ErrorLogger.WriteToErrorLog("Error fetching process exit code. (1)", null, "PowerShellAction Error", Command);
}
if (exitCode != 0)
{
Console.WriteLine($"PowerShell instance exited with error code: {exitCode}");
if (!String.IsNullOrWhiteSpace(StandardError)) Console.WriteLine($"Error message: {StandardError}");
ErrorLogger.WriteToErrorLog("PowerShell exited with a non-zero exit code: " + exitCode, null, "PowerShellAction Error", Command);
this.ExitCode = exitCode;
}
else
{
if (!String.IsNullOrWhiteSpace(StandardError)) Console.WriteLine($"Error output: {StandardError}");
ExitCode = 0;
}
process.CancelOutputRead();
process.CancelErrorRead();
process.Dispose();
}
private static bool PowerShellRunning(int id)
{
try
{
return Process.GetProcessesByName("powershell").Any(x => x.Id == id);
}
catch (Exception)
{
return false;
}
}
private void RunAsPrivilegedProcess()
{
var process = new AugmentedProcess.Process();
var startInfo = new AugmentedProcess.ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "PowerShell.exe",
Arguments = $@"-NoP -ExecutionPolicy Bypass -NonInteractive -C ""{Command}""",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true
};
if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables";
if (!Wait)
{
startInfo.RedirectStandardError = false;
startInfo.RedirectStandardOutput = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = true;
}
process.StartInfo = startInfo;
ProcessPrivilege.StartPrivilegedTask(process, RunAs);
if (!Wait)
{
process.Dispose();
return;
}
var error = new StringBuilder();
process.OutputDataReceived += PrivilegedProcOutputHandler;
process.ErrorDataReceived += delegate(object sender, AugmentedProcess.DataReceivedEventArgs args)
{
if (!String.IsNullOrEmpty(args.Data))
error.AppendLine(args.Data);
else
error.AppendLine();
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (Timeout != null)
{
var exited = process.WaitForExit(Timeout.Value);
@ -115,7 +245,7 @@ namespace TrustedUninstaller.Shared.Actions
if (process.ExitCode != 0)
{
Console.WriteLine($"PowerShell instance exited with error code: {process.ExitCode}");
if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error message: {StandardError}");
if (!String.IsNullOrWhiteSpace(StandardError)) Console.WriteLine($"Error message: {StandardError}");
ErrorLogger.WriteToErrorLog("PowerShell exited with a non-zero exit code: " + process.ExitCode, null, "PowerShellAction Error", Command);
@ -123,23 +253,57 @@ namespace TrustedUninstaller.Shared.Actions
}
else
{
if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error output: {StandardError}");
if (!String.IsNullOrWhiteSpace(StandardError)) Console.WriteLine($"Error output: {StandardError}");
ExitCode = 0;
}
process.CancelOutputRead();
process.CancelErrorRead();
process.Dispose();
InProgress = false;
return true;
}
private static bool ExeRunning(string exe, int id)
{
try
{
return Process.GetProcessesByName(Path.GetFileNameWithoutExtension(exe)).Any(x => x.Id == id);
}
catch (Exception)
{
return false;
}
}
private static void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
private void PrivilegedProcOutputHandler(object sendingProcess, AugmentedProcess.DataReceivedEventArgs outLine)
{
var outputString = outLine.Data;
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
Console.WriteLine(outLine.Data);
if (outputString.Contains("\\AME"))
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
}
Console.WriteLine(outputString);
}
else
{
Console.WriteLine();
}
}
private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
var outputString = outLine.Data;
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
if (outputString.Contains("\\AME"))
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
}
Console.WriteLine(outputString);
}
else
{


+ 55
- 3
TrustedUninstaller.Shared/Actions/RegistryKeyAction.cs View File

@ -4,8 +4,10 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
@ -19,8 +21,9 @@ namespace TrustedUninstaller.Shared.Actions
Delete = 0,
Add = 1
}
public class RegistryKeyAction : ITaskAction
public class RegistryKeyAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "path")]
public string KeyName { get; set; }
@ -34,6 +37,36 @@ namespace TrustedUninstaller.Shared.Actions
public int ProgressWeight { get; set; } = 1;
public int GetProgressWeight() => ProgressWeight;
static Dictionary<RegistryHive, UIntPtr> HiveKeys = new Dictionary<RegistryHive, UIntPtr> {
{ RegistryHive.ClassesRoot, new UIntPtr(0x80000000u) },
{ RegistryHive.CurrentConfig, new UIntPtr(0x80000005u) },
{ RegistryHive.CurrentUser, new UIntPtr(0x80000001u) },
{ RegistryHive.DynData, new UIntPtr(0x80000006u) },
{ RegistryHive.LocalMachine, new UIntPtr(0x80000002u) },
{ RegistryHive.PerformanceData, new UIntPtr(0x80000004u) },
{ RegistryHive.Users, new UIntPtr(0x80000003u) }
};
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult);
[DllImport("advapi32.dll", EntryPoint = "RegDeleteKeyEx", SetLastError = true)]
private static extern int RegDeleteKeyEx(
UIntPtr hKey,
string lpSubKey,
uint samDesired, // see Notes below
uint Reserved);
private static void DeleteKeyTreeWin32(string key, RegistryHive hive)
{
var openedKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default).OpenSubKey(key);
if (openedKey == null)
return;
openedKey.GetSubKeyNames().ToList().ForEach(subKey => DeleteKeyTreeWin32(key + "\\" + subKey, hive));
openedKey.Close();
RegDeleteKeyEx(HiveKeys[hive], key, 0x0100, 0);
}
private bool InProgress { get; set; }
public void ResetProgress() => InProgress = false;
@ -153,7 +186,7 @@ namespace TrustedUninstaller.Shared.Actions
public async Task<bool> RunTask()
{
Console.WriteLine($"{Operation.ToString().TrimEnd('e')}ing registry key '{KeyName}'...");
var roots = GetRoots();
foreach (var _root in roots)
@ -184,7 +217,26 @@ namespace TrustedUninstaller.Shared.Actions
}
if (Operation == RegistryKeyOperation.Delete)
{
root.DeleteSubKeyTree(subKey, false);
try
{
root.DeleteSubKeyTree(subKey, false);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.GetType() + ": " + e.Message,
e.StackTrace, "RegistryKeyAction Warning", root?.Name + "\\" + subKey);
var rootHive = root.Name.Split('\\').First() switch
{
"HKEY_CURRENT_USER" => RegistryHive.CurrentUser,
"HKEY_LOCAL_MACHINE" => RegistryHive.LocalMachine,
"HKEY_CLASSES_ROOT" => RegistryHive.ClassesRoot,
"HKEY_USERS" => RegistryHive.Users,
_ => throw new ArgumentException($"Unable to parse: " + root.Name.Split('\\').First())
};
DeleteKeyTreeWin32(root.Name.StartsWith("HKEY_USERS") ? root.Name.Split('\\')[1] + "\\" + subKey: subKey, rootHive);
}
}
}
catch (Exception e)


+ 2
- 1
TrustedUninstaller.Shared/Actions/RegistryValueAction.cs View File

@ -36,8 +36,9 @@ namespace TrustedUninstaller.Shared.Actions
REG_UNKNOWN = RegistryValueKind.Unknown
}
public class RegistryValueAction : ITaskAction
public class RegistryValueAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "path")]
public string KeyName { get; set; }


+ 218
- 38
TrustedUninstaller.Shared/Actions/RunAction.cs View File

@ -2,14 +2,62 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Documents;
using TrustedUninstaller.Shared.Tasks;
using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
public class RunAction : ITaskAction
public enum Privilege
{
TrustedInstaller,
System,
CurrentUserElevated,
CurrentUser,
}
public class RunAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread()
{
if (RawPath != null) RawPath = Environment.ExpandEnvironmentVariables(RawPath);
InProgress = true;
var privilegeText = RunAs == Privilege.CurrentUser ? " as the current user" : RunAs == Privilege.CurrentUserElevated ? " as the current user elevated" : RunAs == Privilege.System ?
" as the system account" : "";
if (Arguments == null) Console.WriteLine($"Running '{Exe + privilegeText}'...");
else Console.WriteLine($"Running '{Exe}' with arguments '{Arguments + privilegeText}'...");
WinUtil.CheckKph();
var currentDir = Directory.GetCurrentDirectory();
if (ExeDir) RawPath = AmeliorationUtil.Playbook.Path + "\\Executables";
if (BaseDir) RawPath = currentDir;
string file = null;
if (RawPath != null && File.Exists(Path.Combine(Environment.ExpandEnvironmentVariables(RawPath), Exe)))
file = Path.Combine(Environment.ExpandEnvironmentVariables(RawPath), Exe);
else if (ExistsInPath(Exe) || File.Exists(Environment.ExpandEnvironmentVariables(Exe)))
file = Environment.ExpandEnvironmentVariables(Exe);
if (file == null)
throw new FileNotFoundException($"Executable not found.");
if (RunAs == Privilege.TrustedInstaller)
RunAsProcess(file);
else
RunAsPrivilegedProcess(file);
InProgress = false;
return;
}
[YamlMember(typeof(Privilege), Alias = "runas")]
public Privilege RunAs { get; set; } = Privilege.TrustedInstaller;
[YamlMember(typeof(string), Alias = "path")]
public string RawPath { get; set; } = null;
@ -80,28 +128,13 @@ namespace TrustedUninstaller.Shared.Actions
return HasExited || !Wait ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
}
public async Task<bool> RunTask()
public Task<bool> RunTask()
{
if (RawPath != null) RawPath = Environment.ExpandEnvironmentVariables(RawPath);
InProgress = true;
if (Arguments == null) Console.WriteLine($"Running '{Exe}'...");
else Console.WriteLine($"Running '{Exe}' with arguments '{Arguments}'...");
var currentDir = Directory.GetCurrentDirectory();
if (ExeDir) RawPath = AmeliorationUtil.Playbook.Path + "\\Executables";
if (BaseDir) RawPath = currentDir;
string file = null;
if (RawPath != null && File.Exists(Path.Combine(RawPath, Exe)))
file = Path.Combine(RawPath, Exe);
else if (ExistsInPath(Exe) || File.Exists(Environment.ExpandEnvironmentVariables(Exe)))
file = Exe;
if (file == null)
throw new FileNotFoundException($"Executable not found.");
return null;
}
private void RunAsProcess(string file)
{
var startInfo = new ProcessStartInfo
{
CreateNoWindow = !this.CreateWindow,
@ -138,7 +171,7 @@ namespace TrustedUninstaller.Shared.Actions
if (!Wait)
{
exeProcess.Dispose();
return true;
return;
}
if (ShowOutput)
@ -165,15 +198,24 @@ namespace TrustedUninstaller.Shared.Actions
bool exited = exeProcess.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && ExeRunning(exeProcess))
while (!exited && ExeRunning(exeProcess.ProcessName, exeProcess.Id))
{
exited = exeProcess.WaitForExit(30000);
}
}
if (exeProcess.ExitCode != 0)
int exitCode = 0;
try
{
exitCode = exeProcess.ExitCode;
}
catch (Exception ex)
{
ErrorLogger.WriteToErrorLog("Error fetching process exit code. (1)", null, "RunAction Error", Exe + " " + Arguments);
}
if (exitCode != 0)
{
ErrorLogger.WriteToErrorLog("Process exited with a non-zero exit code: " + exeProcess.ExitCode, null, "RunAction Error", Exe + " " + Arguments);
ErrorLogger.WriteToErrorLog("Process exited with a non-zero exit code: " + exitCode, null, "RunAction Error", Exe + " " + Arguments);
}
HasExited = true;
@ -182,15 +224,120 @@ namespace TrustedUninstaller.Shared.Actions
exeProcess.CancelOutputRead();
if (ShowError)
exeProcess.CancelErrorRead();
exeProcess.Dispose();
}
private void RunAsPrivilegedProcess(string file)
{
var startInfo = new AugmentedProcess.ProcessStartInfo
{
CreateNoWindow = !this.CreateWindow,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Normal,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = file,
};
if (Arguments != null) startInfo.Arguments = Arguments;
InProgress = false;
return true;
if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables";
if (!Wait)
{
startInfo.RedirectStandardError = false;
startInfo.RedirectStandardOutput = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = true;
}
if (!ShowOutput)
startInfo.RedirectStandardOutput = false;
if (!ShowError)
startInfo.RedirectStandardError = false;
var exeProcess = new AugmentedProcess.Process
{
StartInfo = startInfo,
EnableRaisingEvents = true
};
ProcessPrivilege.StartPrivilegedTask(exeProcess, RunAs);
if (!Wait)
{
exeProcess.Dispose();
return;
}
if (ShowOutput)
exeProcess.OutputDataReceived += PrivilegedProcOutputHandler;
if (ShowError)
exeProcess.ErrorDataReceived += PrivilegedProcOutputHandler;
if (ShowOutput)
exeProcess.BeginOutputReadLine();
if (ShowError)
exeProcess.BeginErrorReadLine();
if (Timeout.HasValue)
{
var exited = exeProcess.WaitForExit(Timeout.Value);
if (!exited)
{
exeProcess.Kill();
throw new TimeoutException($"Executable run timeout exceeded.");
}
}
else
{
bool exited = exeProcess.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && ExeRunning(exeProcess.ProcessName, exeProcess.Id))
{
exited = exeProcess.WaitForExit(30000);
}
}
try
{
if (exeProcess.ExitCode != 0)
{
ErrorLogger.WriteToErrorLog("Process exited with a non-zero exit code: " + exeProcess.ExitCode, null, "RunAction Error", Exe + " " + Arguments);
}
}
catch (Exception ex)
{
ErrorLogger.WriteToErrorLog("Error fetching process exit code. (1)", null, "RunAction Error", Exe + " " + Arguments);
Thread.Sleep(500);
try
{
if (exeProcess.ExitCode != 0)
{
ErrorLogger.WriteToErrorLog("Process exited with a non-zero exit code: " + exeProcess.ExitCode, null, "RunAction Error", Exe + " " + Arguments);
}
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error fetching process exit code. (2)", null, "RunAction Error", Exe + " " + Arguments);
}
}
HasExited = true;
if (ShowOutput)
exeProcess.CancelOutputRead();
if (ShowError)
exeProcess.CancelErrorRead();
exeProcess.Dispose();
}
private static bool ExeRunning(Process process)
private static bool ExeRunning(string name, int id)
{
try
{
return Process.GetProcessesByName(process.ProcessName).Any(x => x.Id == process.Id);
return Process.GetProcessesByName(name).Any(x => x.Id == id);
}
catch (Exception)
{
@ -198,23 +345,56 @@ namespace TrustedUninstaller.Shared.Actions
}
}
private void PrivilegedProcOutputHandler(object sendingProcess, AugmentedProcess.DataReceivedEventArgs outLine)
{
try
{
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
var outputString = outLine.Data;
if (outputString.Contains("\\AME"))
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
}
Console.WriteLine(outputString);
Output += outputString + Environment.NewLine;
}
else
{
Console.WriteLine();
}
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error processing process output", e.StackTrace, "RunAction Error", Exe);
}
}
private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
try
{
var outputString = outLine.Data;
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
var outputString = outLine.Data;
if (outputString.Contains("\\AME"))
if (outputString.Contains("\\AME"))
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
}
Console.WriteLine(outputString);
Output += outputString + Environment.NewLine;
}
else
{
outputString = outputString.Substring(outputString.IndexOf('>') + 1);
Console.WriteLine();
}
Console.WriteLine(outputString);
Output += outputString + Environment.NewLine;
}
else
catch (Exception e)
{
Console.WriteLine();
ErrorLogger.WriteToErrorLog("Error processing process output", e.StackTrace, "RunAction Error", Exe);
}
}
}


+ 2
- 1
TrustedUninstaller.Shared/Actions/ScheduledTaskAction.cs View File

@ -19,8 +19,9 @@ namespace TrustedUninstaller.Shared.Actions
DeleteFolder = 3
}
internal class ScheduledTaskAction : ITaskAction
internal class ScheduledTaskAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(ScheduledTaskOperation), Alias = "operation")]
public ScheduledTaskOperation Operation { get; set; } = ScheduledTaskOperation.Delete;
[YamlMember(Alias = "data")]


+ 230
- 79
TrustedUninstaller.Shared/Actions/ServiceAction.cs View File

@ -1,5 +1,7 @@
#nullable enable
using System;
using System.Collections.Specialized;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -7,6 +9,7 @@ using System.Management;
using System.ServiceProcess;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
@ -14,7 +17,7 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
internal enum ServiceOperation
public enum ServiceOperation
{
Stop,
Continue,
@ -23,8 +26,9 @@ namespace TrustedUninstaller.Shared.Actions
Delete,
Change
}
internal class ServiceAction : ITaskAction
public class ServiceAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(ServiceOperation), Alias = "operation")]
public ServiceOperation Operation { get; set; } = ServiceOperation.Delete;
@ -94,7 +98,7 @@ namespace TrustedUninstaller.Shared.Actions
return (int)value == Startup.Value ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
}
ServiceController serviceController;
ServiceController? serviceController;
if (Device) serviceController = GetDevice();
else serviceController = GetService();
@ -129,12 +133,10 @@ namespace TrustedUninstaller.Shared.Actions
|| serviceController?.Status == ServiceControllerStatus.PausePending ?
UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo,
ServiceOperation.Delete =>
serviceController == null ?
serviceController == null || Win32.ServiceEx.IsPendingDeleteOrDeleted(serviceController.ServiceName) ?
UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo,
_ => throw new ArgumentOutOfRangeException("Argument out of Range", new ArgumentOutOfRangeException())
};
}
private readonly string[] RegexNoKill = { "DcomLaunch" };
@ -173,6 +175,9 @@ namespace TrustedUninstaller.Shared.Actions
{
Console.WriteLine($"No services found matching '{ServiceName}'.");
//ErrorLogger.WriteToErrorLog($"The service matching '{ServiceName}' does not exist.", Environment.StackTrace, "ServiceAction Error");
if (Operation == ServiceOperation.Start)
throw new ArgumentException("Service " + ServiceName + " not found.");
return false;
}
@ -180,61 +185,72 @@ namespace TrustedUninstaller.Shared.Actions
var cmdAction = new CmdAction();
if (Operation == ServiceOperation.Delete || Operation == ServiceOperation.Stop)
if ((Operation == ServiceOperation.Delete && DeleteStop) || Operation == ServiceOperation.Stop)
{
if (RegexNoKill.Any(regex => Regex.Match(ServiceName, regex, RegexOptions.IgnoreCase).Success))
{
Console.WriteLine($"Skipping {ServiceName}...");
return false;
}
foreach (ServiceController dependentService in service.DependentServices)
try
{
Console.WriteLine($"Killing dependent service {dependentService.ServiceName}...");
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {dependentService.ServiceName} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {dependentService.ServiceName} -caction stop";
await cmdAction.RunTask();
Console.WriteLine("Waiting for the service to stop...");
int delay = 100;
while (service.Status != ServiceControllerStatus.Stopped && delay <= 1000)
{
service.Refresh();
//Wait for the service to stop
Task.Delay(delay).Wait();
delay += 100;
}
if (delay >= 1000)
foreach (ServiceController dependentService in service.DependentServices.Where(x => x.Status != ServiceControllerStatus.Stopped))
{
Console.WriteLine("\r\nService stop timeout exceeded. Trying second method...");
Console.WriteLine($"Killing dependent service {dependentService.ServiceName}...");
if (dependentService.Status != ServiceControllerStatus.StopPending && dependentService.Status != ServiceControllerStatus.Stopped)
{
try
{
dependentService.Stop();
}
catch (Exception e)
{
dependentService.Refresh();
if (dependentService.Status != ServiceControllerStatus.Stopped && dependentService.Status != ServiceControllerStatus.StopPending)
ErrorLogger.WriteToErrorLog("Dependent service stop failed: " + e.Message, e.StackTrace, "ServiceAction Warning", dependentService.ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {dependentService.ServiceName} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {dependentService.ServiceName} -caction stop";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
}
Console.WriteLine("Waiting for the dependent service to stop...");
try
{
dependentService.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
dependentService.Refresh();
if (service.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog("Dependent service stop timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
try
{
using var search = new ManagementObjectSearcher($"SELECT * FROM Win32_Service WHERE Name='{service.ServiceName}'");
foreach (ManagementObject queryObj in search.Get())
var killServ = new TaskKillAction()
{
var serviceId = (UInt32)queryObj["ProcessId"]; // Access service name
var killServ = new TaskKillAction()
{
ProcessID = (int)serviceId
};
await killServ.RunTask();
}
ProcessID = Win32.ServiceEx.GetServiceProcessId(dependentService.ServiceName)
};
await killServ.RunTask();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog($"Could not kill dependent service {dependentService.ServiceName}.",
e.StackTrace, "ServiceAction Error");
dependentService.Refresh();
if (dependentService.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog($"Could not kill dependent service {dependentService.ServiceName}.",
e.StackTrace, "ServiceAction Error", ServiceName);
}
}
}
if (service.ServiceName == "SgrmAgent" && ((Operation == ServiceOperation.Delete && DeleteStop) || Operation == ServiceOperation.Stop))
catch (Exception e)
{
await new TaskKillAction() { ProcessName = "SgrmBroker" }.RunTask();
ErrorLogger.WriteToErrorLog($"Error killing dependent services: " + e.Message,
e.StackTrace, "ServiceAction Error", ServiceName);
}
}
@ -243,48 +259,49 @@ namespace TrustedUninstaller.Shared.Actions
if (DeleteStop && service.Status != ServiceControllerStatus.StopPending && service.Status != ServiceControllerStatus.Stopped)
{
try
{
service.Stop();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped && service.Status != ServiceControllerStatus.StopPending)
ErrorLogger.WriteToErrorLog("Service stop failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction stop" :
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction stop";
await cmdAction.RunTask();
}
Console.WriteLine("Waiting for the service to stop...");
int delay = 100;
while (DeleteStop && service.Status != ServiceControllerStatus.Stopped && delay <= 1500)
{
service.Refresh();
//Wait for the service to stop
await Task.Delay(delay);
delay += 100;
}
if (delay >= 1500)
{
Console.WriteLine("\r\nService stop timeout exceeded. Trying second method...");
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
Console.WriteLine("Waiting for the service to stop...");
try
{
using var search = new ManagementObjectSearcher($"SELECT * FROM Win32_Service WHERE Name='{service.ServiceName}'");
foreach (ManagementObject queryObj in search.Get())
service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog("Service stop timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
try
{
var killServ = new TaskKillAction()
{
var serviceId = (UInt32)queryObj["ProcessId"]; // Access service name
var killServ = new TaskKillAction()
{
ProcessID = (int)serviceId
};
await killServ.RunTask();
}
ProcessID = Win32.ServiceEx.GetServiceProcessId(service.ServiceName)
};
await killServ.RunTask();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog($"Could not kill service {service.ServiceName}.",
e.StackTrace, "ServiceAction Error");
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog($"Could not kill service {service.ServiceName}.", e.StackTrace, "ServiceAction Error");
}
}
if (RegistryDelete)
{
var action = new RegistryKeyAction()
@ -296,18 +313,152 @@ namespace TrustedUninstaller.Shared.Actions
}
else
{
try
{
ServiceInstaller ServiceInstallerObj = new ServiceInstaller();
ServiceInstallerObj.Context = new InstallContext();
ServiceInstallerObj.ServiceName = service.ServiceName;
ServiceInstallerObj.Uninstall(null);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Service uninstall failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction delete" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction delete";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
}
} else if (Operation == ServiceOperation.Start)
{
try
{
service.Start();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Running)
ErrorLogger.WriteToErrorLog("Service start failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction start" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction start";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
try
{
service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Running)
ErrorLogger.WriteToErrorLog("Service start timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
} else if (Operation == ServiceOperation.Stop)
{
try
{
service.Stop();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped && service.Status != ServiceControllerStatus.StopPending)
ErrorLogger.WriteToErrorLog("Service stop failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction stop" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction stop";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
Console.WriteLine("Waiting for the service to stop...");
try
{
service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog("Service stop timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
try
{
var killServ = new TaskKillAction()
{
ProcessID = Win32.ServiceEx.GetServiceProcessId(service.ServiceName)
};
await killServ.RunTask();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Stopped)
ErrorLogger.WriteToErrorLog($"Could not kill dependent service {service.ServiceName}.",
e.StackTrace, "ServiceAction Error");
}
} else if (Operation == ServiceOperation.Pause)
{
try
{
service.Pause();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Paused)
ErrorLogger.WriteToErrorLog("Service pause failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction pause" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction pause";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
try
{
service.WaitForStatus(ServiceControllerStatus.Paused, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Paused)
ErrorLogger.WriteToErrorLog("Service pause timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
}
else
else if (Operation == ServiceOperation.Continue)
{
try
{
service.Pause();
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Running)
ErrorLogger.WriteToErrorLog("Service continue failed: " + e.Message, e.StackTrace, "ServiceAction Warning", ServiceName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {ServiceName} -caction {Operation.ToString().ToLower()}" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {ServiceName} -caction {Operation.ToString().ToLower()}";
await cmdAction.RunTask();
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction continue" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype service -cobject {service.ServiceName} -caction continue";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
try
{
service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMilliseconds(5000));
}
catch (Exception e)
{
service.Refresh();
if (service.Status != ServiceControllerStatus.Running)
ErrorLogger.WriteToErrorLog("Service continue timeout exceeded.", e.StackTrace, "ServiceAction Warning", ServiceName);
}
}
service?.Dispose();


+ 2
- 1
TrustedUninstaller.Shared/Actions/ShortcutAction.cs View File

@ -8,8 +8,9 @@ using File = System.IO.File;
namespace TrustedUninstaller.Shared.Actions
{
class ShortcutAction : ITaskAction
class ShortcutAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "path")]
public string RawPath { get; set; }


+ 6
- 2
TrustedUninstaller.Shared/Actions/SystemPackageAction.cs View File

@ -11,8 +11,10 @@ using System.Threading;
namespace TrustedUninstaller.Shared.Actions
{
internal class SystemPackageAction : ITaskAction
// Integrate ame-assassin later
internal class SystemPackageAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
public enum Architecture
{
amd64 = 0,
@ -76,11 +78,13 @@ namespace TrustedUninstaller.Shared.Actions
}
}
string kernelDriverArg = AmeliorationUtil.UseKernelDriver ? " -UseKernelDriver" : "";
var psi = new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = $@"-SystemPackage ""{Name}"" -Arch {Arch.ToString()} -Language ""{Language}""" + excludeArgs + excludeDependsArgs,
Arguments = $@"-SystemPackage ""{Name}"" -Arch {Arch.ToString()} -Language ""{Language}""" + excludeArgs + excludeDependsArgs + kernelDriverArg,
FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe",
RedirectStandardOutput = true,
RedirectStandardError = true


+ 288
- 116
TrustedUninstaller.Shared/Actions/TaskKillAction.cs View File

@ -11,11 +11,24 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
class TaskKillAction : ITaskAction
class TaskKillAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess,
bool bInheritHandle, int dwProcessId);
public enum ProcessAccessFlags : uint
{
QueryLimitedInformation = 0x1000
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[YamlMember(typeof(string), Alias = "name")]
public string? ProcessName { get; set; }
@ -73,19 +86,39 @@ namespace TrustedUninstaller.Shared.Actions
return processToTerminate.Any() ? UninstallTaskStatus.ToDo : UninstallTaskStatus.Completed;
}
private IEnumerable<Process> GetProcess()
private List<Process> GetProcess()
{
if (ProcessName == null) return new List<Process>();
if (ProcessID.HasValue)
{
var list = new List<Process>();
try
{
var process = Process.GetProcessById(ProcessID.Value);
if (ProcessName == null || process.ProcessName.Equals(ProcessName, StringComparison.OrdinalIgnoreCase))
list.Add(process);
else
return list;
}
catch (Exception e)
{
return list;
}
}
if (ProcessName == null)
{
return new List<Process>();
}
if (ProcessName.EndsWith("*") && ProcessName.StartsWith("*")) return Process.GetProcesses()
.Where(process => process.ProcessName.IndexOf(ProcessName.Trim('*'), StringComparison.CurrentCultureIgnoreCase) >= 0);
if (ProcessName.EndsWith("*") && ProcessName.StartsWith("*")) return Process.GetProcesses().ToList()
.Where(process => process.ProcessName.IndexOf(ProcessName.Trim('*'), StringComparison.CurrentCultureIgnoreCase) >= 0).ToList();
if (ProcessName.EndsWith("*")) return Process.GetProcesses()
.Where(process => process.ProcessName.StartsWith(ProcessName.TrimEnd('*'), StringComparison.CurrentCultureIgnoreCase));
.Where(process => process.ProcessName.StartsWith(ProcessName.TrimEnd('*'), StringComparison.CurrentCultureIgnoreCase)).ToList();
if (ProcessName.StartsWith("*")) return Process.GetProcesses()
.Where(process => process.ProcessName.EndsWith(ProcessName.TrimStart('*'), StringComparison.CurrentCultureIgnoreCase));
.Where(process => process.ProcessName.EndsWith(ProcessName.TrimStart('*'), StringComparison.CurrentCultureIgnoreCase)).ToList();
return Process.GetProcessesByName(ProcessName);
}
return Process.GetProcessesByName(ProcessName).ToList();
}
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool IsProcessCritical(IntPtr hProcess, ref bool Critical);
@ -116,194 +149,333 @@ namespace TrustedUninstaller.Shared.Actions
if (ProcessName != null)
{
//If the service is svchost, we stop the service instead of killing it.
if (ProcessName.Contains("svchost"))
if (ProcessName.Equals("svchost", StringComparison.OrdinalIgnoreCase))
{
// bool serviceFound = false;
try
{
using var search = new ManagementObjectSearcher($"select * from Win32_Service where ProcessId = '{ProcessID}'");
foreach (ManagementObject queryObj in search.Get())
if (ProcessID.HasValue)
{
var serviceName = (string)queryObj["Name"]; // Access service name
var stopServ = new ServiceAction()
foreach (var serviceName in Win32.ServiceEx.GetServicesFromProcessId(ProcessID.Value))
{
ServiceName = serviceName,
Operation = ServiceOperation.Stop
try
{
var stopServ = new ServiceAction()
{
ServiceName = serviceName,
Operation = ServiceOperation.Stop
};
await stopServ.RunTask();
}
catch (Exception e)
{
Console.WriteLine($"Could not kill service " + serviceName + ": " + e.Message);
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Could not kill service " + serviceName + ": " + e.Message);
}
}
}
else
{
foreach (var process in GetProcess())
{
foreach (var serviceName in Win32.ServiceEx.GetServicesFromProcessId(process.Id))
{
try
{
var stopServ = new ServiceAction()
{
ServiceName = serviceName,
Operation = ServiceOperation.Stop
};
await stopServ.RunTask();
};
await stopServ.RunTask();
}
catch (Exception e)
{
Console.WriteLine($"Could not kill service " + serviceName + ": " + e.Message);
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Could not kill service " + serviceName + ": " + e.Message);
}
}
}
}
}
catch (NullReferenceException e)
{
Console.WriteLine($"A service with PID: {ProcessID} could not be found.");
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, $"Could not find service with PID {ProcessID}.");
Console.WriteLine($"A service with PID: {ProcessID.Value} could not be found.");
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, $"Could not find service with PID {ProcessID.Value}.");
}
/* foreach (var serv in servicesToDelete)
int i;
for (i = 0; i <= 6 && GetProcess().Any(); i++)
{
//The ID can only be associated with one of the services, there's no need to loop through
//them all if we already found the service.
if (serviceFound)
{
break;
}
try
{
using var search = new ManagementObjectSearcher($"select ProcessId from Win32_Service where Name = '{serv}'").Get();
var servID = (uint)search.OfType<ManagementObject>().FirstOrDefault()["ProcessID"];
if (servID == ProcessID)
{
serviceFound = true;
}
search.Dispose();
}
catch (Exception e)
{
var search = new ManagementObjectSearcher($"select Name from Win32_Service where ProcessID = '{ProcessID}'").Get();
var servName = search.OfType<ManagementObject>().FirstOrDefault()["Name"];
Console.WriteLine($"Could not find {servName} but PID {ProcessID} still exists.");
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, $"Exception Type: {e.GetType()}");
return false;
}
}*/
//None of the services listed, we shouldn't kill svchost.
/* if (!serviceFound)
await Task.Delay(100 * i);
}
if (i < 6)
{
var search = new ManagementObjectSearcher($"select Name from Win32_Service where ProcessID = '{ProcessID}'").Get();
var servName = search.OfType<ManagementObject>().FirstOrDefault()["Name"];
Console.WriteLine($"A critical system process \"{servName}\" with PID {ProcessID} caused the Wizard to fail.");
await WinUtil.UninstallDriver();
Environment.Exit(-1);
return false;
}*/
await Task.Delay(100);
InProgress = false;
return true;
InProgress = false;
return true;
}
}
if (PathContains != null && !ProcessID.HasValue)
{
var processes = GetProcess().ToList();
var processes = GetProcess();
if (processes.Count > 0) Console.WriteLine("Processes:");
foreach (var process in processes.Where(x => x.MainModule.FileName.Contains(PathContains)))
foreach (var process in processes.Where(x =>
{
try
{
return x.MainModule.FileName.Contains(PathContains);
}
catch (Exception e)
{
return false;
}
}))
{
Console.WriteLine(process.ProcessName + " - " + process.Id);
if (!RegexNotCritical.Any(x => Regex.Match(process.ProcessName, x, RegexOptions.IgnoreCase).Success)) {
if (!RegexNotCritical.Any(x => Regex.Match(process.ProcessName, x, RegexOptions.IgnoreCase).Success))
{
bool isCritical = false;
IsProcessCritical(process.Handle, ref isCritical);
IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, process.Id);
IsProcessCritical(hprocess, ref isCritical);
CloseHandle(hprocess);
if (isCritical)
{
Console.WriteLine($"{process.ProcessName} is a critical process, skipping...");
continue;
}
}
try
{
if (!TerminateProcess(process.Handle, 1))
ErrorLogger.WriteToErrorLog("TerminateProcess failed with error code: " + Marshal.GetLastWin32Error(), Environment.StackTrace, "TaskKill Error", ProcessName);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Could not open process handle: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
try
{
process.WaitForExit(1000);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error waiting for process exit: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
if (process.ProcessName == "explorer") continue;
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.Id} -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.Id} -caction terminate";
await cmdAction.RunTask();
if (AmeliorationUtil.UseKernelDriver && process.ProcessName != "explorer") cmdAction.RunTaskOnMainThread();
int i = 0;
while (i <= 15 && GetProcess().Any(x => x.Id == process.Id && x.ProcessName == process.ProcessName))
while (i <= 3 && GetProcess().Any(x => x.Id == process.Id && x.ProcessName == process.ProcessName))
{
await Task.Delay(300);
try
{
try
{
if (AmeliorationUtil.UseKernelDriver)
cmdAction.RunTaskOnMainThread();
else
TerminateProcess(process.Handle, 1);
}
catch (Exception e) { }
process.WaitForExit(500);
}
catch (Exception e) { }
await Task.Delay(100);
i++;
}
if (i >= 15) ErrorLogger.WriteToErrorLog($"Task kill timeout exceeded.", Environment.StackTrace, "TaskKillAction Error");
if (i >= 3) ErrorLogger.WriteToErrorLog($"Task kill timeout exceeded.", Environment.StackTrace, "TaskKillAction Error");
}
InProgress = false;
return true;
}
}
if (ProcessID.HasValue)
{
var process = Process.GetProcessById(ProcessID.Value);
if (ProcessName != null && ProcessName.Equals("explorer", StringComparison.OrdinalIgnoreCase))
{
try
{
var process = Process.GetProcessById(ProcessID.Value);
TerminateProcess(process.Handle, 1);
} catch (Exception)
try {
if (!TerminateProcess(process.Handle, 1))
ErrorLogger.WriteToErrorLog("TerminateProcess failed with error code: " + Marshal.GetLastWin32Error(), Environment.StackTrace, "TaskKill Error", ProcessName);
try
{
process.WaitForExit(1000);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error waiting for process exit: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
}
catch (Exception e)
{
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID} -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID} -caction terminate";
await cmdAction.RunTask();
ErrorLogger.WriteToErrorLog("Could not open process handle: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
}
else
{
var process = Process.GetProcessById(ProcessID.Value);
if (!RegexNotCritical.Any(x => Regex.Match(process.ProcessName, x, RegexOptions.IgnoreCase).Success))
{
bool isCritical = false;
IsProcessCritical(process.Handle, ref isCritical);
try
{
IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, process.Id);
IsProcessCritical(hprocess, ref isCritical);
CloseHandle(hprocess);
}
catch (InvalidOperationException e)
{
ErrorLogger.WriteToErrorLog("Could not check if process is critical.", e.StackTrace, "TaskKillAction Error", process.ProcessName);
return false;
}
if (isCritical)
{
Console.WriteLine($"{process.ProcessName} is a critical process, skipping...");
return false;
}
}
try
{
if (!TerminateProcess(process.Handle, 1))
ErrorLogger.WriteToErrorLog("TerminateProcess failed with error code: " + Marshal.GetLastWin32Error(), Environment.StackTrace, "TaskKill Error", ProcessName);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Could not open process handle: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
try
{
process.WaitForExit(1000);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error waiting for process exit: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID} -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID} -caction terminate";
await cmdAction.RunTask();
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID.Value} -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {ProcessID.Value} -caction terminate";
if (AmeliorationUtil.UseKernelDriver) cmdAction.RunTaskOnMainThread();
}
int i = 0;
while (i <= 3 && GetProcess().Any(x => x.Id == process.Id && x.ProcessName == process.ProcessName))
{
try
{
try
{
if (AmeliorationUtil.UseKernelDriver)
cmdAction.RunTaskOnMainThread();
else
TerminateProcess(process.Handle, 1);
}
catch (Exception e)
{
}
await Task.Delay(100);
process.WaitForExit(500);
}
catch (Exception e)
{
}
await Task.Delay(100);
i++;
}
if (i >= 3) ErrorLogger.WriteToErrorLog($"Task kill timeout exceeded.", Environment.StackTrace, "TaskKillAction Error");
}
else
{
var processes = GetProcess().ToList();
var processes = GetProcess();
if (processes.Count > 0) Console.WriteLine("Processes:");
foreach (var process in processes)
{
Console.WriteLine(process.ProcessName + " - " + process.Id);
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.ProcessName}.exe -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.ProcessName}.exe -caction terminate";
if (process.ProcessName == "explorer") TerminateProcess(process.Handle, 1);
else
if (!RegexNotCritical.Any(x => Regex.Match(process.ProcessName, x, RegexOptions.IgnoreCase).Success))
{
if (!RegexNotCritical.Any(x => Regex.Match(process.ProcessName, x, RegexOptions.IgnoreCase).Success))
bool isCritical = false;
try
{
bool isCritical = false;
IsProcessCritical(process.Handle, ref isCritical);
if (isCritical)
{
Console.WriteLine($"{process.ProcessName} is a critical process, skipping...");
continue;
}
IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, process.Id);
IsProcessCritical(hprocess, ref isCritical);
CloseHandle(hprocess);
}
await cmdAction.RunTask();
catch (InvalidOperationException e)
{
ErrorLogger.WriteToErrorLog("Could not check if process is critical.", e.StackTrace, "TaskKillAction Error", process.ProcessName);
continue;
}
if (isCritical)
{
Console.WriteLine($"{process.ProcessName} is a critical process, skipping...");
continue;
}
}
try
{
if (!TerminateProcess(process.Handle, 1))
ErrorLogger.WriteToErrorLog("TerminateProcess failed with error code: " + Marshal.GetLastWin32Error(), Environment.StackTrace, "TaskKill Error", ProcessName);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Could not open process handle: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
try
{
process.WaitForExit(1000);
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog("Error waiting for process exit: " + e.Message, e.StackTrace, "TaskKillAction Error", process.ProcessName);
}
if (process.ProcessName == "explorer") continue;
cmdAction.Command = Environment.Is64BitOperatingSystem ?
$"ProcessHacker\\x64\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.Id} -caction terminate" :
$"ProcessHacker\\x86\\ProcessHacker.exe -s -elevate -c -ctype process -cobject {process.Id} -caction terminate";
if (AmeliorationUtil.UseKernelDriver && process.ProcessName != "explorer") cmdAction.RunTaskOnMainThread();
int i = 0;
while (i <= 15 && GetProcess().Any(x => x.Id == process.Id && x.ProcessName == process.ProcessName))
while (i <= 3 && GetProcess().Any(x => x.Id == process.Id && x.ProcessName == process.ProcessName))
{
await Task.Delay(300);
try
{
try
{
if (AmeliorationUtil.UseKernelDriver)
cmdAction.RunTaskOnMainThread();
else
TerminateProcess(process.Handle, 1);
}
catch (Exception e)
{
}
process.WaitForExit(500);
}
catch (Exception e)
{
}
await Task.Delay(100);
i++;
}
if (i >= 15) ErrorLogger.WriteToErrorLog($"Task kill timeout exceeded.", Environment.StackTrace, "TaskKillAction Error");
if (i >= 3) ErrorLogger.WriteToErrorLog($"Task kill timeout exceeded.", Environment.StackTrace, "TaskKillAction Error");
}
}


+ 2
- 1
TrustedUninstaller.Shared/Actions/UpdateAction.cs View File

@ -8,8 +8,9 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
internal class UpdateAction : ITaskAction
internal class UpdateAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "name")]
public string PackageName { get; set; }


+ 2
- 1
TrustedUninstaller.Shared/Actions/UserAction.cs View File

@ -8,8 +8,9 @@ using System.Security.Principal;
namespace TrustedUninstaller.Shared.Actions
{
public class UserAction : ITaskAction
public class UserAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "name")]
public string Username { get; set; } = "";
[YamlMember(typeof(bool), Alias = "admin")]


+ 2
- 1
TrustedUninstaller.Shared/Actions/WriteStatusAction.cs View File

@ -5,8 +5,9 @@ using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Actions
{
public class WriteStatusAction : ITaskAction
public class WriteStatusAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
[YamlMember(typeof(string), Alias = "status")]
public string Status { get; set; }
private bool InProgress { get; set; }


+ 190
- 69
TrustedUninstaller.Shared/AmeliorationUtil.cs View File

@ -1,6 +1,7 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
@ -11,6 +12,7 @@ using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Xml;
using System.Xml.Serialization;
using TrustedUninstaller.Shared.Actions;
@ -25,14 +27,33 @@ namespace TrustedUninstaller.Shared
private static readonly ConfigParser Parser = new ConfigParser();
private static readonly HttpClient Client = new HttpClient();
public static Playbook Playbook { set; get; }
public static Playbook Playbook { set; get; } = new Playbook();
public static bool UseKernelDriver = false;
public static readonly List<string> ErrorDisplayList = new List<string>();
public static int GetProgressMaximum()
public static int GetProgressMaximum(List<string> options)
{
return Parser.Tasks.Sum(task => task.Actions.Sum(action => action.GetProgressWeight()));
return Parser.Tasks.Sum(task => task.Actions.Sum(action =>
{
var taskAction = (TaskAction)action;
if ((!IsApplicableOption(taskAction.Option, options) || !IsApplicableArch(taskAction.Arch)) ||
(taskAction.Builds != null && (
!taskAction.Builds.Where(build => !build.StartsWith("!")).Any(build => IsApplicableWindowsVersion(build))
||
taskAction.Builds.Where(build => build.StartsWith("!")).Any(build => !IsApplicableWindowsVersion(build)))) ||
(taskAction.Options != null && (
!taskAction.Options.Where(option => !option.StartsWith("!")).Any(option => IsApplicableOption(option, Playbook.Options))
||
taskAction.Options.Where(option => option.StartsWith("!")).Any(option => !IsApplicableOption(option, Playbook.Options)))))
{
return 0;
}
return action.GetProgressWeight();
}));
}
public static bool AddTasks(string configPath, string file)
@ -48,16 +69,20 @@ namespace TrustedUninstaller.Shared
var currentTask = Parser.Tasks[Parser.Tasks.Count - 1];
if (File.Exists("TasksAdded.txt"))
if ((!IsApplicableOption(currentTask.Option, Playbook.Options) || !IsApplicableArch(currentTask.Arch)) ||
(currentTask.Builds != null && (
!currentTask.Builds.Where(build => !build.StartsWith("!")).Any(build => IsApplicableWindowsVersion(build))
||
currentTask.Builds.Where(build => build.StartsWith("!")).Any(build => !IsApplicableWindowsVersion(build)))) ||
(currentTask.Options != null && (
!currentTask.Options.Where(option => !option.StartsWith("!")).Any(option => IsApplicableOption(option, Playbook.Options))
||
currentTask.Options.Where(option => option.StartsWith("!")).Any(option => !IsApplicableOption(option, Playbook.Options)))))
{
var doneTasks = File.ReadAllText("TasksAdded.txt").Split(new[] { "\r\n" }, StringSplitOptions.None);
if (doneTasks.Contains(currentTask.Title))
{
Parser.Tasks.Remove(currentTask);
return true;
}
Parser.Tasks.Remove(currentTask);
return true;
}
//Get the features of the last added task (the task that was just added from the config file)
var features = currentTask.Features;
@ -89,16 +114,16 @@ namespace TrustedUninstaller.Shared
try
{
//If the privilege is admin and the program is running as TI, do not do the action.
if (privilege == UninstallTaskPrivilege.Admin && WinUtil.IsTrustedInstaller())
{
return 0;
}
//if (privilege == UninstallTaskPrivilege.Admin && WinUtil.IsTrustedInstaller())
//{
// return 0;
//}
if (privilege == UninstallTaskPrivilege.TrustedInstaller && !WinUtil.IsTrustedInstaller())
if (!WinUtil.IsTrustedInstaller())
{
Console.WriteLine("Relaunching as Trusted Installer!");
var mmf = MemoryMappedFile.CreateNew("ImgA", 5000000);
var mmf = MemoryMappedFile.CreateNew("ImgA", 30000000);
WinUtil.RelaunchAsTrustedInstaller();
if (NativeProcess.Process == null)
{
@ -185,6 +210,21 @@ namespace TrustedUninstaller.Shared
//Check the Actions folder inside the Shared folder for reference.
foreach (ITaskAction action in task.Actions)
{
var taskAction = (TaskAction)action;
if ((!IsApplicableOption(taskAction.Option, Playbook.Options) || !IsApplicableArch(taskAction.Arch)) ||
(taskAction.Builds != null && (
!taskAction.Builds.Where(build => !build.StartsWith("!")).Any(build => IsApplicableWindowsVersion(build))
||
taskAction.Builds.Where(build => build.StartsWith("!")).Any(build => !IsApplicableWindowsVersion(build)))) ||
(taskAction.Options != null && (
!taskAction.Options.Where(option => !option.StartsWith("!")).Any(option => IsApplicableOption(option, Playbook.Options))
||
taskAction.Options.Where(option => option.StartsWith("!")).Any(option => !IsApplicableOption(option, Playbook.Options)))))
{
continue;
}
int i = 0;
//var actionType = action.GetType().ToString().Replace("TrustedUninstaller.Shared.Actions.", "");
@ -197,7 +237,10 @@ namespace TrustedUninstaller.Shared
Console.WriteLine();
try
{
await action.RunTask();
var actionTask = action.RunTask();
if (actionTask == null)
action.RunTaskOnMainThread();
else await actionTask;
action.ResetProgress();
}
catch (Exception e)
@ -210,13 +253,14 @@ namespace TrustedUninstaller.Shared
else
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, action.ErrorString());
List<string> ExceptionBreakList = new List<string>() { "System.ArgumentException", "System.SecurityException", "System.UnauthorizedAccessException", "System.UnauthorizedAccessException", "System.TimeoutException" };
List<string> ExceptionBreakList = new List<string>() { "System.ArgumentException", "System.SecurityException", "System.UnauthorizedAccessException", "System.TimeoutException" };
if (ExceptionBreakList.Any(x => x.Equals(e.GetType().ToString())))
{
i = 10;
break;
}
}
Thread.Sleep(300);
}
Console.WriteLine($"Status: {action.GetStatus()}");
if (i > 0) Thread.Sleep(50);
@ -226,7 +270,8 @@ namespace TrustedUninstaller.Shared
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Critical error while running action.");
Console.WriteLine($":AME-ERROR: Critical error while running action: " + e.Message);
if (!((TaskAction)action).IgnoreErrors)
Console.WriteLine($":AME-ERROR: Critical error while running action: " + e.Message);
}
if (i == 10)
@ -235,7 +280,8 @@ namespace TrustedUninstaller.Shared
ErrorLogger.WriteToErrorLog(errorString, Environment.StackTrace, "Action failed to complete.");
// AmeliorationUtil.ErrorDisplayList.Add(errorString) would NOT work here since this
// might be a separate process, and thus has to be forwarded via the console
Console.WriteLine($":AME-ERROR: {errorString}");
if (!((TaskAction)action).IgnoreErrors)
Console.WriteLine($":AME-ERROR: {errorString}");
//Environment.Exit(-2);
Console.WriteLine($"Action completed. Weight:{action.GetProgressWeight()}");
continue;
@ -244,7 +290,7 @@ namespace TrustedUninstaller.Shared
}
Console.WriteLine("Task completed.");
File.AppendAllText("TasksAdded.txt", task.Title + Environment.NewLine);
ProcessPrivilege.ResetTokens();
}
catch (Exception e)
{
@ -260,12 +306,32 @@ namespace TrustedUninstaller.Shared
Playbook pb;
XmlSerializer serializer = new XmlSerializer(typeof(Playbook));
/*serializer.UnknownElement += delegate(object sender, XmlElementEventArgs args)
{
MessageBox.Show(args.Element.Name);
};
serializer.UnknownAttribute += delegate(object sender, XmlAttributeEventArgs args)
{
MessageBox.Show(args.Attr.Name);
};*/
using (XmlReader reader = XmlReader.Create($"{dir}\\playbook.conf"))
{
pb = (Playbook)serializer.Deserialize(reader);
}
pb.Path = dir;
var validateResult = pb.Validate();
if (validateResult != null)
throw new XmlException(validateResult);
if (File.Exists($"{dir}\\options.txt"))
{
pb.Options = new List<string>();
using (var reader = new StreamReader($"{dir}\\options.txt"))
{
while (!reader.EndOfStream)
pb.Options.Add(reader.ReadLine());
}
}
pb.Path = dir;
return Task.FromResult(pb);
}
@ -275,11 +341,6 @@ namespace TrustedUninstaller.Shared
//After the auto start up.
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
if (File.Exists("TasksAdded.txt") && !WinUtil.IsTrustedInstaller())
{
File.Delete("TasksAdded.txt");
}
if (Directory.Exists("Logs") && !WinUtil.IsTrustedInstaller())
{
if (File.Exists("Logs\\AdminOutput.txt"))
@ -291,11 +352,6 @@ namespace TrustedUninstaller.Shared
{
File.Delete("Logs\\TIOutput.txt");
}
if (File.Exists("Logs\\FileChecklist.txt"))
{
File.Delete("Logs\\FileChecklist.txt");
}
}
//Check if KPH is installed.
@ -335,17 +391,19 @@ namespace TrustedUninstaller.Shared
if (Parser.Tasks.Any(x => x.Priority != Parser.Tasks.First().Priority))
Parser.Tasks.Sort(new TaskComparer());
UninstallTaskPrivilege prevPriv = UninstallTaskPrivilege.Admin;
bool launched = false;
foreach (var task in Parser.Tasks.Where(task => task.Actions.Count != 0))
{
try
{
if (prevPriv == UninstallTaskPrivilege.TrustedInstaller && task.Privilege == UninstallTaskPrivilege.TrustedInstaller && !WinUtil.IsTrustedInstaller())
//if (prevPriv == UninstallTaskPrivilege.TrustedInstaller && task.Privilege == UninstallTaskPrivilege.TrustedInstaller && !WinUtil.IsTrustedInstaller())
if (!WinUtil.IsTrustedInstaller() && launched)
{
continue;
}
launched = true;
await DoActions(task, task.Privilege);
prevPriv = task.Privilege;
//prevPriv = task.Privilege;
}
catch (Exception ex)
{
@ -357,45 +415,19 @@ namespace TrustedUninstaller.Shared
WinUtil.RegistryManager.UnhookUserHives();
//Check how many files were successfully and unsuccessfully deleted.
var deletedItemsCount = 0;
var failedDeletedItemsCount = 0;
if (File.Exists("Logs\\FileChecklist.txt"))
{
using (var reader = new StreamReader("Logs\\FileChecklist.txt"))
{
var data = reader.ReadToEnd();
var listData = data.Split(new [] { Environment.NewLine }, StringSplitOptions.None).ToList();
deletedItemsCount = listData.FindAll(s => s == "Deleted: True").Count();
failedDeletedItemsCount = listData.FindAll(s => s == "Deleted: False").Count();
}
using (var writer = new StreamWriter("Logs\\FileChecklist.txt", true))
{
writer.WriteLine($"{deletedItemsCount} files were deleted successfully. " +
$"{failedDeletedItemsCount} files couldn't be deleted.");
}
}
Console.WriteLine($"{deletedItemsCount} files were deleted successfully. " +
$"{failedDeletedItemsCount} files couldn't be deleted.");
//Check if the kernel driver is installed.
//service = ServiceController.GetDevices()
//.FirstOrDefault(s => s.DisplayName == "KProcessHacker2");
if (true)
if (UseKernelDriver)
{
//Remove Process Hacker's kernel driver.
await WinUtil.UninstallDriver();
await AmeliorationUtil.SafeRunAction(new RegistryKeyAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2",
});
}
await AmeliorationUtil.SafeRunAction(new RegistryKeyAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2",
});
File.Delete("TasksAdded.txt");
Console.WriteLine();
Console.WriteLine("Playbook finished.");
@ -572,6 +604,95 @@ namespace TrustedUninstaller.Shared
}
}
}
private static bool IsApplicableWindowsVersion(string version)
{
bool negative = false;
if (version.StartsWith("!"))
{
version = version.TrimStart('!');
negative = true;
}
bool compareUpdateBuild = version.Contains(".");
var currentBuild = decimal.Parse(compareUpdateBuild ? Globals.WinVer + "." + Globals.WinUpdateVer : Globals.WinVer.ToString());
bool result = false;
if (version.StartsWith(">="))
{
var parsed = decimal.Parse(version.Substring(2));
if (currentBuild >= parsed)
result = true;
} else if (version.StartsWith("<="))
{
var parsed = decimal.Parse(version.Substring(2));
if (currentBuild <= parsed)
result = true;
} else if (version.StartsWith(">"))
{
var parsed = decimal.Parse(version.Substring(1));
if (currentBuild > parsed)
result = true;
} else if (version.StartsWith("<"))
{
var parsed = decimal.Parse(version.Substring(1));
if (currentBuild < parsed)
result = true;
}
else
{
var parsed = decimal.Parse(version);
if (currentBuild == parsed)
result = true;
}
return negative ? !result : result;
}
private static bool IsApplicableOption(string option, List<string> options)
{
if (String.IsNullOrEmpty(option))
return true;
if (option.Contains("&"))
{
if (option.Contains("!"))
throw new ArgumentException("YAML options item must not contain both & and !", "options");
return option.Split('&').All(splitOption => IsApplicableOption(splitOption, options));
}
bool negative = false;
if (option.StartsWith("!"))
{
option = option.TrimStart('!');
negative = true;
}
if (options == null)
return negative ? true : false;
var result = options.Contains(option, StringComparer.OrdinalIgnoreCase);
return negative ? !result : result;
}
private static bool IsApplicableArch(string arch)
{
if (String.IsNullOrEmpty(arch))
return true;
bool negative = false;
if (arch.StartsWith("!"))
{
arch = arch.TrimStart('!');
negative = true;
}
var result = String.Equals(arch, RuntimeInformation.ProcessArchitecture.ToString(), StringComparison.OrdinalIgnoreCase);
return negative ? !result : result;
}
public static async Task<bool> SafeRunAction(ITaskAction action)
{


+ 3340
- 0
TrustedUninstaller.Shared/AugmentedProcess.cs
File diff suppressed because it is too large
View File


+ 22
- 0
TrustedUninstaller.Shared/Debug.cs View File

@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace TrustedUninstaller.Shared
{
public static class Testing
{
[Conditional("DEBUG")]
public static void WriteLine(object text)
{
Console.WriteLine(text.ToString());
}
public static void WriteLine(Exception exception, string shortTrace)
{
Console.WriteLine(exception.GetType() + " at " + shortTrace + ":" + exception.Message);
}
public static void WriteLine(Exception exception, string shortTrace, string item)
{
Console.WriteLine(exception.GetType() + " at " + shortTrace + $" ({item}):" + exception.Message);
}
}
}

+ 1638
- 0
TrustedUninstaller.Shared/Defender.cs
File diff suppressed because it is too large
View File


+ 21
- 6
TrustedUninstaller.Shared/Globals.cs View File

@ -9,12 +9,27 @@ namespace TrustedUninstaller.Shared
{
public class Globals
{
public const string CurrentVersion = "0.6.5";
public const double CurrentVersionNumber = 0.65;
#if DEBUG
public static readonly int WinVer = 19045;
#else
public const string CurrentVersion = "0.7.4";
public const double CurrentVersionNumber = 0.74;
public static readonly int WinVer = Int32.Parse(Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuildNumber").ToString());
#endif
private static int _winUpdateVer = -1;
public static int WinUpdateVer
{
get
{
if (_winUpdateVer != -1)
return _winUpdateVer;
try
{
_winUpdateVer = (int)Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("UBR");
}
catch { _winUpdateVer = 0; }
return _winUpdateVer;
}
}
}
}

+ 351
- 2
TrustedUninstaller.Shared/Playbook.cs View File

@ -1,10 +1,22 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Policy;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using MessageBox = System.Windows.MessageBox;
namespace TrustedUninstaller.Shared
{
@ -18,25 +30,362 @@ namespace TrustedUninstaller.Shared
public string Username { get; set; }
public string Details { get; set; }
public string Version { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "CheckboxPage", Type = typeof(CheckboxPage))]
[XmlArrayItem(ElementName = "RadioPage", Type = typeof(RadioPage))]
[XmlArrayItem(ElementName = "RadioImagePage", Type = typeof(RadioImagePage))]
public FeaturePage[] FeaturePages { get; set; }
public string ProgressText { get; set; } = "Deploying the selected Playbook configuration onto the system.";
public int EstimatedMinutes { get; set; } = 25;
#nullable enable
public string[]? SupportedBuilds { get; set; }
public Requirements.Requirement[]? Requirements { get; set; }
public Requirements.Requirement[] Requirements { get; set; } = new Requirements.Requirement[] {};
public string? Git { get; set; }
public string? DonateLink { get; set; }
public string? Website { get; set; }
public string? ProductCode { get; set; }
public string? PasswordReplace { get; set; }
#nullable disable
public bool Overhaul { get; set; } = false;
public string Path { get; set; }
public bool? UseKernelDriver { get; set; } = null;
public List<string> Options { get; set; } = null;
public string Validate()
{
if (FeaturePages == null)
return null;
foreach (var rawPage in FeaturePages)
{
if (rawPage.GetType() == typeof(CheckboxPage))
{
var page = (CheckboxPage)rawPage;
if (page.Options.Length > 2 && page.TopLine != null && page.BottomLine != null)
return @$"CheckboxPage with a TopLine and BottomLine must not have more than 2 options.";
if (page.Options.Length > 3 && (page.TopLine != null || page.BottomLine != null))
return @$"CheckboxPage with a TopLine or BottomLine must not have more than 3 options.";
if (page.Options.Length > 4)
return @$"CheckboxPage must not have more than 4 options.";
}
else if (rawPage.GetType() == typeof(RadioPage))
{
var page = (RadioPage)rawPage;
if (page.Options.Length > 2 && page.TopLine != null && page.BottomLine != null)
return @$"RadioPage with a TopLine and BottomLine must not have more than 2 options.";
if (page.Options.Length > 3 && (page.TopLine != null || page.BottomLine != null))
return @$"RadioPage with a TopLine or BottomLine must not have more than 3 options.";
if (page.Options.Length > 4)
return @$"RadioPage must not have more than 4 options.";
if (page.DefaultOption != null && !page.Options.Any(x => x.Name == page.DefaultOption))
return @$"No option matching DefaultOption {page.DefaultOption} in RadioPage.";
}
else if (rawPage.GetType() == typeof(RadioImagePage))
{
var page = (RadioImagePage)rawPage;
if (page.Options.Length > 4)
return @$"RadioImagePage must not have more than 4 options.";
if (page.DefaultOption != null && !page.Options.Any(x => x.Name == page.DefaultOption))
return @$"No option matching DefaultOption {page.DefaultOption} in RadioImagePage.";
}
}
return null;
}
public static double GetVersionNumber(string toBeParsed)
{
// Examples:
// 0.4
// 0.4 Alpha
// 1.0.5
// 1.0.5 Beta
// Remove characters after first space (and the space itself)
if (toBeParsed.IndexOf(' ') >= 0)
toBeParsed = toBeParsed.Substring(0, toBeParsed.IndexOf(' '));
if (toBeParsed.LastIndexOf('.') != toBeParsed.IndexOf('.'))
{
// Example: 1.0.5
toBeParsed = toBeParsed.Remove(toBeParsed.LastIndexOf('.'), 1);
// Result: 1.05
}
return double.Parse(toBeParsed, CultureInfo.InvariantCulture);
}
public double GetVersionNumber()
{
return GetVersionNumber(Version);
}
public async Task<string> LatestPlaybookVersion()
{
if (!IsValidGit())
{
throw new ArgumentException("Link provided is not a proper Git link.");
}
string gitPlatform = GetPlaybookGitPlatform();
string repo = GetRepository();
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("curl/7.55.1"); //Required for GitHub
string url = gitPlatform switch
{
"github.com" => $"https://api.github.com/repos/{repo}/releases",
"gitlab.com" => $"https://gitlab.com/api/v4/projects/{Uri.EscapeDataString(repo)}/releases",
_ => $"https://{gitPlatform}/api/v1/repos/{repo}/releases"
};
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var array = JArray.Parse(json);
return (string) array.FirstOrDefault()?["tag_name"];
}
public async Task<List<string>> GetPlaybookVersions()
{
if (!IsValidGit())
{
throw new ArgumentException("Link provided is not a proper Git link.");
}
string gitPlatform = GetPlaybookGitPlatform();
string repo = GetRepository();
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("curl/7.55.1"); //Required for GitHub
string url = gitPlatform switch
{
"github.com" => $"https://api.github.com/repos/{repo}/releases",
"gitlab.com" => $"https://gitlab.com/api/v4/projects/{Uri.EscapeDataString(repo)}/releases",
_ => $"https://{gitPlatform}/api/v1/repos/{repo}/releases"
};
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var array = JArray.Parse(json);
var result = new List<string>();
foreach (var releaseToken in array)
result.Add((string)releaseToken["tag_name"]);
return result;
}
public async Task DownloadLatestPlaybook(BackgroundWorker worker = null)
{
string repo = GetRepository();
string gitPlatform = GetPlaybookGitPlatform();
var httpClient = new WinUtil.HttpProgressClient();
httpClient.Client.DefaultRequestHeaders.UserAgent.ParseAdd("curl/7.55.1"); //Required for GitHub
var downloadUrl = string.Empty;
var downloadDir = System.IO.Path.Combine(Environment.GetEnvironmentVariable("TEMP"), "AME");
var downloadPath = System.IO.Path.Combine(downloadDir, "playbook.apbx");
string baseUrl;
string releasesUrl;
string assetsKey;
string browserDownloadUrlKey;
switch (gitPlatform)
{
case "github.com":
baseUrl = "https://api.github.com";
releasesUrl = $"{baseUrl}/repos/{repo}/releases";
assetsKey = "assets";
browserDownloadUrlKey = "browser_download_url";
break;
case "gitlab.com":
baseUrl = "https://gitlab.com/api/v4";
releasesUrl = $"{baseUrl}/projects/{Uri.EscapeDataString(repo)}/releases";
assetsKey = "assets.links";
browserDownloadUrlKey = "direct_asset_url";
break;
default:
baseUrl = $"https://{gitPlatform}/api/v1";
releasesUrl = $"{baseUrl}/repos/{repo}/releases";
assetsKey = "assets";
browserDownloadUrlKey = "browser_download_url";
break;
}
var releasesResponse = await httpClient.GetAsync(releasesUrl);
releasesResponse.EnsureSuccessStatusCode();
var releasesContent = await releasesResponse.Content.ReadAsStringAsync();
var releases = JArray.Parse(releasesContent);
var release = releases.FirstOrDefault();
long size = 3000000;
if (release?.SelectToken(assetsKey) is JArray assets)
{
var asset = assets.FirstOrDefault(a => a["name"].ToString().EndsWith(".apbx"));
if (asset != null)
{
downloadUrl = asset[browserDownloadUrlKey]?.ToString();
if (asset["size"] != null)
long.TryParse(asset["size"].ToString(), out size);
}
}
if (worker != null)
worker.ReportProgress(10);
// Download the release asset
if (!string.IsNullOrEmpty(downloadUrl))
{
httpClient.Client.DefaultRequestHeaders.Clear();
httpClient.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) => {
if (progressPercentage.HasValue && worker != null)
worker.ReportProgress((int)Math.Ceiling(10 + (progressPercentage.Value * 0.7)));
};
await httpClient.StartDownload(downloadUrl, downloadPath, size);
}
httpClient.Dispose();
}
public string GetRepository()
{
if (Git == null)
{
return null;
}
var urlSegments = Git.Replace("https://", "").Replace("http://", "").Split('/');
return urlSegments[1] +"/"+ urlSegments[2];
}
public string GetPlaybookGitPlatform()
{
if (this.Git == null)
{
throw new NullReferenceException("No Git link available.");
}
return new Uri(Git).Host;
}
public bool IsValidGit()
{
if (Git == null)
{
throw new NullReferenceException("No Git link available.");
}
return Regex.IsMatch(Git, "((git|ssh|http(s)?)|(git@[\\w\\.]+))(:(//)?)([\\w\\.@\\:/\\-~]+)(/)?");;
}
public override string ToString()
{
return $"Name: {Name}\nDescription: {Description}\nUsername: {Username}\nDetails: {Details}\nRequirements: {Requirements}.";
}
[XmlType("CheckboxPage")]
public class CheckboxPage : FeaturePage
{
public class CheckboxOption : Option
{
[XmlAttribute]
public bool IsChecked { get; set; } = true;
}
[XmlArray]
[XmlArrayItem(ElementName = "CheckboxOption", Type = typeof(CheckboxOption))]
public Option[] Options { get; set; }
}
public class RadioPage : FeaturePage
{
[XmlAttribute]
public string DefaultOption { get; set; } = null;
public class RadioOption : Option
{
}
[XmlArray]
[XmlArrayItem(ElementName = "RadioOption", Type = typeof(RadioOption))]
public Option[] Options { get; set; }
}
public class RadioImagePage : FeaturePage
{
[XmlAttribute]
public string DefaultOption { get; set; } = null;
public class RadioImageOption : Option
{
public string FileName { get; set; } = null;
public bool Fill { get; set; } = false;
[XmlAttribute]
public bool None { get; set; } = false;
public string GradientTopColor { get; set; } = null;
public string GradientBottomColor { get; set; } = null;
}
[XmlArray]
[XmlArrayItem(ElementName = "RadioImageOption", Type = typeof(RadioImageOption))]
public Option[] Options { get; set; }
[XmlAttribute]
public bool CheckDefaultBrowser { get; set; } = false;
}
public class FeaturePage
{
[XmlAttribute]
public string DependsOn { get; set; } = null;
[XmlAttribute]
public bool IsRequired { get; set; } = false;
public Line TopLine { get; set; } = null;
public Line BottomLine { get; set; } = null;
public class Option
{
public string Name { get; set; } = null;
public virtual string Text { get; set; }
[XmlAttribute]
public string DependsOn { get; set; } = null;
}
public class Line
{
[XmlAttribute("Text")]
public string Text { get; set; }
[XmlAttribute("Link")]
public string Link { get; set; } = null;
}
[XmlAttribute]
public string Description { get; set; }
}
}
}

+ 506
- 0
TrustedUninstaller.Shared/ProcessPrivilege.cs View File

@ -0,0 +1,506 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
using TrustedUninstaller.Shared.Actions;
namespace TrustedUninstaller.Shared
{
public class ProcessPrivilege
{
private static Win32.TokensEx.SafeTokenHandle userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
private static Win32.TokensEx.SafeTokenHandle elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
private static Win32.TokensEx.SafeTokenHandle systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
private static Win32.TokensEx.SafeTokenHandle impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
private static Win32.TokensEx.SafeTokenHandle lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
internal static void ResetTokens()
{
elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
}
public static void StartPrivilegedTask(AugmentedProcess.Process process, Privilege privilege)
{
var tcs = StartThread(process, privilege);
tcs.Task.Wait();
for (int i = 0; tcs.Task.Result != null && i <= 3; i++)
{
ErrorLogger.WriteToErrorLog("Error launching privileged process: " + tcs.Task.Result.Message, tcs.Task.Result.StackTrace, "PrivilegedProcess Warning",
Path.GetFileName(process.StartInfo.FileName));
ResetTokens();
Thread.Sleep(500 * i);
tcs = StartThread(process, privilege);
tcs.Task.Wait();
}
if (tcs.Task.Result != null)
throw new SecurityException("Error launching privileged process.", tcs.Task.Result);
}
private static TaskCompletionSource<Exception> StartThread(AugmentedProcess.Process process, Privilege privilege)
{
var tcs = new TaskCompletionSource<Exception>();
var thread = new Thread(() =>
{
try
{
switch (privilege)
{
case (Privilege.System):
GetSystemToken();
process.Start(AugmentedProcess.Process.CreateType.RawToken, ref systemToken);
break;
case (Privilege.CurrentUser):
GetUserToken(true);
process.Start(AugmentedProcess.Process.CreateType.UserToken, ref userToken);
break;
case (Privilege.CurrentUserElevated):
GetElevatedUserToken();
process.Start(AugmentedProcess.Process.CreateType.RawToken, ref elevatedUserToken);
break;
default:
throw new ArgumentException("Unexpected.");
}
}
catch (Exception e)
{
tcs.SetResult(e);
return;
}
tcs.SetResult(null);
});
thread.Start();
return tcs;
}
private static uint GetUserSession()
{
var sessionId = Win32.WTS.WTSGetActiveConsoleSessionId();
if (sessionId != 0xFFFFFFFF) return sessionId;
IntPtr pSessionInfo = IntPtr.Zero;
Int32 count = 0;
if (Win32.WTS.WTSEnumerateSessions((IntPtr)null, 0, 1, ref pSessionInfo, ref count) == 0)
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error enumerating user sessions.");
Int32 dataSize = Marshal.SizeOf(typeof(Win32.WTS.WTS_SESSION_INFO));
Int64 current = (Int64)pSessionInfo;
for (int i = 0; i < count; i++)
{
Win32.WTS.WTS_SESSION_INFO si =
(Win32.WTS.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current,
typeof(Win32.WTS.WTS_SESSION_INFO));
current += dataSize;
if (si.State == Win32.WTS.WTS_CONNECTSTATE_CLASS.WTSActive)
{
sessionId = (uint)si.SessionID;
break;
}
}
Win32.WTS.WTSFreeMemory(pSessionInfo);
return sessionId;
}
private static void GetUserToken(bool getPrivileges)
{
if (getPrivileges)
{
GetSystemToken();
var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken);
if (!result)
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token.");
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME);
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME);
}
if (userToken.DangerousGetHandle() != IntPtr.Zero)
return;
var sessionId = GetUserSession();
if (Win32.WTS.WTSQueryUserToken(sessionId, out Win32.TokensEx.SafeTokenHandle wtsToken))
{
if (!Win32.Tokens.DuplicateTokenEx(wtsToken, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS,
IntPtr.Zero,
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out userToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error(),
"Failed to duplicate process token for lsass.");
}
return;
}
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error fetching active user session token.");
}
private static void GetElevatedUserToken()
{
GetSystemToken();
var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken);
if (!result)
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token.");
if (lsassToken.DangerousGetHandle() == IntPtr.Zero)
{
var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("lsass").First().Id);
if (!Win32.Tokens.OpenProcessToken(processHandle,
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE |
Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
out var tokenHandle))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for lsass.");
}
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS,
IntPtr.Zero,
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
Win32.Tokens.TOKEN_TYPE.TokenImpersonation, out lsassToken))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(),
"Failed to duplicate process token for lsass.");
}
Win32.CloseHandle(processHandle);
}
result = Win32.Tokens.ImpersonateLoggedOnUser(lsassToken);
if (!result)
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating lsass process token.");
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME);
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME);
if (elevatedUserToken.DangerousGetHandle() != IntPtr.Zero)
return;
var privileges = new[]
{
Win32.Tokens.SE_INCREASE_QUOTA_NAME,
Win32.Tokens.SE_MACHINE_ACCOUNT_NAME, Win32.Tokens.SE_SECURITY_NAME,
Win32.Tokens.SE_TAKE_OWNERSHIP_NAME, Win32.Tokens.SE_LOAD_DRIVER_NAME,
Win32.Tokens.SE_SYSTEM_PROFILE_NAME, Win32.Tokens.SE_SYSTEMTIME_NAME,
Win32.Tokens.SE_PROFILE_SINGLE_PROCESS_NAME, Win32.Tokens.SE_INCREASE_BASE_PRIORITY_NAME,
Win32.Tokens.SE_CREATE_PERMANENT_NAME,
Win32.Tokens.SE_BACKUP_NAME, Win32.Tokens.SE_RESTORE_NAME, Win32.Tokens.SE_SHUTDOWN_NAME,
Win32.Tokens.SE_DEBUG_NAME, Win32.Tokens.SE_AUDIT_NAME, Win32.Tokens.SE_SYSTEM_ENVIRONMENT_NAME,
Win32.Tokens.SE_CHANGE_NOTIFY_NAME,
Win32.Tokens.SE_UNDOCK_NAME, Win32.Tokens.SE_SYNC_AGENT_NAME,
Win32.Tokens.SE_ENABLE_DELEGATION_NAME, Win32.Tokens.SE_MANAGE_VOLUME_NAME,
Win32.Tokens.SE_IMPERSONATE_NAME, Win32.Tokens.SE_CREATE_GLOBAL_NAME,
Win32.Tokens.SE_TRUSTED_CREDMAN_ACCESS_NAME, Win32.Tokens.SE_RELABEL_NAME,
Win32.Tokens.SE_TIME_ZONE_NAME,
Win32.Tokens.SE_CREATE_SYMBOLIC_LINK_NAME, Win32.Tokens.SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME
};
var authId = Win32.Tokens.SYSTEM_LUID;
GetUserToken(false);
Win32.Tokens.DuplicateTokenEx(userToken,
Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.TOKEN_TYPE.TokenPrimary,
out Win32.TokensEx.SafeTokenHandle dupedUserToken);
Win32.SID.AllocateAndInitializeSid(
ref Win32.SID.SECURITY_MANDATORY_LABEL_AUTHORITY,
1,
(int)Win32.SID.SECURITY_MANDATORY_LABEL.High,
0,
0,
0,
0,
0,
0,
0,
out IntPtr integritySid);
var tokenMandatoryLabel = new Win32.Tokens.TOKEN_MANDATORY_LABEL() {
Label = default(Win32.SID.SID_AND_ATTRIBUTES)
};
tokenMandatoryLabel.Label.Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_INTEGRITY;
tokenMandatoryLabel.Label.Sid = integritySid;
var integritySize = Marshal.SizeOf(tokenMandatoryLabel);
var tokenInfo = Marshal.AllocHGlobal(integritySize);
Marshal.StructureToPtr(tokenMandatoryLabel, tokenInfo, false);
Win32.Tokens.SetTokenInformation(
dupedUserToken,
Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel,
tokenInfo,
integritySize + Win32.SID.GetLengthSid(integritySid));
var pTokenUser = Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenUser);
var pTokenOwner =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenOwner);
var pTokenPrivileges =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrivileges);
var pTokenGroups =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenGroups);
var pTokenPrimaryGroup =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrimaryGroup);
var pTokenDefaultDacl =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenDefaultDacl);
var pTokenSource =
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenSource);
var tokenUser =
(Win32.Tokens.TOKEN_USER)Marshal.PtrToStructure(pTokenUser, typeof(Win32.Tokens.TOKEN_USER));
if (!Win32.TokensEx.CreateTokenPrivileges(privileges, out var tokenPrivileges))
tokenPrivileges =
(Win32.Tokens.TOKEN_PRIVILEGES)Marshal.PtrToStructure(pTokenPrivileges,
typeof(Win32.Tokens.TOKEN_PRIVILEGES));
var tokenGroups = (Win32.Tokens.TOKEN_GROUPS)Marshal.PtrToStructure(
pTokenGroups, typeof(Win32.Tokens.TOKEN_GROUPS));
var tokenOwner =
(Win32.Tokens.TOKEN_OWNER)Marshal.PtrToStructure(pTokenOwner, typeof(Win32.Tokens.TOKEN_OWNER));
var tokenPrimaryGroup =
(Win32.Tokens.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(pTokenPrimaryGroup,
typeof(Win32.Tokens.TOKEN_PRIMARY_GROUP));
var tokenDefaultDacl = (Win32.Tokens.TOKEN_DEFAULT_DACL)Marshal.PtrToStructure(
pTokenDefaultDacl, typeof(Win32.Tokens.TOKEN_DEFAULT_DACL));
var tokenSource = (Win32.Tokens.TOKEN_SOURCE)Marshal.PtrToStructure(
pTokenSource, typeof(Win32.Tokens.TOKEN_SOURCE));
/*
for (var idx = 0; idx < tokenPrivileges.PrivilegeCount - 1; idx++)
{
if ((tokenPrivileges.Privileges[idx].Attributes &
(uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED) != 0)
{
}
if ((tokenPrivileges.Privileges[idx].Attributes &
(uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED_BY_DEFAULT) != 0)
{
}
}
*/
IntPtr adminsSid = IntPtr.Zero;
IntPtr localAndAdminSid = IntPtr.Zero;
bool adminsFound = false;
bool localAndAdminFound = false;
for (var idx = 0; idx < tokenGroups.GroupCount - 1; idx++)
{
Win32.SID.ConvertSidToStringSid(tokenGroups.Groups[idx].Sid, out string strSid);
if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_ADMINS, StringComparison.OrdinalIgnoreCase) == 0)
{
adminsFound = true;
tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES
.SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_OWNER;
} else if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, StringComparison.OrdinalIgnoreCase) == 0)
{
localAndAdminFound = true;
tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES
.SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY;
}
}
if (!adminsFound)
{
Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_ADMINS, out adminsSid);
tokenGroups.Groups[tokenGroups.GroupCount].Sid = adminsSid;
tokenGroups.Groups[tokenGroups.GroupCount].Attributes =
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT;
tokenGroups.GroupCount++;
}
if (!localAndAdminFound)
{
Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, out localAndAdminSid);
tokenGroups.Groups[tokenGroups.GroupCount].Sid = localAndAdminSid;
tokenGroups.Groups[tokenGroups.GroupCount].Attributes =
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT;
tokenGroups.GroupCount++;
}
var expirationTime = new Win32.LARGE_INTEGER() { QuadPart = -1L };
var sqos = new Win32.Tokens.SECURITY_QUALITY_OF_SERVICE(
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.SECURITY_STATIC_TRACKING,
0);
var oa = new Win32.Tokens.OBJECT_ATTRIBUTES(string.Empty, 0) { };
var pSqos = Marshal.AllocHGlobal(Marshal.SizeOf(sqos));
Marshal.StructureToPtr(sqos, pSqos, true);
oa.SecurityQualityOfService = pSqos;
var status = Win32.Tokens.ZwCreateToken(out elevatedUserToken,
Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, ref oa, Win32.Tokens.TOKEN_TYPE.TokenPrimary,
ref authId, ref expirationTime, ref tokenUser, ref tokenGroups, ref tokenPrivileges, ref tokenOwner,
ref tokenPrimaryGroup, ref tokenDefaultDacl, ref tokenSource);
Win32.LocalFree(pTokenUser);
Win32.LocalFree(pTokenOwner);
Win32.LocalFree(pTokenGroups);
Win32.LocalFree(pTokenDefaultDacl);
Win32.LocalFree(pTokenPrivileges);
Win32.LocalFree(pTokenPrimaryGroup);
if (adminsSid != IntPtr.Zero)
Win32.SID.FreeSid(adminsSid);
if (localAndAdminSid != IntPtr.Zero)
Win32.SID.FreeSid(localAndAdminSid);
if (integritySid != IntPtr.Zero)
Win32.SID.FreeSid(integritySid);
if (status != 0)
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error creating elevated user token: " + status);
}
public static void GetSystemToken()
{
if (systemToken.DangerousGetHandle() != IntPtr.Zero)
return;
try
{
var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("winlogon").First().Id);
if (!Win32.Tokens.OpenProcessToken(processHandle,
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
out var tokenHandle))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for winlogon.");
}
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(),
"Failed to duplicate process token for winlogon.");
}
Win32.CloseHandle(processHandle);
}
catch (Exception e)
{
var sessionId = GetUserSession();
int dwLsassPID = -1;
int dwWinLogonPID = -1;
Win32.WTS.WTS_PROCESS_INFO[] pProcesses;
IntPtr pProcessInfo = IntPtr.Zero;
int dwProcessCount = 0;
if (Win32.WTS.WTSEnumerateProcesses((IntPtr)null, 0, 1, ref pProcessInfo, ref dwProcessCount))
{
IntPtr pMemory = pProcessInfo;
pProcesses = new Win32.WTS.WTS_PROCESS_INFO[dwProcessCount];
for (int i = 0; i < dwProcessCount; i++)
{
pProcesses[i] =
(Win32.WTS.WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo,
typeof(Win32.WTS.WTS_PROCESS_INFO));
pProcessInfo = (IntPtr)((long)pProcessInfo + Marshal.SizeOf(pProcesses[i]));
var processName = Marshal.PtrToStringAnsi(pProcesses[i].ProcessName);
Win32.SID.ConvertSidToStringSid(pProcesses[i].UserSid, out string sid);
string strSid;
if (processName == null || pProcesses[i].UserSid == default || sid != "S-1-5-18") continue;
if ((-1 == dwLsassPID) && (0 == pProcesses[i].SessionID) && (processName == "lsass.exe"))
{
dwLsassPID = pProcesses[i].ProcessID;
continue;
}
if ((-1 == dwWinLogonPID) && (sessionId == pProcesses[i].SessionID) &&
(processName == "winlogon.exe"))
{
dwWinLogonPID = pProcesses[i].ProcessID;
continue;
}
}
Win32.WTS.WTSFreeMemory(pMemory);
}
IntPtr systemProcessHandle = IntPtr.Zero;
try
{
systemProcessHandle = Process.GetProcessById(dwLsassPID).Handle;
}
catch
{
systemProcessHandle = Process.GetProcessById(dwWinLogonPID).Handle;
}
if (!Win32.Tokens.OpenProcessToken(systemProcessHandle, Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE,
out Win32.TokensEx.SafeTokenHandle token))
{
Win32.CloseHandle(systemProcessHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token.");
}
if (!Win32.Tokens.DuplicateTokenEx(token, Win32.Tokens.TokenAccessFlags.MAXIMUM_ALLOWED, IntPtr.Zero,
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken))
{
Win32.CloseHandle(systemProcessHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to duplicate process token.");
}
Win32.CloseHandle(systemProcessHandle);
}
}
public static Win32.TokensEx.SafeTokenHandle GetCurrentProcessToken()
{
if (!Win32.Tokens.OpenProcessToken(Win32.Process.GetCurrentProcess(),
Win32.Tokens.TokenAccessFlags.TOKEN_READ, out Win32.TokensEx.SafeTokenHandle token))
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error opening token for current process.");
return token;
}
private static Win32.TokensEx.SafeTokenHandle GetProcessTokenByName(string name, bool impersonation)
{
var processHandle = Process.GetProcessesByName(name).First().Handle;
if (!Win32.Tokens.OpenProcessToken(processHandle,
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
out var tokenHandle))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for " + name + ".");
}
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
impersonation ? Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation : Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
impersonation ? Win32.Tokens.TOKEN_TYPE.TokenImpersonation : Win32.Tokens.TOKEN_TYPE.TokenPrimary, out Win32.TokensEx.SafeTokenHandle handle))
{
Win32.CloseHandle(processHandle);
throw new Win32Exception(Marshal.GetLastWin32Error(),
"Failed to duplicate process token for " + name + ".");
}
Win32.CloseHandle(processHandle);
return handle;
} }
}

+ 1
- 0
TrustedUninstaller.Shared/ProviderStatus.cs View File

@ -39,6 +39,7 @@ namespace TrustedUninstaller.Shared
public SignatureStatusFlags SignatureStatus;
public AVStatusFlags AVStatus;
public ProviderFlags SecurityProvider;
public bool FileExists;
public string DisplayName;
}
}

+ 163
- 17
TrustedUninstaller.Shared/Requirements.cs View File

@ -8,12 +8,16 @@ 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
{
@ -36,15 +40,19 @@ namespace TrustedUninstaller.Shared
Activation = 5,
[XmlEnum("NoAntivirus")]
NoAntivirus = 6,
[XmlEnum("LocalAccounts")]
LocalAccounts = 11,
[XmlEnum("PasswordSet")]
PasswordSet = 7,
PasswordSet = 11,
[XmlEnum("AdministratorPasswordSet")]
AdministratorPasswordSet = 8,
[XmlEnum("PluggedIn")]
PluggedIn = 9,
[XmlEnum("NoTweakware")]
NoTweakware = 10,
}
public static async Task<Requirement[]> MetRequirements(this Requirement[] requirements)
public static async Task<Requirement[]> MetRequirements(this Requirement[] requirements, bool checkNoPendingUpdate = false)
{
var requirementEnum = (Requirement[])Enum.GetValues(typeof(Requirement));
if (requirements == null)
@ -59,28 +67,35 @@ namespace TrustedUninstaller.Shared
else metRequirements.Add(Requirement.NoInternet);
if (requirements.Contains(Requirement.NoAntivirus))
if (await new NoAntivirus().IsMet()) metRequirements.Add(Requirement.NoAntivirus);
if (requirements.Contains(Requirement.NoPendingUpdates))
if (await new NoPendingUpdates().IsMet()) metRequirements.Add(Requirement.NoPendingUpdates);
if (true) metRequirements.Add(Requirement.NoAntivirus);
// Handled upstream
if (requirements.Contains(Requirement.Activation))
if (await new Activation().IsMet()) metRequirements.Add(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.PasswordSet))
metRequirements.Add(Requirement.PasswordSet);
if (requirements.Contains(Requirement.LocalAccounts))
metRequirements.Add(Requirement.LocalAccounts);
if (requirements.Contains(Requirement.AdministratorPasswordSet))
metRequirements.Add(Requirement.AdministratorPasswordSet);
if (requirements.Contains(Requirement.PluggedIn))
if (await new Battery().IsMet()) metRequirements.Add(Requirement.PluggedIn);
return metRequirements.ToArray();
}
@ -210,13 +225,35 @@ namespace TrustedUninstaller.Shared
{
public async Task<bool> IsMet()
{
if (Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\WinDefend") != null)
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<bool> Meet()
{
throw new NotImplementedException();
OnProgressAdded(30);
try
{
@ -244,7 +281,7 @@ namespace TrustedUninstaller.Shared
};
await defenderService.RunTask();
OnProgressAdded(20);
// MpOAV.dll normally in use by a lot of processes. This prevents that.
// MpOAV.dll normally is in use by a lot of processes. This prevents that.
var MpOAVCLSID = new RunAction()
{
Exe = $"NSudoLC.exe",
@ -348,15 +385,124 @@ namespace TrustedUninstaller.Shared
}
}
class SearchCompletedCallback : ISearchCompletedCallback
{
public void Invoke(ISearchJob searchJob, ISearchCompletedCallbackArgs callbackArgs)
{
this.CompleteTask();
}
private TaskCompletionSource<bool> taskSource = new TaskCompletionSource<bool>();
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<bool> IsMet()
{
//TODO: This
return true;
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<bool> 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<IUpdate>().Any(x => x.IsDownloaded))
{
result = true;
}
}
catch (Exception e)
{
result = false;
}
return result;
}
}
public class NoAntivirus : RequirementBase, IRequirements


+ 1
- 0
TrustedUninstaller.Shared/Tasks/ITaskAction.cs View File

@ -20,5 +20,6 @@ namespace TrustedUninstaller.Shared.Tasks
public string ErrorString();
public UninstallTaskStatus GetStatus();
public Task<bool> RunTask();
public void RunTaskOnMainThread();
}
}

+ 22
- 0
TrustedUninstaller.Shared/Tasks/TaskAction.cs View File

@ -0,0 +1,22 @@
using YamlDotNet.Serialization;
namespace TrustedUninstaller.Shared.Tasks
{
public class TaskAction
{
[YamlMember(typeof(bool), Alias = "ignoreErrors")]
public bool IgnoreErrors { get; set; } = false;
[YamlMember(typeof(string), Alias = "option")]
public string Option { get; set; } = null;
[YamlMember(typeof(string[]), Alias = "options")]
public string[] Options { get; set; } = null;
[YamlMember(typeof(string[]), Alias = "builds")]
public string[] Builds { get; set; } = null;
[YamlMember(typeof(string), Alias = "cpuArch")]
public string Arch { get; set; } = null;
}
}

+ 18
- 1
TrustedUninstaller.Shared/Tasks/UninstallTask.cs View File

@ -19,12 +19,29 @@ namespace TrustedUninstaller.Shared.Tasks
public int? MaxVersion { get; set; }
#nullable disable
public UninstallTaskStatus Status { get; set; } = UninstallTaskStatus.ToDo;
public List<ITaskAction> Actions { get; set; }
public List<ITaskAction> Actions { get; set; } = new List<ITaskAction>();
public int Priority { get; set; } = 1;
public UninstallTaskPrivilege Privilege { get; set; } = UninstallTaskPrivilege.Admin;
[YamlMember(typeof(string), Alias = "option")]
public string Option { get; set; } = null;
[YamlMember(typeof(string[]), Alias = "options")]
public string[] Options { get; set; } = null;
[YamlMember(typeof(string[]), Alias = "builds")]
public string[] Builds { get; set; } = null;
[YamlMember(typeof(string), Alias = "cpuArch")]
public string Arch { get; set; } = null;
public List<string> Features { get; set; } = new List<string>();
public List<string> Tasks
{
set => Features = value;
get => Features;
}
public void Update()
{
/*


+ 49
- 12
TrustedUninstaller.Shared/TrustedUninstaller.Shared.csproj View File

@ -14,6 +14,9 @@
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<AllowedReferenceRelatedFileExtensions>
*.xml
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
<PropertyGroup>
<PathMap>$([System.IO.Path]::GetFullPath('$(SolutionDir)'))=./</PathMap>
@ -40,14 +43,29 @@
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Single File|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<Optimize>true</Optimize>
<DebugType>embedded</DebugType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>SINGLE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug Single File|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<Optimize>true</Optimize>
<DebugType>embedded</DebugType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>SINGLE;DEBUG</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Private>True</Private>
@ -56,15 +74,10 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Windows">
<HintPath>bin\Debug\Windows.winmd</HintPath>
<Private>True</Private>
<EmbedInteropTypes>False</EmbedInteropTypes>
<Reference Include="YamlDotNet">
<HintPath>..\TrustedUninstaller.GUI\bin\x64\Release\YamlDotNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@ -86,9 +99,13 @@
<Compile Include="Actions\UserAction.cs" />
<Compile Include="Actions\WriteStatusAction.cs" />
<Compile Include="AmeliorationUtil.cs" />
<Compile Include="AugmentedProcess.cs" />
<Compile Include="Debug.cs" />
<Compile Include="Defender.cs" />
<Compile Include="DualOut.cs" />
<Compile Include="Globals.cs" />
<Compile Include="Playbook.cs" />
<Compile Include="ProcessPrivilege.cs" />
<Compile Include="ProviderStatus.cs" />
<Compile Include="ErrorLogger.cs" />
<Compile Include="Exceptions\InvalidRegistryEntryException.cs" />
@ -98,10 +115,12 @@
<Compile Include="Parser\TaskActionResolver.cs" />
<Compile Include="Predicates\IPredicate.cs" />
<Compile Include="Requirements.cs" />
<Compile Include="Tasks\TaskAction.cs" />
<Compile Include="Tasks\UninstallTaskPrivilege.cs" />
<Compile Include="Tasks\ITaskAction.cs" />
<Compile Include="Tasks\UninstallTaskStatus.cs" />
<Compile Include="Tasks\UninstallTask.cs" />
<Compile Include="Win32.cs" />
<Compile Include="WinUtil.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
@ -115,16 +134,25 @@
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="WUApiLib">
<Guid>{B596CC9F-56E5-419E-A622-E01BB457431E}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.IO" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Runtime" Version="4.3.0" />
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
<PackageReference Include="System.Security.Cryptography.Encoding" Version="4.3.0" />
@ -145,7 +173,16 @@
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' != 'Single File|x64' ">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Single File|x64' Or '$(Configuration)|$(Platform)' == 'Debug Single File|x64' ">
<PostBuildEvent>for /f "usebackq delims=" %%A in (`DIR /B /S /A:d "$(SolutionDir)" ^| FINDSTR /R /c:".*\\bin\\.*\\de$" /c:".*\\bin\\.*\\en$" /c:".*\\bin\\.*\\es$" /c:".*\\bin\\.*\\fr$" /c:".*\\bin\\.*\\it$" /c:".*\\bin\\.*\\ja$" /c:".*\\bin\\.*\\ko$" /c:".*\\bin\\.*\\ru$" /c:".*\\bin\\.*\\zh-Hans$" /c:".*\\bin\\.*\\zh-Hant$" /c:".*\\bin\\.*\\pl$" /c:".*\\bin\\.*\\zh-CN$"`) do (RMDIR /Q /S "%%A" &amp; cmd /c "exit /b 0")
PowerShell -NoP -C "Start-Process '$(SolutionDir)\TrustedUninstaller.GUI\gui-builder\ame-builder.exe' -ArgumentList 'Shared','""""x64\$(Configuration)""""' -NoNewWindow -Wait"
</PostBuildEvent>
<AllowedReferenceRelatedFileExtensions>
<!-- Prevent default XML files copied to output.-->
.allowedextension
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' != 'Single File|x64' And '$(Configuration)|$(Platform)' != 'Debug Single File|x64' ">
<PostBuildEvent>for /f "usebackq delims=" %%A in (`DIR /B /S /A:d "$(SolutionDir)" ^| FINDSTR /R /c:".*\\bin\\.*\\de$" /c:".*\\bin\\.*\\en$" /c:".*\\bin\\.*\\es$" /c:".*\\bin\\.*\\fr$" /c:".*\\bin\\.*\\it$" /c:".*\\bin\\.*\\ja$" /c:".*\\bin\\.*\\ko$" /c:".*\\bin\\.*\\ru$" /c:".*\\bin\\.*\\zh-Hans$" /c:".*\\bin\\.*\\zh-Hant$" /c:".*\\bin\\.*\\pl$" /c:".*\\bin\\.*\\zh-CN$"`) do (RMDIR /Q /S "%%A" &amp; cmd /c "exit /b 0")</PostBuildEvent>
</PropertyGroup>
</Project>

+ 1721
- 0
TrustedUninstaller.Shared/Win32.cs
File diff suppressed because it is too large
View File


+ 159
- 111
TrustedUninstaller.Shared/WinUtil.cs View File

@ -5,7 +5,6 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Management.Automation;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
@ -18,6 +17,7 @@ using System.Windows;
using System.Windows.Interop;
using Microsoft.Win32;
using TrustedUninstaller.Shared.Actions;
using TrustedUninstaller.Shared.Tasks;
namespace TrustedUninstaller.Shared
{
@ -173,7 +173,7 @@ namespace TrustedUninstaller.Shared
select g).FirstOrDefault();
return msAccount == null ? Environment.UserName : msAccount.Substring(@"MicrosoftAccount\".Length);
}
public static bool IsLocalAccount()
{
var wi = WindowsIdentity.GetCurrent();
@ -190,15 +190,14 @@ namespace TrustedUninstaller.Shared
public enum SL_GENUINE_STATE
{
SL_GEN_STATE_IS_GENUINE = 0,
// SL_GEN_STATE_INVALID_LICENSE = 1,
// SL_GEN_STATE_TAMPERED = 2,
SL_GEN_STATE_LAST = 3
}
[DllImport("Slwga.dll", EntryPoint = "SLIsGenuineLocal", CharSet = CharSet.None, ExactSpelling =
false, SetLastError = false, PreserveSig = true, CallingConvention = CallingConvention.Winapi, BestFitMapping =
false, ThrowOnUnmappableChar = false)]
false, SetLastError = false, PreserveSig = true, CallingConvention = CallingConvention.Winapi, BestFitMapping =
false, ThrowOnUnmappableChar = false)]
[PreserveSigAttribute()]
internal static extern uint SLIsGenuineLocal(ref SLID slid, [In, Out] ref SL_GENUINE_STATE genuineState, IntPtr val3);
@ -206,7 +205,7 @@ namespace TrustedUninstaller.Shared
{
// Microsoft-Windows-Security-SPP GUID
// http://technet.microsoft.com/en-us/library/dd772270.aspx
var windowsSlid = new SLID("55c92734-d682-4d71-983e-d6ec3f16059f");
var windowsSlid = new SLID("55c92734-d682-4d71-983e-d6ec3f16059f");
var genuineState = SL_GENUINE_STATE.SL_GEN_STATE_LAST;
var resultInt = SLIsGenuineLocal(ref windowsSlid, ref genuineState, IntPtr.Zero);
#if DEBUG
@ -214,20 +213,21 @@ namespace TrustedUninstaller.Shared
#else
return resultInt == 0 && genuineState == SL_GENUINE_STATE.SL_GEN_STATE_IS_GENUINE;
#endif
}
private static IEnumerable<string> GetWindowsGroups(WindowsIdentity id)
{
var irc = id.Groups ?? new IdentityReferenceCollection();
return irc.Select(ir => (NTAccount)ir.Translate(typeof(NTAccount))).Select(acc => acc.Value).ToList();
return irc.Select(ir => (NTAccount) ir.Translate(typeof(NTAccount))).Select(acc => acc.Value).ToList();
}
public static bool HasWindowsGroup(string groupName)
{
var appDomain = Thread.GetDomain();
appDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
var currentPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
var groups = GetWindowsGroups((WindowsIdentity)currentPrincipal.Identity);
var currentPrincipal = (WindowsPrincipal) Thread.CurrentPrincipal;
var groups = GetWindowsGroups((WindowsIdentity) currentPrincipal.Identity);
return groups.Any(group => group == groupName);
}
@ -444,7 +444,7 @@ namespace TrustedUninstaller.Shared
if (res == ERROR_MORE_DATA)
{
// Create an array to store the process results
RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded + 3];
pnProcInfo = pnProcInfoNeeded;
// Get the list
@ -465,7 +465,7 @@ namespace TrustedUninstaller.Shared
catch (ArgumentException) { }
}
}
else throw new Exception("Could not list processes locking resource.");
else throw new Exception("Could not list processes locking resource: " + res);
}
else if (res != 0)
throw new Exception("Could not list processes locking resource. Could not get size of result." + $" Result value: {res}");
@ -554,7 +554,8 @@ namespace TrustedUninstaller.Shared
DisplayName = result["displayName"].ToString(),
AVStatus = enabled ? AVStatusFlags.Enabled : AVStatusFlags.Unknown,
SecurityProvider = ProviderFlags.ANTIVIRUS,
SignatureStatus = outdated ? SignatureStatusFlags.OutOfDate : SignatureStatusFlags.UpToDate
SignatureStatus = outdated ? SignatureStatusFlags.OutOfDate : SignatureStatusFlags.UpToDate,
FileExists = File.Exists(result["pathToSignedProductExe"].ToString())
};
avList.Add(av);
}
@ -608,37 +609,67 @@ namespace TrustedUninstaller.Shared
public static async Task RemoveProtectionAsync()
{
var cmdAction = new CmdAction();
if (!IsVCInstalled())
if (AmeliorationUtil.UseKernelDriver)
{
Console.WriteLine(Environment.NewLine + "Installing VC 15...");
/*
if (!IsVCInstalled())
{
Console.WriteLine(Environment.NewLine + "Installing VC 15...");
try
{
//Install Visual C++ 2015 redistributable package silently
cmdAction.Command = "vc_redist.x64.exe /q /norestart";
cmdAction.RunTaskOnMainThread();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Error while installing VC 15.");
throw;
}
}
*/
try
{
//Install Visual C++ 2015 redistributable package silently
cmdAction.Command = "vc_redist.x64.exe /q /norestart";
await cmdAction.RunTask();
Console.WriteLine(Environment.NewLine + "Installing driver...");
cmdAction.Command = Environment.Is64BitOperatingSystem
? $"ProcessHacker\\x64\\ProcessHacker.exe -s -installkph"
: $"ProcessHacker\\x86\\ProcessHacker.exe -s -installkph";
cmdAction.RunTaskOnMainThread();
await AmeliorationUtil.SafeRunAction(new RegistryValueAction()
{ KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2", Value = "DeleteFlag", Type = RegistryValueType.REG_DWORD, Data = 1 });
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Error while installing VC 15.");
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "ProcessHacker ran into an error while installing its driver.");
throw;
}
}
}
public static void CheckKph()
{
try
{
if (!AmeliorationUtil.UseKernelDriver || new RegistryKeyAction() { KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2", Operation = RegistryKeyOperation.Add }.GetStatus() == UninstallTaskStatus.Completed)
return;
Console.WriteLine(Environment.NewLine + "Installing driver...");
var cmdAction = new CmdAction();
cmdAction.Command = Environment.Is64BitOperatingSystem
? $"ProcessHacker\\x64\\ProcessHacker.exe -s -installkph"
: $"ProcessHacker\\x86\\ProcessHacker.exe -s -installkph";
var res = await cmdAction.RunTask();
cmdAction.RunTaskOnMainThread();
AmeliorationUtil.SafeRunAction(new RegistryValueAction()
{ KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2", Value = "DeleteFlag", Type = RegistryValueType.REG_DWORD, Data = 1 }).Wait();
}
catch (Exception e)
{
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "ProcessHacker ran into an error while installing its driver.");
throw;
ErrorLogger.WriteToErrorLog("Error checking kernel driver: " + e.Message, e.StackTrace, "Warning");
}
}
private const int GWL_STYLE = -16;
@ -682,89 +713,13 @@ namespace TrustedUninstaller.Shared
return false;
}
}
public static void PrepareSystemCLI()
{
try
{
var defenderStop = new RunAction()
{
RawPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Exe = $"NSudoLC.exe",
Arguments = "-U:T -P:E -M:S -ShowWindowMode:Hide -Priority:RealTime -Wait cmd /c \"" +
"sc sdset \"WinDefend\" \"D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWRPLOCRRC;;;BA)(A;;CCLCSWRPLOCRRC;;;BU)(A;;CCLCSWRPLOCRRC;;;IU)(A;;CCLCSWRPLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)\"&" +
"sc config WinDefend start=disabled&" +
"net stop WinDefend\"",
CreateWindow = false,
Timeout = 7500,
};
defenderStop.RunTask().Wait();
} catch (Exception e)
{
}
var defenderValues = new RunAction()
{
RawPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Exe = $"NSudoLC.exe",
Arguments = "-U:T -P:E -M:S -ShowWindowMode:Hide -Priority:RealTime -Wait cmd /c \"reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows Defender\" /v \"ProductAppDataPath\" /f &" +
" reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows Defender\" /v \"InstallLocation\" /f\"",
CreateWindow = false
};
defenderValues.RunTask().Wait();
var defenderKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows Defender");
if (defenderKey != null && defenderKey.GetValueNames().Contains("InstallLocation"))
{
throw new Exception("Could not remove defender install values.");
}
var defenderService = new RunAction()
{
RawPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Exe = $"NSudoLC.exe",
Arguments = "-U:T -P:E -M:S -ShowWindowMode:Hide -Priority:RealTime -Wait reg delete \"HKLM\\SYSTEM\\CurrentControlSet\\Services\\WinDefend\" /f",
CreateWindow = false
};
defenderService.RunTask().Wait();
if (Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\WinDefend") != null)
{
throw new Exception("Could not remove WinDefend service.");
}
// MpOAV.dll normally in use by a lot of processes. This prevents that.
var MpOAVCLSID = new RunAction()
{
RawPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Exe = $"NSudoLC.exe",
Arguments = @"-U:T -P:E -M:S -Priority:RealTime -ShowWindowMode:Hide -Wait reg delete ""HKCR\CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32"" /f",
CreateWindow = false
};
MpOAVCLSID.RunTask().Wait();
if (Registry.ClassesRoot.OpenSubKey(@"CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32") != null)
{
throw new Exception("Could not remove MpOAV mapping.");
}
// Can cause ProcessHacker driver warnings without this
AmeliorationUtil.SafeRunAction(new RegistryValueAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity",
Value = "Enabled",
Data = 0,
}).Wait();
AmeliorationUtil.SafeRunAction(new RegistryValueAction()
{
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Control\CI\Config",
Value = "VulnerableDriverBlocklistEnable",
Data = 0,
}).Wait();
}
public static async Task UninstallDriver()
{
if (AmeliorationUtil.UseKernelDriver == false)
return;
AmeliorationUtil.UseKernelDriver = false;
CmdAction cmdAction = new CmdAction();
try
{
@ -772,7 +727,7 @@ namespace TrustedUninstaller.Shared
cmdAction.Command = Environment.Is64BitOperatingSystem
? $"ProcessHacker\\x64\\ProcessHacker.exe -s -uninstallkph"
: $"ProcessHacker\\x86\\ProcessHacker.exe -s -uninstallkph";
await cmdAction.RunTask();
cmdAction.RunTaskOnMainThread();
}
catch (Exception e)
{
@ -781,8 +736,6 @@ namespace TrustedUninstaller.Shared
}
}
public class RegistryManager
{
[DllImport("advapi32.dll", SetLastError = true)]
@ -809,11 +762,12 @@ namespace TrustedUninstaller.Shared
string name;
if (path.Contains("Users\\Default\\")) name = classHive ? "AME_UserHive_Default_Classes" : "AME_UserHive_Default";
else name = classHive ? "AME_UserHive_" + (HivesLoaded + 1) + "_Classes" : "AME_UserHive_" + (HivesLoaded + 1);
else name = classHive ? "AME_UserHive_" + (HivesLoaded) + "_Classes" : "AME_UserHive_" + (HivesLoaded + 1);
IntPtr parentHandle = parentKey.Handle.DangerousGetHandle();
RegLoadKey(parentHandle, name, path);
HivesLoaded++;
if (!path.Contains("Users\\Default\\"))
HivesLoaded++;
}
private static void AcquirePrivileges()
{
@ -836,7 +790,7 @@ namespace TrustedUninstaller.Shared
private static bool HivesHooked;
private static int HivesLoaded;
public static async void HookUserHives()
public static void HookUserHives()
{
try
{
@ -909,7 +863,7 @@ namespace TrustedUninstaller.Shared
}
}
public static async void UnhookUserHives()
public static void UnhookUserHives()
{
try
{
@ -933,5 +887,99 @@ namespace TrustedUninstaller.Shared
}
}
}
public class HttpProgressClient : IDisposable
{
private string _downloadUrl;
private string _destinationFilePath;
public HttpClient Client;
public delegate void ProgressChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
public event ProgressChangedHandler ProgressChanged;
public HttpProgressClient()
{
Client = new HttpClient { Timeout = TimeSpan.FromDays(1) };
}
public async Task StartDownload(string downloadUrl, string destinationFilePath, long? size = null)
{
_downloadUrl = downloadUrl;
_destinationFilePath = destinationFilePath;
using (var response = await Client.GetAsync(_downloadUrl, HttpCompletionOption.ResponseHeadersRead))
await DownloadFileFromHttpResponseMessage(response, size);
}
public Task<HttpResponseMessage> GetAsync(string link)
{
return Client.GetAsync(link);
}
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response, long? size)
{
response.EnsureSuccessStatusCode();
if (!size.HasValue)
size = response.Content.Headers.ContentLength;
using (var contentStream = await response.Content.ReadAsStreamAsync())
await ProcessContentStream(size, contentStream);
}
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
{
var totalBytesRead = 0L;
var readCount = 0L;
var buffer = new byte[8192];
var isMoreToRead = true;
using (var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
{
do
{
var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
isMoreToRead = false;
TriggerProgressChanged(totalDownloadSize, totalBytesRead);
continue;
}
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
readCount += 1;
if (readCount % 50 == 0)
TriggerProgressChanged(totalDownloadSize, totalBytesRead);
}
while (isMoreToRead);
}
}
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
{
if (ProgressChanged == null)
return;
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
{
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
}
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
}
public void Dispose()
{
Client?.Dispose();
}
}
}
}

BIN
Windows.winmd View File


BIN
ameliorated_logo.png View File

Before After
Width: 1039  |  Height: 905  |  Size: 80 KiB

Loading…
Cancel
Save