Adds support for reading 'v2' consent ui headers

This commit is contained in:
Ryan Newington
2024-08-28 01:29:34 +10:00
parent fe2a6cabb4
commit fcdd67bb0f
36 changed files with 447 additions and 22 deletions
@@ -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
@@ -62,7 +66,8 @@ 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)
{
@@ -330,7 +335,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);
@@ -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
@@ -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
@@ -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
@@ -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"
}