diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Helpers.cs b/src/Lithnet.CredentialProvider.UnitTests.x64/Helpers.cs
new file mode 100644
index 0000000..4b7328e
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x64/Helpers.cs
@@ -0,0 +1,19 @@
+using System.IO;
+using System.Runtime.InteropServices;
+using Lithnet.CredentialProvider.Interop;
+using NUnit.Framework;
+
+namespace Lithnet.CredentialProvider.UnitTests
+{
+ internal static class Helpers
+ {
+ public static SafeHGlobalHandle ReadFile(string filename)
+ {
+ var data = File.ReadAllBytes(Path.Combine(TestContext.CurrentContext.TestDirectory, filename));
+ var p = SafeHGlobalHandle.AllocHGlobal(data.Length);
+ Marshal.Copy(data, 0, p.ToIntPtr(), data.Length);
+
+ return p;
+ }
+ }
+}
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Lithnet.CredentialProvider.UnitTests.x64.csproj b/src/Lithnet.CredentialProvider.UnitTests.x64/Lithnet.CredentialProvider.UnitTests.x64.csproj
new file mode 100644
index 0000000..86fc565
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x64/Lithnet.CredentialProvider.UnitTests.x64.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0-windows;net7.0-windows;net8.0-windows;net461;net48
+ false
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-com-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-com-x64.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-com-x64.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-com-x64.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-exe-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-exe-x64.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-exe-x64.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-exe-x64.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msi-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-msi-x64.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msi-x64.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-msi-x64.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msix-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-msix-x64.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msix-x64.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V1/dump-consent-msix-x64.dat
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-com-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-com-x64.dat
new file mode 100644
index 0000000..ad14352
Binary files /dev/null and b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-com-x64.dat differ
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-exe-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-exe-x64.dat
new file mode 100644
index 0000000..e250d05
Binary files /dev/null and b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-exe-x64.dat differ
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msi-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msi-x64.dat
new file mode 100644
index 0000000..64c404d
Binary files /dev/null and b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msi-x64.dat differ
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msix-x64.dat b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msix-x64.dat
new file mode 100644
index 0000000..e7687e9
Binary files /dev/null and b/src/Lithnet.CredentialProvider.UnitTests.x64/Samples/V2/dump-consent-msix-x64.dat differ
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/V1HeaderTests.cs b/src/Lithnet.CredentialProvider.UnitTests.x64/V1HeaderTests.cs
new file mode 100644
index 0000000..abf486c
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x64/V1HeaderTests.cs
@@ -0,0 +1,96 @@
+using System;
+using Lithnet.CredentialProvider.Interop;
+using NUnit.Framework;
+
+namespace Lithnet.CredentialProvider.UnitTests
+{
+ public class V1HeaderTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ ConsentUIData.HeaderSize = ConsentUIData.v1HeaderSize;
+ }
+
+ [Test]
+ public void TestExe()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-exe-x64.dat");
+
+ var d = new ConsentUIDataExe(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Exe, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(3, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0000000000010128, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Request, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.ExecutablePath);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.Unknown1);
+ Assert.AreEqual("\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" ARGS1 ARGS2", d.CommandLine);
+ Assert.AreEqual("", d.Unknown2);
+ }
+
+ [Test]
+ public void TestMsi()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-msi-x64.dat");
+
+ var d = new ConsentUIDataMsi(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msi, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther, d.Flags);
+ Assert.AreEqual(3, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0000000000230370, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msi, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("7-Zip 23.01 (x64 edition)", d.ProductName);
+ Assert.AreEqual(ConsentUIMsiAction.Install, d.Action);
+ Assert.AreEqual("C:\\Windows\\Installer\\b733392.msi", d.ExecutionPath);
+ Assert.AreEqual("1033", d.Locale);
+ Assert.AreEqual("C:\\Users\\ryan2\\Downloads\\7z2301-x64.msi", d.OriginalMsi);
+ Assert.AreEqual("7-Zip 23.01 (x64 edition)", d.ProductName);
+ Assert.AreEqual("Igor Pavlov", d.Publisher);
+ Assert.AreEqual("23.01.00.0", d.Version);
+ }
+
+ [Test]
+ public void TestMsix()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-msix-x64.dat");
+
+ var d = new ConsentUIDataMsix(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msix, d.Type);
+ Assert.AreEqual( ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(3, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msix, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("\"C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2023.807.0_x64__8wekyb3d8bbwe\\MsixPackageTool.exe\" ", d.CommandLine);
+ Assert.AreEqual("C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2023.807.0_x64__8wekyb3d8bbwe\\MsixPackageTool.exe", d.ExecutablePath);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe!Msix.App", d.OtherName);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe", d.PackageName);
+ }
+
+ [Test]
+ public void TestCom()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-com-x64.dat");
+
+ var d = new ConsentUIDataCom(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Com, d.Type);
+ Assert.AreEqual(ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther | ConsentUIFlags.InWindowsDirectory, d.Flags);
+ Assert.AreEqual(3, d.SessionId);
+ Assert.AreEqual((IntPtr)0x00000000000903c2, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Clsid, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual(new Guid("{3ad05575-8857-4850-9277-11b85bdb8e09}"), d.ClsId);
+ Assert.AreEqual("C:\\Windows\\system32\\windows.storage.dll", d.ComComponentPath);
+ Assert.AreEqual("", d.ImageResourcePath);
+ Assert.AreEqual("File Operation", d.OperationType);
+ Assert.AreEqual("C:\\Windows\\Explorer.EXE", d.ProcessPath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x64/V2HeaderTests.cs b/src/Lithnet.CredentialProvider.UnitTests.x64/V2HeaderTests.cs
new file mode 100644
index 0000000..d32e3f3
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x64/V2HeaderTests.cs
@@ -0,0 +1,97 @@
+using System;
+using Lithnet.CredentialProvider.Interop;
+using NUnit.Framework;
+
+namespace Lithnet.CredentialProvider.UnitTests
+{
+ public class V2HeaderTests
+ {
+
+ [SetUp]
+ public void Setup()
+ {
+ ConsentUIData.HeaderSize = ConsentUIData.v2HeaderSize;
+ }
+
+ [Test]
+ public void TestExe()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V2\\dump-consent-exe-x64.dat");
+
+ ConsentUIDataExe d = new ConsentUIDataExe(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Exe, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(3, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0, d.HWnd); // this seems odd
+ Assert.AreEqual(ConsentUIElevationReason.Request, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.ExecutablePath);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.Unknown1);
+ Assert.AreEqual("\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" ", d.CommandLine);
+ Assert.AreEqual("", d.Unknown2);
+ }
+
+ [Test]
+ public void TestMsi()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V2\\dump-consent-msi-x64.dat");
+
+ var d = new ConsentUIDataMsi(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msi, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x00000000001e033a, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msi, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("7-Zip 24.08 (x64 edition)", d.ProductName);
+ Assert.AreEqual(ConsentUIMsiAction.Install, d.Action);
+ Assert.AreEqual("C:\\WINDOWS\\Installer\\58ca98.msi", d.ExecutionPath);
+ Assert.AreEqual("1033", d.Locale);
+ Assert.AreEqual("C:\\Users\\testuser\\Downloads\\7z2408-x64.msi", d.OriginalMsi);
+ Assert.AreEqual("7-Zip 24.08 (x64 edition)", d.ProductName);
+ Assert.AreEqual("Igor Pavlov", d.Publisher);
+ Assert.AreEqual("24.08.00.0", d.Version);
+ }
+
+ [Test]
+ public void TestMsix()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V2\\dump-consent-msix-x64.dat");
+
+ var d = new ConsentUIDataMsix(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msix, d.Type);
+ Assert.AreEqual(ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msix, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("\"C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2024.405.0_x64__8wekyb3d8bbwe\\MsixPackageTool.exe\" ", d.CommandLine);
+ Assert.AreEqual("C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2024.405.0_x64__8wekyb3d8bbwe\\MsixPackageTool.exe", d.ExecutablePath);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe!Msix.App", d.OtherName);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe", d.PackageName);
+ }
+
+ [Test]
+ public void TestCom()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V2\\dump-consent-com-x64.dat");
+
+ var d = new ConsentUIDataCom(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Com, d.Type);
+ Assert.AreEqual(ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther | ConsentUIFlags.InWindowsDirectory, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x00000000000d021e, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Clsid, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual(new Guid("{3ad05575-8857-4850-9277-11b85bdb8e09}"), d.ClsId);
+ Assert.AreEqual("C:\\WINDOWS\\system32\\windows.storage.dll", d.ComComponentPath);
+ Assert.AreEqual("", d.ImageResourcePath);
+ Assert.AreEqual("File Operation", d.OperationType);
+ Assert.AreEqual("C:\\WINDOWS\\Explorer.EXE", d.ProcessPath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x86/Helpers.cs b/src/Lithnet.CredentialProvider.UnitTests.x86/Helpers.cs
new file mode 100644
index 0000000..4b7328e
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x86/Helpers.cs
@@ -0,0 +1,19 @@
+using System.IO;
+using System.Runtime.InteropServices;
+using Lithnet.CredentialProvider.Interop;
+using NUnit.Framework;
+
+namespace Lithnet.CredentialProvider.UnitTests
+{
+ internal static class Helpers
+ {
+ public static SafeHGlobalHandle ReadFile(string filename)
+ {
+ var data = File.ReadAllBytes(Path.Combine(TestContext.CurrentContext.TestDirectory, filename));
+ var p = SafeHGlobalHandle.AllocHGlobal(data.Length);
+ Marshal.Copy(data, 0, p.ToIntPtr(), data.Length);
+
+ return p;
+ }
+ }
+}
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x86/Lithnet.CredentialProvider.UnitTests.x86.csproj b/src/Lithnet.CredentialProvider.UnitTests.x86/Lithnet.CredentialProvider.UnitTests.x86.csproj
new file mode 100644
index 0000000..31f57a7
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x86/Lithnet.CredentialProvider.UnitTests.x86.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0-windows;net7.0-windows;net8.0-windows;net461;net48
+ false
+ x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-com-x86.dat b/src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-com-x86.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-com-x86.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-com-x86.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-exe-x86.dat b/src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-exe-x86.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-exe-x86.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-exe-x86.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msi-x86.dat b/src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-msi-x86.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msi-x86.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-msi-x86.dat
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msix-x86.dat b/src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-msix-x86.dat
similarity index 100%
rename from src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-msix-x86.dat
rename to src/Lithnet.CredentialProvider.UnitTests.x86/Samples/V1/dump-consent-msix-x86.dat
diff --git a/src/Lithnet.CredentialProvider.UnitTests.x86/V1HeaderTests.cs b/src/Lithnet.CredentialProvider.UnitTests.x86/V1HeaderTests.cs
new file mode 100644
index 0000000..b2ad989
--- /dev/null
+++ b/src/Lithnet.CredentialProvider.UnitTests.x86/V1HeaderTests.cs
@@ -0,0 +1,96 @@
+using System;
+using Lithnet.CredentialProvider.Interop;
+using NUnit.Framework;
+
+namespace Lithnet.CredentialProvider.UnitTests
+{
+ public class V1HeaderTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ ConsentUIData.HeaderSize = ConsentUIData.v1HeaderSize;
+ }
+
+ [Test]
+ public void TestExe()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-exe-x86.dat");
+
+ var d = new ConsentUIDataExe(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Exe, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0006056a, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Request, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.ExecutablePath);
+ Assert.AreEqual("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", d.Unknown1);
+ Assert.AreEqual("\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" ARGS1 ARGS2", d.CommandLine);
+ Assert.AreEqual("", d.Unknown2);
+ }
+
+ [Test]
+ public void TestMsi()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-msi-x86.dat");
+
+ var d = new ConsentUIDataMsi(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msi, d.Type);
+ Assert.AreEqual(ConsentUIFlags.InWindowsDirectory | ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x000705bc, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msi, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("7-Zip 23.01", d.ProductName);
+ Assert.AreEqual(ConsentUIMsiAction.Install, d.Action);
+ Assert.AreEqual("C:\\Windows\\Installer\\26396d5.msi", d.ExecutionPath);
+ Assert.AreEqual("1033", d.Locale);
+ Assert.AreEqual("C:\\Users\\std\\Downloads\\7z2301.msi", d.OriginalMsi);
+ Assert.AreEqual("7-Zip 23.01", d.ProductName);
+ Assert.AreEqual("Igor Pavlov", d.Publisher);
+ Assert.AreEqual("23.01.00.0", d.Version);
+ }
+
+ [Test]
+ public void TestMsix()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-msix-x86.dat");
+
+ var d = new ConsentUIDataMsix(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Msix, d.Type);
+ Assert.AreEqual( ConsentUIFlags.SecureDesktop | ConsentUIFlags.Unknown3, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x0, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Msix, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual("\"C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2023.807.0_x86__8wekyb3d8bbwe\\MsixPackageTool.exe\" ", d.CommandLine);
+ Assert.AreEqual("C:\\Program Files\\WindowsApps\\Microsoft.MSIXPackagingTool_1.2023.807.0_x86__8wekyb3d8bbwe\\MsixPackageTool.exe", d.ExecutablePath);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe!Msix.App", d.OtherName);
+ Assert.AreEqual("Microsoft.MSIXPackagingTool_8wekyb3d8bbwe", d.PackageName);
+ }
+
+ [Test]
+ public void TestCom()
+ {
+ SafeHGlobalHandle p = Helpers.ReadFile($"Samples\\V1\\dump-consent-com-x86.dat");
+
+ var d = new ConsentUIDataCom(p.ToIntPtr(), p.Size);
+
+ Assert.AreEqual(ConsentUIType.Com, d.Type);
+ Assert.AreEqual(ConsentUIFlags.SecureDesktop | ConsentUIFlags.AutoElevationOther | ConsentUIFlags.InWindowsDirectory, d.Flags);
+ Assert.AreEqual(2, d.SessionId);
+ Assert.AreEqual((IntPtr)0x000b0586, d.HWnd);
+ Assert.AreEqual(ConsentUIElevationReason.Clsid, d.ElevationReason);
+ Assert.AreEqual(ConsentUIPromptType.Credentials, d.PromptType);
+ Assert.AreEqual(new Guid("{3ad05575-8857-4850-9277-11b85bdb8e09}"), d.ClsId);
+ Assert.AreEqual("C:\\Windows\\system32\\windows.storage.dll", d.ComComponentPath);
+ Assert.AreEqual("", d.ImageResourcePath);
+ Assert.AreEqual("File Operation", d.OperationType);
+ Assert.AreEqual("C:\\Windows\\Explorer.EXE", d.ProcessPath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Lithnet.CredentialProvider.sln b/src/Lithnet.CredentialProvider.sln
index 52e6520..4460844 100644
--- a/src/Lithnet.CredentialProvider.sln
+++ b/src/Lithnet.CredentialProvider.sln
@@ -23,6 +23,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.TestApp.x86", "samples\Lithnet.CredentialProvider.TestApp.x86\Lithnet.CredentialProvider.TestApp.x86.csproj", "{F39C84F2-60C2-45EB-BC87-0ED095D41C96}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lithnet.CredentialProvider.UnitTests.x64", "Lithnet.CredentialProvider.UnitTests.x64\Lithnet.CredentialProvider.UnitTests.x64.csproj", "{21E66D65-6E3F-4ACA-B1D0-CA4CC7C58D0C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lithnet.CredentialProvider.UnitTests.x86", "Lithnet.CredentialProvider.UnitTests.x86\Lithnet.CredentialProvider.UnitTests.x86.csproj", "{DA23151B-B7B6-4942-B7A4-48E1918EF145}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -57,6 +61,14 @@ Global
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F39C84F2-60C2-45EB-BC87-0ED095D41C96}.Release|Any CPU.Build.0 = Release|Any CPU
+ {21E66D65-6E3F-4ACA-B1D0-CA4CC7C58D0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {21E66D65-6E3F-4ACA-B1D0-CA4CC7C58D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {21E66D65-6E3F-4ACA-B1D0-CA4CC7C58D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {21E66D65-6E3F-4ACA-B1D0-CA4CC7C58D0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA23151B-B7B6-4942-B7A4-48E1918EF145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA23151B-B7B6-4942-B7A4-48E1918EF145}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA23151B-B7B6-4942-B7A4-48E1918EF145}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA23151B-B7B6-4942-B7A4-48E1918EF145}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs
index de92d28..34fe588 100644
--- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs
+++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIData.cs
@@ -23,8 +23,12 @@ namespace Lithnet.CredentialProvider
{
private static bool? isConsentUI;
private static ConsentUICommandLineArgs commandLineArgs;
- private protected ConsentUIStructureHeader header;
+ private protected ConsentUIStructureHeaderBase header;
private readonly byte[] rawData;
+ private static readonly Version v2HeaderOsVersion = new Version(10, 0, 26100, 0);
+ internal static int v2HeaderSize = Marshal.SizeOf();
+ internal static int v1HeaderSize = Marshal.SizeOf();
+ internal static int HeaderSize { get; set; } = Environment.OSVersion.Version >= v2HeaderOsVersion ? v2HeaderSize : v1HeaderSize;
///
/// Gets a value indicating the type of ConsentUI data structure
@@ -32,7 +36,8 @@ namespace Lithnet.CredentialProvider
public ConsentUIType Type => this.header.Type;
///
- /// Gets a value indicating the consent prompt type
+ /// Gets a value indicating how UAC has been told to fetch approval.
+ /// In the case where a Credential Provider is initialised, this should always be `Credentials`.
///
public ConsentUIPromptType PromptType => this.header.PromptType;
@@ -42,13 +47,13 @@ namespace Lithnet.CredentialProvider
public IntPtr HWnd => this.header.hWindow;
///
- /// 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`.
+ /// Gets the reason why `consent.exe` was started in the first place. In other words,
+ /// the type of action that led to an elevation request.
///
- public ConsentUIElevationType ElevationType => this.header.ElevationType;
+ public ConsentUIElevationReason ElevationReason => this.header.ElevationReason;
///
- /// A series of flags that AppInfo passes to ConsentUI to signifiy actions that need to
+ /// A series of flags that AppInfo passes to ConsentUI to signify actions that need to
/// take place on the UI side.
/// This includes specifics around the UI that should be presented & signature verification settings.
///
@@ -62,12 +67,18 @@ namespace Lithnet.CredentialProvider
private protected ConsentUIData(IntPtr pData, int expectedSize)
{
this.rawData = GetRawBytes(pData, expectedSize);
- this.header = Marshal.PtrToStructure(pData);
+
+ this.header = Marshal.PtrToStructure(pData);
if (this.header.Size != expectedSize)
{
throw new InvalidDataException($"The size of the data structure {this.header.Size} does not match the expected size {expectedSize}");
}
+
+ if (HeaderSize > this.header.Size)
+ {
+ throw new InvalidDataException($"The size of the data structure {this.header.Size} is less than the expected header size {HeaderSize}");
+ }
}
///
@@ -330,7 +341,7 @@ namespace Lithnet.CredentialProvider
/// The handle to duplicate
/// A duplicated reference to the handle
/// Thrown when the handle could not be duplicated
- protected private static SafeHandle DuplicateHandleInternal(IntPtr handle)
+ private protected static SafeHandle DuplicateHandleInternal(IntPtr handle)
{
commandLineArgs ??= GetConsentUICommandLineArgs();
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataCom.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataCom.cs
index c596f0e..bc6c29d 100644
--- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataCom.cs
+++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataCom.cs
@@ -41,7 +41,7 @@ namespace Lithnet.CredentialProvider
throw new InvalidOperationException("The data structure is not of type COM");
}
- var s = Marshal.PtrToStructure(pData);
+ var s = Marshal.PtrToStructure(pData + HeaderSize);
this.ComComponentPath = this.GetStringValueIfValid(pData, (int)s.oComComponentPath);
this.ImageResourcePath = this.GetStringValueIfValid(pData, (int)s.oImageResourcePath);
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs
index 7a90c44..80cae5f 100644
--- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs
+++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataExe.cs
@@ -50,7 +50,7 @@ namespace Lithnet.CredentialProvider
throw new InvalidOperationException("The data structure is not of type EXE");
}
- var s = Marshal.PtrToStructure(pData);
+ var s = Marshal.PtrToStructure(pData + HeaderSize);
this.hFile = s.hFile;
this.ExecutablePath = this.GetStringValueIfValid(pData, (int)s.oExecutablePath1);
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs
index 436999d..1197f0d 100644
--- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs
+++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsi.cs
@@ -51,7 +51,7 @@ namespace Lithnet.CredentialProvider
throw new InvalidOperationException("The data structure is not of type MSI");
}
- var s = Marshal.PtrToStructure(pData);
+ var s = Marshal.PtrToStructure(pData + HeaderSize);
this.Action = s.MsiAction;
this.ProductName = this.GetStringValueIfValid(pData, (int)s.oProductName);
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsix.cs b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsix.cs
index d93e4ee..6589216 100644
--- a/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsix.cs
+++ b/src/Lithnet.CredentialProvider/ConsentUI/ConsentUIDataMsix.cs
@@ -36,7 +36,7 @@ namespace Lithnet.CredentialProvider
throw new InvalidOperationException("The data structure is not of type MSIX");
}
- var s = Marshal.PtrToStructure(pData);
+ var s = Marshal.PtrToStructure(pData + HeaderSize);
this.ExecutablePath = this.GetStringValueIfValid(pData, (int)s.oExecutablePath);
this.PackageName = this.GetStringValueIfValid(pData, (int)s.oPackageName);
diff --git a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-winsec-x86.dat b/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-winsec-x86.dat
deleted file mode 100644
index 311afd6..0000000
Binary files a/src/Lithnet.CredentialProvider/ConsentUI/Samples/dump-consent-winsec-x86.dat and /dev/null differ
diff --git a/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationReason.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationReason.cs
new file mode 100644
index 0000000..9c07c1e
--- /dev/null
+++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationReason.cs
@@ -0,0 +1,89 @@
+namespace Lithnet.CredentialProvider
+{
+ public enum ConsentUIElevationReason
+ {
+ ///
+ /// Application Compatibility
+ /// e.g. "Run this program as an Administrator" explicitly configured
+ ///
+ /// > "The AppCompat database stores information in the application
+ /// > compatibility fix entries for an application."
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_APPCOMPAT_EXPLICIT (ole32.dll)`
+ ///
+ AppCompatExplicit = 0,
+
+ ///
+ /// Application Compatibility
+ /// e.g. "Run this program as an Administrator" set via Windows heuristics
+ ///
+ /// > "The AppCompat database stores information in the application
+ /// > compatibility fix entries for an application."
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_APPCOMPAT_HEURISTIC (ole32.dll)`
+ ///
+ AppCompatHeuristic = 1,
+
+ ///
+ /// Application manifest
+ /// > "The Fusion database stores information from application
+ /// > manifests that describe the applications. The manifest schema
+ /// > is updated to add a new requested execution level field."
+ /// See also: https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#trustinfo
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_FUSION (ole32.dll)`
+ ///
+ Fusion = 2,
+
+ ///
+ /// Automatically detected Windows Installer package (e.g. an EXE installer)
+ /// > "Installer detection detects setup files, which helps prevent installations
+ /// > from being run without the user's knowledge and consent."
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_INSTALLER (ole32.dll)`
+ ///
+ Installer = 3,
+
+ ///
+ /// COM elevation action
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_CLSID (ole32.dll)`
+ ///
+ Clsid = 4,
+
+ ///
+ /// Windows Installer package installation (MSI)
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_MSI (ole32.dll)`
+ ///
+ Msi = 5,
+
+ ///
+ /// "Run as Administrator..." (e.g. manual UAC)
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_REQUEST (ole32.dll)`
+ ///
+ Request = 6,
+
+ ///
+ /// ActiveX Installer Service (AXIS)
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_AXIS (ole32.dll)`
+ ///
+ Axis = 7,
+
+ ///
+ /// Packaged Applications (MSIX / APPX)
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_PACKAGED_APP (ole32.dll)`
+ ///
+ Msix = 8,
+
+ ///
+ /// Unknown
+ ///
+ /// `ELEVATION_REASON.ELEVATION_REASON_NUM_REASONS (ole32.dll)`
+ ///
+ NumReasons = 9,
+ }
+}
\ No newline at end of file
diff --git a/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs b/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs
deleted file mode 100644
index b01808b..0000000
--- a/src/Lithnet.CredentialProvider/Enums/ConsentUIElevationType.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-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
index 08bda47..04a82bf 100644
--- a/src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs
+++ b/src/Lithnet.CredentialProvider/Enums/ConsentUIFlags.cs
@@ -62,7 +62,7 @@ namespace Lithnet.CredentialProvider
BlockElevation = 0x1000,
///
- /// Corresponds to `ConsentUIElevationType.AutomaticAdmin`
+ /// Corresponds to `ConsentUIPromptType.AutomaticAdmin`
/// This seems to be an instance where UAC creates a local, secondary
/// account called '%username%_admin' which is used to elevate a process.
///
diff --git a/src/Lithnet.CredentialProvider/Interop/SafeHGlobalHandle.cs b/src/Lithnet.CredentialProvider/Interop/SafeHGlobalHandle.cs
index 7650635..80828d6 100644
--- a/src/Lithnet.CredentialProvider/Interop/SafeHGlobalHandle.cs
+++ b/src/Lithnet.CredentialProvider/Interop/SafeHGlobalHandle.cs
@@ -10,6 +10,8 @@ namespace Lithnet.CredentialProvider.Interop
///
IntPtr pointer;
+ int size;
+
SafeHGlobalHandle()
{
this.pointer = IntPtr.Zero;
@@ -25,6 +27,8 @@ namespace Lithnet.CredentialProvider.Interop
this.Dispose();
}
+ public int Size => size;
+
public static SafeHGlobalHandle InvalidHandle => new SafeHGlobalHandle(IntPtr.Zero);
///
@@ -58,6 +62,7 @@ namespace Lithnet.CredentialProvider.Interop
SafeHGlobalHandle result = new SafeHGlobalHandle();
result.pointer = Marshal.AllocHGlobal(cb);
+ result.size = cb;
return result;
}
}
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureCom.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureCom.cs
index 24a35a3..6c28aaa 100644
--- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureCom.cs
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureCom.cs
@@ -6,8 +6,6 @@ namespace Lithnet.CredentialProvider.Interop
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct ConsentUIStructureCom
{
- public ConsentUIStructureHeader Header;
-
// 64
public IntPtr oOperationType; // 8
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureExe.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureExe.cs
index ed69888..ff0682e 100644
--- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureExe.cs
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureExe.cs
@@ -6,8 +6,6 @@ namespace Lithnet.CredentialProvider.Interop
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct ConsentUIStructureExe
{
- public ConsentUIStructureHeader Header;
-
// 64
public IntPtr hFile; // 8
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderBase.cs
similarity index 79%
rename from src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs
rename to src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderBase.cs
index f016be1..2edb82c 100644
--- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeader.cs
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderBase.cs
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace Lithnet.CredentialProvider.Interop
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- internal struct ConsentUIStructureHeader
+ internal struct ConsentUIStructureHeaderBase
{
public int Size; // 4
public ConsentUIType Type; // 4
@@ -18,7 +18,7 @@ namespace Lithnet.CredentialProvider.Interop
// 32
- public ConsentUIElevationType ElevationType; // 4
+ public ConsentUIElevationReason ElevationReason; // 4
public int sessionId; // 4
public IntPtr hMutex; // 8
@@ -26,8 +26,5 @@ namespace Lithnet.CredentialProvider.Interop
public ConsentUIFlags Flags; // 4
public int unknown0; // 4
- public IntPtr pReturnAddress; // 8
-
- // 64
}
}
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV1.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV1.cs
new file mode 100644
index 0000000..9d387ed
--- /dev/null
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV1.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Lithnet.CredentialProvider.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct ConsentUIStructureHeaderV1
+ {
+ public ConsentUIStructureHeaderBase BaseHeader;
+
+ public IntPtr pReturnAddress; // 8
+
+ // 64
+ }
+}
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV2.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV2.cs
new file mode 100644
index 0000000..4fae264
--- /dev/null
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureHeaderV2.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Lithnet.CredentialProvider.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct ConsentUIStructureHeaderV2
+ {
+ public ConsentUIStructureHeaderBase BaseHeader;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x81)]
+ public byte[] unknown1;
+
+ public IntPtr pReturnAddress; // 8
+ }
+}
\ No newline at end of file
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs
index b7a04bc..3d3b543 100644
--- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsi.cs
@@ -6,8 +6,6 @@ namespace Lithnet.CredentialProvider.Interop
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct ConsentUIStructureMsi
{
- public ConsentUIStructureHeader Header;
-
// 64
public ConsentUIMsiAction MsiAction; // 8
diff --git a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsix.cs b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsix.cs
index 456624a..c58c24d 100644
--- a/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsix.cs
+++ b/src/Lithnet.CredentialProvider/Interop/Structs/ConsentUIStructureMsix.cs
@@ -6,8 +6,6 @@ namespace Lithnet.CredentialProvider.Interop
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct ConsentUIStructureMsix
{
- public ConsentUIStructureHeader Header;
-
// 64
public IntPtr oExecutablePath; // 8
diff --git a/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj b/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj
index 34d41dc..7dfebbb 100644
--- a/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj
+++ b/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj
@@ -1,6 +1,6 @@
- net6.0-windows;net7.0-windows;net461
+ net6.0-windows;net7.0-windows;net8.0-windows;net461
false
Library
true
@@ -38,6 +38,15 @@
true
+
+
+ <_Parameter1>Lithnet.CredentialProvider.UnitTests.x64
+
+
+ <_Parameter1>Lithnet.CredentialProvider.UnitTests.x86
+
+
+
all
diff --git a/src/Lithnet.CredentialProvider/NativeMethods.json b/src/Lithnet.CredentialProvider/NativeMethods.json
deleted file mode 100644
index 6d04a57..0000000
--- a/src/Lithnet.CredentialProvider/NativeMethods.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "$schema": "https://aka.ms/CsWin32.schema.json"
-}
\ No newline at end of file