Merge pull request #12 from lithnet/v2-consent-header
Adds support for reading 'v2' consent ui headers
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0-windows;net7.0-windows;net8.0-windows;net461;net48</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<PlatformTargets>x64</PlatformTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lithnet.CredentialProvider\Lithnet.CredentialProvider.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Samples\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0-windows;net7.0-windows;net8.0-windows;net461;net48</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lithnet.CredentialProvider\Lithnet.CredentialProvider.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Samples\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<ConsentUIStructureHeaderV2>();
|
||||
internal static int v1HeaderSize = Marshal.SizeOf<ConsentUIStructureHeaderV1>();
|
||||
internal static int HeaderSize { get; set; } = Environment.OSVersion.Version >= v2HeaderOsVersion ? v2HeaderSize : v1HeaderSize;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating the type of ConsentUI data structure
|
||||
@@ -32,7 +36,8 @@ namespace Lithnet.CredentialProvider
|
||||
public ConsentUIType Type => this.header.Type;
|
||||
|
||||
/// <summary>
|
||||
/// 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`.
|
||||
/// </summary>
|
||||
public ConsentUIPromptType PromptType => this.header.PromptType;
|
||||
|
||||
@@ -42,13 +47,13 @@ namespace Lithnet.CredentialProvider
|
||||
public IntPtr HWnd => this.header.hWindow;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public ConsentUIElevationType ElevationType => this.header.ElevationType;
|
||||
public ConsentUIElevationReason ElevationReason => this.header.ElevationReason;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
@@ -62,12 +67,18 @@ namespace Lithnet.CredentialProvider
|
||||
private protected ConsentUIData(IntPtr pData, int expectedSize)
|
||||
{
|
||||
this.rawData = GetRawBytes(pData, expectedSize);
|
||||
this.header = Marshal.PtrToStructure<ConsentUIStructureHeader>(pData);
|
||||
|
||||
this.header = Marshal.PtrToStructure<ConsentUIStructureHeaderBase>(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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -330,7 +341,7 @@ namespace Lithnet.CredentialProvider
|
||||
/// <param name="handle">The handle to duplicate</param>
|
||||
/// <returns>A duplicated reference to the handle</returns>
|
||||
/// <exception cref="Win32Exception">Thrown when the handle could not be duplicated</exception>
|
||||
protected private static SafeHandle DuplicateHandleInternal(IntPtr handle)
|
||||
private protected static SafeHandle DuplicateHandleInternal(IntPtr handle)
|
||||
{
|
||||
commandLineArgs ??= GetConsentUICommandLineArgs();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Lithnet.CredentialProvider
|
||||
throw new InvalidOperationException("The data structure is not of type COM");
|
||||
}
|
||||
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureCom>(pData);
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureCom>(pData + HeaderSize);
|
||||
|
||||
this.ComComponentPath = this.GetStringValueIfValid(pData, (int)s.oComComponentPath);
|
||||
this.ImageResourcePath = this.GetStringValueIfValid(pData, (int)s.oImageResourcePath);
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Lithnet.CredentialProvider
|
||||
throw new InvalidOperationException("The data structure is not of type EXE");
|
||||
}
|
||||
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureExe>(pData);
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureExe>(pData + HeaderSize);
|
||||
|
||||
this.hFile = s.hFile;
|
||||
this.ExecutablePath = this.GetStringValueIfValid(pData, (int)s.oExecutablePath1);
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Lithnet.CredentialProvider
|
||||
throw new InvalidOperationException("The data structure is not of type MSI");
|
||||
}
|
||||
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureMsi>(pData);
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureMsi>(pData + HeaderSize);
|
||||
|
||||
this.Action = s.MsiAction;
|
||||
this.ProductName = this.GetStringValueIfValid(pData, (int)s.oProductName);
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Lithnet.CredentialProvider
|
||||
throw new InvalidOperationException("The data structure is not of type MSIX");
|
||||
}
|
||||
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureMsix>(pData);
|
||||
var s = Marshal.PtrToStructure<ConsentUIStructureMsix>(pData + HeaderSize);
|
||||
|
||||
this.ExecutablePath = this.GetStringValueIfValid(pData, (int)s.oExecutablePath);
|
||||
this.PackageName = this.GetStringValueIfValid(pData, (int)s.oPackageName);
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
namespace Lithnet.CredentialProvider
|
||||
{
|
||||
public enum ConsentUIElevationReason
|
||||
{
|
||||
/// <summary>
|
||||
/// 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)`
|
||||
/// </summary>
|
||||
AppCompatExplicit = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 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)`
|
||||
/// </summary>
|
||||
AppCompatHeuristic = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 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)`
|
||||
/// </summary>
|
||||
Fusion = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 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)`
|
||||
/// </summary>
|
||||
Installer = 3,
|
||||
|
||||
/// <summary>
|
||||
/// COM elevation action
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_CLSID (ole32.dll)`
|
||||
/// </summary>
|
||||
Clsid = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Windows Installer package installation (MSI)
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_MSI (ole32.dll)`
|
||||
/// </summary>
|
||||
Msi = 5,
|
||||
|
||||
/// <summary>
|
||||
/// "Run as Administrator..." (e.g. manual UAC)
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_REQUEST (ole32.dll)`
|
||||
/// </summary>
|
||||
Request = 6,
|
||||
|
||||
/// <summary>
|
||||
/// ActiveX Installer Service (AXIS)
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_AXIS (ole32.dll)`
|
||||
/// </summary>
|
||||
Axis = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Packaged Applications (MSIX / APPX)
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_PACKAGED_APP (ole32.dll)`
|
||||
/// </summary>
|
||||
Msix = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
///
|
||||
/// `ELEVATION_REASON.ELEVATION_REASON_NUM_REASONS (ole32.dll)`
|
||||
/// </summary>
|
||||
NumReasons = 9,
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Lithnet.CredentialProvider
|
||||
{
|
||||
public enum ConsentUIElevationType
|
||||
{
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
AutomaticAdmin = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Prompt the user for consent (i.e. Yes or No)
|
||||
/// </summary>
|
||||
Consent = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Prompt the user for credentials
|
||||
/// </summary>
|
||||
Credentials = 3
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ namespace Lithnet.CredentialProvider
|
||||
BlockElevation = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Lithnet.CredentialProvider.Interop
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
@@ -58,6 +62,7 @@ namespace Lithnet.CredentialProvider.Interop
|
||||
|
||||
SafeHGlobalHandle result = new SafeHGlobalHandle();
|
||||
result.pointer = Marshal.AllocHGlobal(cb);
|
||||
result.size = cb;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-5
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0-windows;net7.0-windows;net461</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0-windows;net7.0-windows;net8.0-windows;net461</TargetFrameworks>
|
||||
<RegisterForComInterop>false</RegisterForComInterop>
|
||||
<OutputType>Library</OutputType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -38,6 +38,15 @@
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
|
||||
<_Parameter1>Lithnet.CredentialProvider.UnitTests.x64</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
|
||||
<_Parameter1>Lithnet.CredentialProvider.UnitTests.x86</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json"
|
||||
}
|
||||
Reference in New Issue
Block a user