Skip to content

Commit

Permalink
Adding support for custom file path rule creation (#624)
Browse files Browse the repository at this point in the history
File path rules now work for non-admin protected folders such as Desktop folder. In the Create Supplemental Policy page, if the scan level is set to File Path or Wildcard File Path, a new rule option called Disabled:Runtime FilePath Rule Protection will be added so that you can use file path rules to allow files in non-admin protected paths to run.

Added a deploy toggle button to the Configure policy rule options page. Related discussion

File Publisher and Hash rule types created in the XML file will no longer have the file path in the FriendlyName field. This is to make the generated policy more generic for mass deployments. Related discussion

Added the ability to create custom pattern-based file-rule-based Supplemental and Deny policies. Related feature request. You can use this feature to create sophisticated allow/deny rules for very dynamic situations.

Bumped version to 1.9.3.0

Added toggle buttons to the Create AppControl Policy that allows you to create/deploy the base policies without creation/deploying the Microsoft recommended (user-mode) block rules.

Improved the resiliency of installed packaged apps list retrieval.

In the Configure Policy Rule Options page, when you assign an XML file path to the page using the Sidebar button, its rule options will be automatically retrieved and displayed to you. Previously this would only work when you used the Browse button in the page itself.

Some of the info bars in the Create Supplemental Policy page weren't closable at the end of the operation, that's fixed now.

All CIP files generated for supplemental and deny policies have the same file name that you select as policy name, making it easier to identify them in the user configurations directory. Previously the CIP files would have the ID (GUID format) which made it hard to recognize which XML or policy they belonged to.

Made the same change to the Allow New Apps page at the final step (Step 3) when you create to deploy the supplemental policy.
When creating Supplemental or Deny policies, if you choose to deploy them, only the XML policy file will exist in the AppControl Manager directory in Program Files, but if you do not toggle the Deploy button, then the CIP file will also exist in the AppControl Manager directory. This makes it easier for you to use the CIP file on another system. Both the XML and CIP files will have the same name, easy to recognize, and it's the same name you select for the policy.

Made the same change to the Allow New Apps page at the final step (Step 3) when you create to deploy the supplemental policy.
When user is already inside of the scan results pages for supplemental and deny policies, the total logs/files count is now updated in real time.
  • Loading branch information
HotCakeX authored Feb 27, 2025
1 parent 5bbd3cc commit 0f31220
Show file tree
Hide file tree
Showing 27 changed files with 1,155 additions and 333 deletions.
2 changes: 1 addition & 1 deletion AppControl Manager/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
private Window? m_window;

// Adding this public property to expose the window
public static Window? MainWindow => ((App)Current).m_window;
internal static Window? MainWindow => ((App)Current).m_window;

/// <summary>
/// Event handler for unhandled exceptions.
Expand Down
4 changes: 2 additions & 2 deletions AppControl Manager/AppControl Manager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>

<!-- Publish Properties -->
<PublishReadyToRun>True</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">true</PublishReadyToRun>

<ImplicitUsings>disable</ImplicitUsings>
<Description>A modern secure application that simplifies management of Application Control in Windows.</Description>
Expand Down Expand Up @@ -79,7 +79,7 @@
<PublishAot>True</PublishAot>
<OptimizationPreference>Speed</OptimizationPreference>
<ErrorReport>send</ErrorReport>
<FileVersion>1.9.2.0</FileVersion>
<FileVersion>1.9.3.0</FileVersion>
<AssemblyVersion>$(FileVersion)</AssemblyVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
Expand Down
102 changes: 102 additions & 0 deletions AppControl Manager/CustomUIElements/CustomPatternBasedFilePath.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<ContentDialog
x:Class="AppControlManager.CustomUIElements.CustomPatternBasedFilePath"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppControlManager.CustomUIElements"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:CommunityToolkit.WinUI.Behaviors"
mc:Ignorable="d"
Title="Pattern Based File Path"
CloseButtonText="OK"
IsPrimaryButtonEnabled="False"
DefaultButton="Primary"
BorderThickness="1"
CornerRadius="8"
Style="{ThemeResource DefaultContentDialogStyle}"
BorderBrush="{ThemeResource AccentFillColorDefaultBrush}">

<ContentDialog.Resources>
<!-- https://github.com/microsoft/microsoft-ui-xaml/issues/424 -->
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
</ContentDialog.Resources>

<Grid>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<controls:WrapPanel Orientation="Vertical" Margin="0,0,0,15" Grid.Row="0" HorizontalSpacing="10" VerticalSpacing="10">

<TextBlock IsTextSelectionEnabled="True" TextWrapping="Wrap" VerticalAlignment="Top" Text="Here are some examples of custom patterns for file path rules" />

<HyperlinkButton Content="More Info" NavigateUri="https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/select-types-of-rules-to-create#using-wildcards-in-app-control-filepath-rules" />

</controls:WrapPanel>

<ListView x:Name="CustomPatternBasedFilePathListView"
Grid.Row="1"
SelectionMode="None"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.IsHorizontalRailEnabled="True"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ShowsScrollingPlaceholders="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Margin="0,0,0,15">

<ListView.Header>

<Border CornerRadius="5" Background="Black">
<interactivity:Interaction.Behaviors>
<behaviors:StickyHeaderBehavior />
</interactivity:Interaction.Behaviors>
<Grid>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="400" />
<ColumnDefinition Width="400" />
</Grid.ColumnDefinitions>
<TextBlock Text="Example" Foreground="LightGray" HorizontalAlignment="Stretch" Grid.Column="0" FontWeight="Bold" Margin="10,0,2,0" Padding="5"/>
<TextBlock Text="Description" Foreground="LightGray" HorizontalAlignment="Stretch" Grid.Column="1" FontWeight="Bold" Margin="10,0,2,0" Padding="5"/>
</Grid>
</Border>
</ListView.Header>

<!-- DataTemplate for ListView items -->
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:FilePathPatternExample">
<!-- Setting Background="Transparent" on the Grid makes it hit-test visible, meaning that even areas without any child elements (like empty spaces in the column) will respond to pointer events. -->
<Grid Background="Transparent">

<Grid.ColumnDefinitions>
<ColumnDefinition Width="400" />
<ColumnDefinition Width="400" />
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Example}" HorizontalAlignment="Left" Grid.Column="0" Margin="0,10,2,10" TextWrapping="WrapWholeWords" IsTextSelectionEnabled="True"/>
<TextBlock Text="{x:Bind Description}" HorizontalAlignment="Left" Grid.Column="1" TextWrapping="WrapWholeWords" Margin="0,10,2,10" IsTextSelectionEnabled="True"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

<TextBlock IsTextSelectionEnabled="True" Margin="0,0,0,15" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top">
<Bold><Run Foreground="DeepPink" FontSize="18">*</Run></Bold>
<Span>Matches zero or more characters.</Span>
</TextBlock>

<TextBlock IsTextSelectionEnabled="True" Margin="0,0,0,15" Grid.Row="3" TextWrapping="Wrap" VerticalAlignment="Top">
<Bold><Run Foreground="DeepPink" FontSize="18">?</Run></Bold>
<Span>Matches a single character.</Span>
</TextBlock>

</Grid>

</ContentDialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.ObjectModel;
using Microsoft.UI.Xaml.Controls;

namespace AppControlManager.CustomUIElements;

// https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.contentdialog
internal sealed partial class CustomPatternBasedFilePath : ContentDialog
{

internal static readonly ObservableCollection<FilePathPatternExample> FilePathPatternExamplesCollection = [

new()
{
Example = "C:\\Windows\\*",
Description = "Matches all files in the 'C:\\Windows' directory and its sub-directories."
},
new()
{
Example = "D:\\EnterpriseApps\\MyApp\\*",
Description = "Matches all files in the 'D:\\EnterpriseApps\\MyApp\\' directory and its sub-directories."
},
new()
{
Example = "*\\Bing.exe",
Description = "Matches any file(s) named 'Bing.exe' in any location."
},
new()
{
Example = "C:\\*\\CCMCACHE\\*\\7z????-x64.exe",
Description = "Wildcards used in the middle of a path allow all files that match that pattern. In this example, both of these hypothetical paths would match: 'C:\\WINDOWS\\CCMCACHE\\12345\\7zabcd-x64.exe' and 'C:\\USERS\\AppControlUSER\\Downloads\\Malware\\CCMCACHE\\Pwned\\7zhaha-x64.exe'"
},
new()
{
Example = "C:\\Users\\UserName\\AppData\\Local\\Temp\\????????-????-????-????-????????????.tmp.node\"",
Description = "This example allows any '.node' temporary file inside of the TEMP folder that has a GUID as file name."
}
];

internal CustomPatternBasedFilePath()
{
this.InitializeComponent();

XamlRoot = App.MainWindow?.Content.XamlRoot;

CustomPatternBasedFilePathListView.ItemsSource = FilePathPatternExamplesCollection;
}
}

internal sealed class FilePathPatternExample
{
public string? Example;
public string? Description;
}
3 changes: 2 additions & 1 deletion AppControl Manager/IntelGathering/ScanLevels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public enum ScanLevels
Hash,
FilePath,
WildCardFolderPath,
PFN
PFN,
CustomFileRulePattern
}
12 changes: 6 additions & 6 deletions AppControl Manager/Main/BasePolicyCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ internal static void GetDriversBlockRules(string StagingArea)
/// <param name="RequireEVSigners"></param>
/// <param name="EnableScriptEnforcement"></param>
/// <param name="TestMode"></param>
internal static void BuildAllowMSFT(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null)
internal static void BuildAllowMSFT(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null, bool DeployMicrosoftRecommendedBlockRules = true)
{

string policyName;
Expand All @@ -414,7 +414,7 @@ internal static void BuildAllowMSFT(string StagingArea, bool IsAudit, ulong? Log
string finalPolicyPath = Path.Combine(GlobalVars.UserConfigDir, $"{policyName}.xml");

// Get/Deploy the block rules if this base policy is not being swapped
if (PolicyIDToUse is null)
if (PolicyIDToUse is null && DeployMicrosoftRecommendedBlockRules)
GetBlockRules(StagingArea, deploy);

Logger.Write("Copying the AllowMicrosoft.xml from Windows directory to the Staging Area");
Expand Down Expand Up @@ -476,7 +476,7 @@ internal static void BuildAllowMSFT(string StagingArea, bool IsAudit, ulong? Log
/// <param name="RequireEVSigners"></param>
/// <param name="EnableScriptEnforcement"></param>
/// <param name="TestMode"></param>
internal static void BuildDefaultWindows(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null)
internal static void BuildDefaultWindows(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null, bool DeployMicrosoftRecommendedBlockRules = true)
{

string policyName;
Expand All @@ -500,7 +500,7 @@ internal static void BuildDefaultWindows(string StagingArea, bool IsAudit, ulong
string finalPolicyPath = Path.Combine(GlobalVars.UserConfigDir, $"{policyName}.xml");

// Get/Deploy the block rules if this base policy is not being swapped
if (PolicyIDToUse is null)
if (PolicyIDToUse is null && DeployMicrosoftRecommendedBlockRules)
GetBlockRules(StagingArea, deploy);

Logger.Write("Copying the DefaultWindows.xml from Windows directory to the Staging Area");
Expand Down Expand Up @@ -658,7 +658,7 @@ internal static void GetBlockRules(string StagingArea, bool deploy)
/// <param name="RequireEVSigners"></param>
/// <param name="EnableScriptEnforcement"></param>
/// <param name="TestMode"></param>
internal static void BuildSignedAndReputable(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null)
internal static void BuildSignedAndReputable(string StagingArea, bool IsAudit, ulong? LogSize, bool deploy, bool RequireEVSigners, bool EnableScriptEnforcement, bool TestMode, bool? deployAppControlSupplementalPolicy, string? PolicyIDToUse = null, bool DeployMicrosoftRecommendedBlockRules = true)
{

string policyName;
Expand All @@ -682,7 +682,7 @@ internal static void BuildSignedAndReputable(string StagingArea, bool IsAudit, u
string finalPolicyPath = Path.Combine(GlobalVars.UserConfigDir, $"{policyName}.xml");

// Get/Deploy the block rules if this base policy is not being swapped
if (PolicyIDToUse is null)
if (PolicyIDToUse is null && DeployMicrosoftRecommendedBlockRules)
GetBlockRules(StagingArea, deploy);

Logger.Write("Copying the AllowMicrosoft.xml from Windows directory to the Staging Area");
Expand Down
99 changes: 99 additions & 0 deletions AppControl Manager/Others/GetAppsList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.Management.Deployment;

namespace AppControlManager.Others;

internal static class GetAppsList
{

// Package Manager object used by the PFN section
private static readonly PackageManager packageManager = new();

/// <summary>
/// Gets the list of all installed Packaged Apps
/// </summary>
/// <returns></returns>
private static async Task<List<PackagedAppView>> Get()
{
return await Task.Run(() =>
{
// The list to return as output
List<PackagedAppView> apps = [];

// Get all of the packages on the system
IEnumerable<Package> allApps = packageManager.FindPackages();

// Loop over each package
foreach (Package item in allApps)
{
try
{
// Try get the logo string
string? logoStr = item.Logo?.ToString();

// Validate that the logo string is a valid absolute URI
if (!Uri.TryCreate(logoStr, UriKind.Absolute, out _))
{
// If invalid, assign a fallback logo
logoStr = GlobalVars.FallBackAppLogoURI;
}

// Create a new instance of the class that displays each app in the ListView
apps.Add(new PackagedAppView(
displayName: item.DisplayName,
version: $"Version: {item.Id.Version.Major}.{item.Id.Version.Minor}.{item.Id.Version.Build}.{item.Id.Version.Revision}",
packageFamilyName: $"PFN: {item.Id.FamilyName}",
logo: logoStr,
packageFamilyNameActual: item.Id.FamilyName
));
}
catch (Exception ex)
{
try
{
Logger.Write($"There was an error getting the details for the app: {item.Id.FamilyName}");
}
catch
{
Logger.Write("There was an error getting the details of an app");
}
Logger.Write(ErrorWriter.FormatException(ex));
}
}

return apps;
});

}


// To create a collection of grouped items, create a query that groups
// an existing list, or returns a grouped collection from a database.
// The following method is used to create the ItemsSource for our CollectionViewSource that is defined in XAML
internal static async Task<ObservableCollection<GroupInfoListForPackagedAppView>> GetContactsGroupedAsync()
{
// Grab Apps objects from pre-existing list
IEnumerable<GroupInfoListForPackagedAppView> query = from item in await Get()

// Ensure DisplayName is not null before grouping
// This also prevents apps without a DisplayName to exist in the returned apps list
where !string.IsNullOrWhiteSpace(item.DisplayName)

// Group the items returned from the query, sort and select the ones you want to keep
group item by item.DisplayName[..1].ToUpper() into g
orderby g.Key

// GroupInfoListForPackagedAppView is a simple custom class that has an IEnumerable type attribute, and
// a key attribute. The IGrouping-typed variable g now holds the App objects,
// and these objects will be used to create a new GroupInfoListForPackagedAppView object.
select new GroupInfoListForPackagedAppView(g) { Key = g.Key };

return [.. query];
}

}
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.9.2.0" />
Version="1.9.3.0" />

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

Expand Down
Loading

0 comments on commit 0f31220

Please sign in to comment.