From 2499c4acbd96006cdf3b1b44ba9cd216be1c034a Mon Sep 17 00:00:00 2001 From: James Spencer Date: Sun, 17 Dec 2023 15:19:44 +1100 Subject: [PATCH] Tidy and document structures, document more fields from Consent/AppInfo --- .../ConsentUI/ConsentUIData.cs | 17 ++++- .../ConsentUI/ConsentUIDataExe.cs | 3 + .../ConsentUI/ConsentUIDataMsi.cs | 22 +++--- .../Enums/ConsentUIElevationType.cs | 24 +++++++ .../Enums/ConsentUIFlags.cs | 71 +++++++++++++++++++ .../Enums/ConsentUIMsiAction.cs | 11 +++ .../ConsentUIPromptType.cs} | 8 +-- .../Structs/ConsentUIStructureHeader.cs | 10 +-- .../Interop/Structs/ConsentUIStructureMsi.cs | 2 +- 9 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs create mode 100644 src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs create mode 100644 src/Lithnet.CredentialProvider/Enums/ConsentUIMsiAction.cs rename src/Lithnet.CredentialProvider/{ConsentUI/ElevationType.cs => Enums/ConsentUIPromptType.cs} (53%) diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs index 6c56ae8..de92d28 100644 --- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs +++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs @@ -34,14 +34,25 @@ namespace Lithnet.CredentialProvider /// /// Gets a value indicating the consent prompt type /// - public int PromptType => this.header.PromptType; + public ConsentUIPromptType PromptType => this.header.PromptType; /// /// Gets a handle to the Window that was responsible for invoking the ConsentUI prompt /// - public IntPtr HWnd => this.header.hWnd; + public IntPtr HWnd => this.header.hWindow; - public ElevationType ElevationType => this.header.elevationType; + /// + /// Gets the method that ConsentUI has been told to fetch approval. + /// In the case where a Credential Provider is initialised, this should always be `Credentials`. + /// + public ConsentUIElevationType ElevationType => this.header.ElevationType; + + /// + /// A series of flags that AppInfo passes to ConsentUI to signifiy actions that need to + /// take place on the UI side. + /// This includes specifics around the UI that should be presented & signature verification settings. + /// + public ConsentUIFlags Flags => this.header.Flags; /// /// Gets the ID of the session where the ConsentUI prompt was originally invoked diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs index 4d74baa..7a90c44 100644 --- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs +++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs @@ -9,6 +9,9 @@ namespace Lithnet.CredentialProvider /// public class ConsentUIDataExe : ConsentUIData { + /// + /// A file handle pointing to the EXE in question + /// private IntPtr hFile; /// diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs index 930412b..436999d 100644 --- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs +++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs @@ -9,6 +9,11 @@ namespace Lithnet.CredentialProvider /// public class ConsentUIDataMsi : ConsentUIData { + /// + /// The action being performed, such as Install, Uninstall or Repair + /// + public ConsentUIMsiAction Action { get; set; } + /// /// The name of the product being installed /// @@ -39,16 +44,6 @@ namespace Lithnet.CredentialProvider /// public string OriginalMsi { get; } - /// - /// A currently unknown parameter - /// - public string Unknown1 { get; } - - /// - /// A currently unknown parameter - /// - public string Unknown2 { get; } - internal ConsentUIDataMsi(IntPtr pData, int expectedSize) : base(pData, expectedSize) { if (this.header.Type != ConsentUIType.Msi) @@ -58,14 +53,13 @@ namespace Lithnet.CredentialProvider var s = Marshal.PtrToStructure(pData); + this.Action = s.MsiAction; this.ProductName = this.GetStringValueIfValid(pData, (int)s.oProductName); this.Version = this.GetStringValueIfValid(pData, (int)s.oVersion); this.Locale = this.GetStringValueIfValid(pData, (int)s.oLocale); this.Publisher = this.GetStringValueIfValid(pData, (int)s.oPublisher); - this.ExecutionPath = this.GetStringValueIfValid(pData, (int)s.oExecutionPath); - this.OriginalMsi = this.GetStringValueIfValid(pData, (int)s.oOriginalMsi); - this.Unknown1 = this.GetStringValueIfValid(pData, (int)s.oUnknown1); - this.Unknown2 = this.GetStringValueIfValid(pData, (int)s.oUnknown2); + this.ExecutionPath = this.GetStringValueIfValid(pData, (int)s.oExecutionPath); + this.OriginalMsi = this.GetStringValueIfValid(pData, (int)s.oOriginalMsi); } } } diff --git a/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs new file mode 100644 index 0000000..b01808b --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs @@ -0,0 +1,24 @@ +namespace Lithnet.CredentialProvider +{ + public enum ConsentUIElevationType + { + Unknown = 0, + + /// + /// Automatic Admin Mode. + /// This seems to be an instance where UAC creates a local, secondary + /// account called '%username%_admin' which is used to elevate a process. + /// + AutomaticAdmin = 1, + + /// + /// Prompt the user for consent (i.e. Yes or No) + /// + Consent = 2, + + /// + /// Prompt the user for credentials + /// + Credentials = 3 + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs new file mode 100644 index 0000000..08bda47 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs @@ -0,0 +1,71 @@ +using System; + +namespace Lithnet.CredentialProvider +{ + [Flags] + public enum ConsentUIFlags + { + SkipSignatureVerification = 0x01, + + /// + /// Indicates to ConsentUI that it needs to switch to the Secure Desktop + /// + SecureDesktop = 0x02, + + Unknown1 = 0x04, + Unknown2 = 0x08, + Unknown3 = 0x10, + + /// + /// This flag seems to cause ConsentUI to + /// skip all signature verification related code. + /// + SkipVerification = 0x20, + + /// + /// Indicates that the executable file is contained within a Windows directory. + /// As all the executables in System32, etc. are unsigned, ConsentUI + /// uses this to toggle catalog verification, if required. + /// + InWindowsDirectory = 0x40, + + /// + /// Seems to indicates to ConsentUI that automatic elevation should occur, + /// and that the executable is in a safe Windows location + /// + AutoElevationWindows = 0x80, + + /// + /// Like `AutoElevationWindows`, this seems indicates to ConsentUI that + /// automatic elevation should occur, but that further verification + /// inside ConsentUI should occur. + /// + AutoElevationOther = 0x100, + + Unknown4 = 0x200, + + /// + /// ConsentUI uses this flag to determine if it should pass + /// SIF_BASE_VERIFICATION | SIF_AUTHENTICODE_SIGNED to WTGetSignatureInfo + /// + PerformBaseVerification = 0x400, + + /// + /// Indicates that the publisher is untrusted - this is what seems to trigger + /// an AMSI scan (i.e., SmartScreen) + /// + UntrustedPublisher = 0x800, + + /// + /// This flag seems to cause ConsentUI to skip all elevation-related code and exit. + /// + BlockElevation = 0x1000, + + /// + /// Corresponds to `ConsentUIElevationType.AutomaticAdmin` + /// This seems to be an instance where UAC creates a local, secondary + /// account called '%username%_admin' which is used to elevate a process. + /// + AutomaticAdminMode = 0x2000 + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/ConsentUIMsiAction.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIMsiAction.cs new file mode 100644 index 0000000..24e7ad1 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIMsiAction.cs @@ -0,0 +1,11 @@ +using System; + +namespace Lithnet.CredentialProvider +{ + public enum ConsentUIMsiAction : uint + { + Install = 0, + Uninstall = 1, + Update = 2 + } +} diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ElevationType.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIPromptType.cs similarity index 53% rename from src/Lithnet.CredentialProvider/ConsentUI/ElevationType.cs rename to src/Lithnet.CredentialProvider/Enums/ConsentUIPromptType.cs index 39770de..eee927a 100644 --- a/src/Lithnet.CredentialProvider/ConsentUI/ElevationType.cs +++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIPromptType.cs @@ -1,10 +1,10 @@ namespace Lithnet.CredentialProvider { - public enum ElevationType + public enum ConsentUIPromptType { - Unknown1 = 0, - Unknown2 = 1, + Unknown = 0, + AutomaticAdmin = 1, Consent = 2, Credentials = 3 } -} \ No newline at end of file +} diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs index e84af60..f016be1 100644 --- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs +++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs @@ -8,24 +8,24 @@ namespace Lithnet.CredentialProvider.Interop { public int Size; // 4 public ConsentUIType Type; // 4 - public int PromptType; // 4 + public ConsentUIPromptType PromptType; // 4 // padding on x64 - 4 // 16 - public IntPtr hWnd; // 8 + public IntPtr hWindow; // 8 public IntPtr hToken; // 8 // 32 - public ElevationType elevationType; // 4 + public ConsentUIElevationType ElevationType; // 4 public int sessionId; // 4 public IntPtr hMutex; // 8 // 48+ - public int unknownFlags1; // 4 - public int unknownFlags2; // 4 + public ConsentUIFlags Flags; // 4 + public int unknown0; // 4 public IntPtr pReturnAddress; // 8 // 64 diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs index 85b7ab3..b7a04bc 100644 --- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs +++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs @@ -10,7 +10,7 @@ namespace Lithnet.CredentialProvider.Interop // 64 - public IntPtr hUnknown1; // 8 + public ConsentUIMsiAction MsiAction; // 8 public IntPtr oProductName; // 8 // 64 + 16 == 80