Skip to content

Commit

Permalink
AppControl Manager v.1.8.3.0 (#516)
Browse files Browse the repository at this point in the history
Improved the update mechanism, it will remove any related previous ASR rule exclusions instead of only those for the previous app version. The same improvement was previously implemented in the bootstrapper script and the Harden Windows Security module as well.

Improved page behaviors, their states will now be preserved at all times even if you navigate away from them for any amount of time.

Fixed NuGet connection (e.g., for downloading the SignTool.exe), it isn't always compatible with HTTP v.2
  • Loading branch information
HotCakeX authored Jan 9, 2025
1 parent d834c20 commit 183f9e2
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 82 deletions.
2 changes: 1 addition & 1 deletion AppControl Manager/AppControl Manager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
<AssemblyName>AppControlManager</AssemblyName>
<PublishAot>False</PublishAot>
<ErrorReport>send</ErrorReport>
<FileVersion>1.8.2.0</FileVersion>
<FileVersion>1.8.3.0</FileVersion>
<AssemblyVersion>$(FileVersion)</AssemblyVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
Expand Down
1 change: 0 additions & 1 deletion AppControl Manager/Logic/CertificateCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ internal static class CertificateGenerator

/// <summary>
/// Build a self-signed on-device certificate for the purpose of App Control policy signing
/// Use certutil -dump -v '.\codesign.cer' to view the certificate properties, such as encoding of the certificate fields like the subject
/// </summary>
/// <param name="CommonName"></param>
/// <param name="Password"></param>
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Logic/Main/BasePolicyCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ internal static void DeployDriversBlockRules(string StagingArea)
}

// Download the zip file
using (HttpClient client = new SecHttpClient())
using (HttpClient client = new())
{
// Download the file synchronously
byte[] fileBytes = client.GetByteArrayAsync(DriversBlockListZipDownloadLink).GetAwaiter().GetResult();
Expand Down
5 changes: 2 additions & 3 deletions AppControl Manager/Logic/SignToolHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Runtime.InteropServices;
using System.Text.Json;
using AppControlManager.Logging;
using AppControlManager.Logic;

namespace AppControlManager;

Expand Down Expand Up @@ -77,7 +76,7 @@ private static string Download()
{
DirectoryInfo stagingArea = StagingArea.NewStagingArea("GetSignTool");

using HttpClient client = new SecHttpClient();
using HttpClient client = new();

string packageName = "microsoft.windows.sdk.buildtools"; // Important that this stays all lower case

Expand Down Expand Up @@ -109,7 +108,7 @@ private static string Download()

// Extract the .nupkg file
string extractPath = Path.Combine(stagingArea.FullName, "extracted");
ZipFile.ExtractToDirectory(filePath, extractPath);
ZipFile.ExtractToDirectory(filePath, extractPath, true);

Logger.Write($"Extracted package to {extractPath}");

Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Identity
Name="AppControlManager"
Publisher="CN=SelfSignedCertForAppControlManager"
Version="1.8.2.0" />
Version="1.8.3.0" />

<mp:PhoneIdentity PhoneProductId="199a23ec-7cb6-4ab5-ab50-8baca348bc79" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>

Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/BuildNewCertificate.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public BuildNewCertificate()
{
this.InitializeComponent();

this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

CheckFieldContents();
}
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/CreateDenyPolicy.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public CreateDenyPolicy()
{
this.InitializeComponent();

this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

// Assign this instance to the static field
_instance = this;
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/CreatePolicy.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public CreatePolicy()
SignedAndReputableLogSizeInput.IsEnabled = false;

// Make sure navigating to/from this page maintains its state
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

}

Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/CreateSupplementalPolicy.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public CreateSupplementalPolicy()
this.InitializeComponent();

// Make sure navigating to/from this page maintains its state
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

// Assign this instance to the static field
_instance = this;
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/Deployment.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public Deployment()
{
this.InitializeComponent();

this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

if (GlobalVars.IsOlderThan24H2)
{
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/GetCIHashes.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed partial class GetCIHashes : Page
public GetCIHashes()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/MDEAHPolicyCreation.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public MDEAHPolicyCreation()
this.InitializeComponent();

// Make sure navigating to/from this page maintains its state
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

// Initialize the lists
FileIdentities = [];
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/MergePolicies.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public MergePolicies()
this.InitializeComponent();

// Make sure navigating to/from this page maintains its state
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;
}


Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/Pages/Simulation.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public sealed partial class Simulation : Page
public Simulation()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.NavigationCacheMode = NavigationCacheMode.Required;

SimulationOutputs = [];
AllSimulationOutputs = [];
Expand Down
128 changes: 63 additions & 65 deletions AppControl Manager/Pages/Update.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,25 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Windows.ApplicationModel;
using Windows.Management.Deployment;

#pragma warning disable IDE0063 // Do not simplify using statements, keep them scoped for proper disposal otherwise files will be in use until the method is exited

namespace AppControlManager.Pages;


public sealed partial class Update : Page
{
// Pattern for AppControl Manager version and architecture extraction from file path and download link URL
[GeneratedRegex(@"_(?<Version>\d+\.\d+\.\d+\.\d+)_(?<Architecture>x64|arm64)\.msix$", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
private static partial Regex MyRegex();

// Pattern for finding ASR rules that belong to the AppControl Manager
[GeneratedRegex("__sadt7br7jpt02", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
private static partial Regex MyRegex1();

// Common name of the on-device generated certificate used to sign the AppControl Manager MSIX package
private const string commonName = "SelfSignedCertForAppControlManager";

// Create a Regex object
internal readonly Regex regex = MyRegex();

Expand Down Expand Up @@ -226,9 +231,6 @@ await Task.Run(() =>
// Random password to temporarily encrypt the private key of the newly generated certificate
string PassWord = SiPolicyIntel.GUIDGenerator.GenerateUniqueGUID();

// Common name of the certificate
string commonName = "SelfSignedCertForAppControlManager";

// Path where the .cer file will be saved
string CertificateOutputPath = Path.Combine(stagingArea, $"{commonName}.cer");

Expand Down Expand Up @@ -263,52 +265,66 @@ await Task.Run(() =>
throw new InvalidOperationException("Could not get the version of the installing app");
}


// Signing the App Control Manager MSIX package
// In this step the SignTool detects the cert to use based on Common name + ThumbPrint + Hash Algo + Store Type + Store Name
ProcessStarter.RunCommand(signToolPath, $"sign /debug /n \"{commonName}\" /fd Sha512 /sm /s Root /sha1 {generatedCert.Thumbprint} \"{AppControlManagerSavePath}\"");

PackageManager packageManager = new();
IEnumerable<Package> PossibleExistingApp = packageManager.FindPackages("AppControlManager", "CN=SelfSignedCertForAppControlManager");

Package? PossibleExistingPackage = PossibleExistingApp.FirstOrDefault();
// Remove any certificates with the specified common name again
// Because the existing one contains private keys and we don't want that
CertificateGenerator.DeleteCertificateByCN(commonName);

// Get the version of the first matching package
string? InstalledAppVersionBefore = $"{PossibleExistingPackage?.Id.Version.Major}.{PossibleExistingPackage?.Id.Version.Minor}.{PossibleExistingPackage?.Id.Version.Build}.{PossibleExistingPackage?.Id.Version.Revision}";
// Adding the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with public key only.
// This safely stores the certificate on your device, ensuring its private key does not exist so cannot be used to sign anything else.
CertificateGenerator.StoreCertificateInStore(generatedCert, CertificateGenerator.CertificateStoreLocation.Machine, true);

// Get the architecture of the first matching package
string? InstalledAppArchitectureBefore = PossibleExistingPackage?.Id.Architecture.ToString();
try
{

Logger.Write($"Installing AppControl Manager MSIX package version '{InstallingAppVersion}' with architecture '{InstallingAppArchitecture}'");
// Execute the query to get the MpPreferences
using ManagementObjectSearcher searcher = new("ROOT\\Microsoft\\Windows\\Defender", $"SELECT AttackSurfaceReductionOnlyExclusions FROM MSFT_MpPreference");
ManagementObjectCollection results = searcher.Get();

// https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.addpackageoptions
AddPackageOptions options = new()
{
DeferRegistrationWhenPackagesAreInUse = true,
ForceUpdateFromAnyVersion = true
};
// Retrieve the property value for AttackSurfaceReductionOnlyExclusions
ManagementBaseObject? result = results.Cast<ManagementBaseObject>().FirstOrDefault();
string[]? currentAttackSurfaceReductionExclusions = result?["AttackSurfaceReductionOnlyExclusions"] as string[];

_ = packageManager.AddPackageByUriAsync(new Uri(AppControlManagerSavePath), options);
// If there are ASR rule exclusions, find ones that belong to AppControl Manager and remove them
// Before adding new ones for the new version
if (currentAttackSurfaceReductionExclusions is not null)
{

List<string> asrRulesToRemove = [];

// Remove any certificates with the specified common name again
// Because the existing one contains private keys and don't want that
CertificateGenerator.DeleteCertificateByCN(commonName);
// Find all the rules that belong to the AppControl Manager
foreach (string item in currentAttackSurfaceReductionExclusions)
{
if (MyRegex1().Match(item).Success)
{
asrRulesToRemove.Add(item);
}
}

// Adding the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with public key only. This safely stores the certificate on your device, ensuring its private key does not exist so cannot be used to sign anything else
CertificateGenerator.StoreCertificateInStore(generatedCert, CertificateGenerator.CertificateStoreLocation.Machine, true);
// If any of the rules belong to the AppControl Manager
if (asrRulesToRemove.Count > 0)
{
string[] stringArrayRepo = [.. asrRulesToRemove];

try
{
// Remove ASR rule exclusions that belong to all previous app versions
using ManagementClass managementClass = new(@"root\Microsoft\Windows\Defender", "MSFT_MpPreference", null);
ManagementBaseObject inParams = managementClass.GetMethodParameters("Remove");
inParams["AttackSurfaceReductionOnlyExclusions"] = stringArrayRepo;
_ = managementClass.InvokeMethod("Remove", inParams, null);
}
}

// Connect to the WMI namespace
// Connect to the WMI namespace again
ManagementScope scope = new(@"\\.\ROOT\Microsoft\Windows\Defender");
scope.Connect();

// Create an instance of the MSFT_MpPreference class for Add method
using ManagementClass mpPreferenceClass = new(scope, new ManagementPath("MSFT_MpPreference"), null);


// Construct the paths to the .exe and .dll files of the AppControl Manager
StringBuilder InstallingAppLocationToAdd = new();
_ = InstallingAppLocationToAdd.Append("C:\\Program Files\\WindowsApps\\AppControlManager_");
_ = InstallingAppLocationToAdd.Append(InstallingAppVersion);
Expand All @@ -323,50 +339,32 @@ await Task.Run(() =>
// Get the available methods for the class
ManagementBaseObject methodParams = mpPreferenceClass.GetMethodParameters("Add");

// Create a string array containing the paths which is what AttackSurfaceReductionOnlyExclusions accepts
methodParams["AttackSurfaceReductionOnlyExclusions"] = new string[] { path1, path2 };

// Invoke the method to apply the settings
// Invoke the Add method to add the paths to the ASR rules exclusions
_ = mpPreferenceClass.InvokeMethod("Add", methodParams, null);


// Remove ASR rule exclusions that belong to the previous app version if it existed
if (!string.IsNullOrWhiteSpace(InstalledAppVersionBefore) && !string.IsNullOrWhiteSpace(InstalledAppArchitectureBefore))
{

// Removing ASR Rules exclusions that belong to the previous app version.

StringBuilder InstalledAppLocationToRemove = new();
_ = InstalledAppLocationToRemove.Append("C:\\Program Files\\WindowsApps\\AppControlManager_");
_ = InstalledAppLocationToRemove.Append(InstalledAppVersionBefore);
_ = InstalledAppLocationToRemove.Append('_');
_ = InstalledAppLocationToRemove.Append(InstalledAppArchitectureBefore);
_ = InstalledAppLocationToRemove.Append("__sadt7br7jpt02\\");

// Create an instance of the MSFT_MpPreference class for Remove Method
using ManagementClass mpPreferenceClass2 = new(scope, new ManagementPath("MSFT_MpPreference"), null);


path1 = Path.Combine(InstalledAppLocationToRemove.ToString(), "AppControlManager.exe");
path2 = Path.Combine(InstalledAppLocationToRemove.ToString(), "AppControlManager.dll");


// Get the available methods for the class
ManagementBaseObject methodParams2 = mpPreferenceClass2.GetMethodParameters("Remove");

methodParams2["AttackSurfaceReductionOnlyExclusions"] = new string[] { path1, path2 };

// Invoke the method to apply the settings
_ = mpPreferenceClass2.InvokeMethod("Remove", methodParams2, null);

}

}

catch (Exception ex)
{
Logger.Write($"An error occurred while trying to add the ASR rule exclusions which you can ignore: {ex.Message}");
}


PackageManager packageManager = new();

Logger.Write($"Installing AppControl Manager MSIX package version '{InstallingAppVersion}' with architecture '{InstallingAppArchitecture}'");

// https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.addpackageoptions
AddPackageOptions options = new()
{
DeferRegistrationWhenPackagesAreInUse = true,
ForceUpdateFromAnyVersion = true
};

_ = packageManager.AddPackageByUriAsync(new Uri(AppControlManagerSavePath), options);

});

UpdateStatusInfoBar.Message = "Update has been successful. When you close and reopen the AppControl Manager, you will be automatically using the new version.";
Expand Down
2 changes: 1 addition & 1 deletion AppControl Manager/app.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- INFO: https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<!-- INFO (for legacy UWP but its info can be used for better understanding): https://learn.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/root-elements -->
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.8.2.0" name="AppControlManager"/>
<assemblyIdentity version="1.8.3.0" name="AppControlManager"/>

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
Expand Down

0 comments on commit 183f9e2

Please sign in to comment.