Patrick Stoeckle
Patrick Stoeckle

Reputation: 129

PowerShell AuditQuerySystemPolicy: Value of audit policy

Situation

I want the value of an audit policy in Windows, e.g., 0cce9240-69ae-11d9-bed3-50505450303Success or 1. Hereby, I have to use PowerShell. As the auditpol is language dependent, I was looking for a language independent method. Thus, I came across this helpful article to use the Win32.Advapi32 module.

Code

$MemberDefinition = @'
[DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool AuditEnumerateCategories(
        out IntPtr ppAuditCategoriesArray, 
        out uint pCountReturned);

[DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool AuditLookupCategoryName(
        ref Guid pAuditCategoryGuid, 
        out StringBuilder ppszCategoryName);

[DllImport("advapi32.dll", SetLastError = true)]
    public  static extern bool AuditEnumerateSubCategories(
        ref Guid pAuditCategoryGuid, 
        bool bRetrieveAllSubCategories, 
        out IntPtr ppAuditSubCategoriesArray, 
        out uint pCountReturned);

[DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool AuditLookupSubCategoryName(
        ref Guid pAuditSubCategoryGuid, 
        out StringBuilder ppszSubCategoryName);

[DllImport("advapi32.dll")]
    public static extern void AuditFree(
        IntPtr buffer);

[DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool AuditQuerySystemPolicy(
        Guid pSubCategoryGuids, 
        uint PolicyCount, 
        out IntPtr ppAuditPolicy);
'@

$Advapi32 = Add-Type -MemberDefinition $MemberDefinition -Name 'Advapi32' -Namespace 'Win32' -UsingNamespace System.Text -PassThru

$neBuild = [System.Text.StringBuilder]::new()
$res1 = [Win32.Advapi32]::AuditLookupSubCategoryName([ref]"0cce9240-69ae-11d9-bed3-505054503030",[ref]$neBuild)
Write-Host "$neBuild"
[IntPtr]$test_out = [IntPtr]::Zero
$result = [Win32.Advapi32]::AuditQuerySystemPolicy("0cce9240-69ae-11d9-bed3-505054503030", 1,[ref]$test_out)

Problem

On the one hand, the output of the Write-Host statement is Kerberos Service Ticket Operations and, therefore, I'm assuming that the general import is working. On the other hand, $test_out is always 0, no matter to which value I configure the Kerberos Service Ticket Operations.

Question

Did I do anything wrong here? Is the import, e.g. public static extern bool AuditQuerySystemPolicy, flawed? Do I have to initialize the passed parameters differently?

Thank you for any help!

Upvotes: 1

Views: 577

Answers (1)

davidgiga1993
davidgiga1993

Reputation: 2853

The signature of the AuditQuerySystemPolicy is a bit wrong.

Here is a full working example. I mostly rely on C# to do the pinvoke and pointer to struct conversion. Make sure to run it as administrator, otherwise it will return -1 as error result.

$TypeDefinition = @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Audit
{
    public class AuditPol
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.U1)]
        public static extern bool AuditQuerySystemPolicy(
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), In]
            Guid[] pSubCategoryGuids,
            uint dwPolicyCount,
            out IntPtr ppAuditPolicy);

        public static IEnumerable<AUDIT_POLICY_INFORMATION> AuditQuerySystemPolicy([In] Guid[] pSubCategoryGuids)
        {
            IntPtr ppAuditPolicy;
            if (!AuditQuerySystemPolicy(pSubCategoryGuids, (uint) pSubCategoryGuids.Length, out ppAuditPolicy))
                return new AUDIT_POLICY_INFORMATION[0];

            return ToIEnum<AUDIT_POLICY_INFORMATION>(ppAuditPolicy, pSubCategoryGuids.Length);
        }

        public static IEnumerable<T> ToIEnum<T>(IntPtr ptr, int count, int prefixBytes = 0)
        {
            if (count != 0 && !(ptr == IntPtr.Zero))
            {
                int stSize = Marshal.SizeOf(typeof(T));
                for (int i = 0; i < count; ++i)
                    yield return ToStructure<T>(new IntPtr(ptr.ToInt64() + prefixBytes + i * stSize));
            }
        }

        public static T ToStructure<T>(IntPtr ptr, long allocatedBytes = -1)
        {
            Type type = typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T);
            if (allocatedBytes < 0L || allocatedBytes >= (long) Marshal.SizeOf(type))
            {
                return (T) Marshal.PtrToStructure(ptr, type);
            }

            throw new InsufficientMemoryException();
        }

        public struct AUDIT_POLICY_INFORMATION
        {
            public Guid AuditSubCategoryGuid;
            public AuditCondition AuditingInformation;
            public Guid AuditCategoryGuid;
        }

        public enum AuditCondition : uint
        {
            /// <summary>Do not change auditing options for the specified event type.
            /// <para>This value is valid for the AuditSetSystemPolicy and AuditQuerySystemPolicy functions.</para></summary>
            POLICY_AUDIT_EVENT_UNCHANGED = 0,

            /// <summary>Audit successful occurrences of the specified event type.
            /// <para>This value is valid for the AuditSetSystemPolicy and AuditQuerySystemPolicy functions.</para></summary>
            POLICY_AUDIT_EVENT_SUCCESS = 1,

            /// <summary>Audit failed attempts to cause the specified event type.
            /// <para>This value is valid for the AuditSetSystemPolicy and AuditQuerySystemPolicy functions.</para></summary>
            POLICY_AUDIT_EVENT_FAILURE = 2,

            /// <summary>Do not audit the specified event type.
            /// <para>This value is valid for the AuditSetSystemPolicy and AuditQuerySystemPolicy functions.</para></summary>
            POLICY_AUDIT_EVENT_NONE = 4,

            /// <summary>Do not change auditing options for the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_POLICY_UNCHANGED = 0,

            /// <summary>Audit successful occurrences of the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_AUDIT_SUCCESS_INCLUDE = POLICY_AUDIT_EVENT_SUCCESS, // 0x00000001

            /// <summary>Do not audit successful occurrences of the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_AUDIT_SUCCESS_EXCLUDE = POLICY_AUDIT_EVENT_FAILURE, // 0x00000002

            /// <summary>Audit failed attempts to cause the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_AUDIT_FAILURE_INCLUDE = POLICY_AUDIT_EVENT_NONE, // 0x00000004

            /// <summary>Do not audit failed attempts to cause the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_AUDIT_FAILURE_EXCLUDE = 8,

            /// <summary>Do not audit the specified event type.
            /// <para>This value is valid for the AuditSetPerUserPolicy and AuditQueryPerUserPolicy functions.</para></summary>
            PER_USER_AUDIT_NONE = 16, // 0x00000010
        }

        public static int GetPolicy(String uid)
        {
            var guid = new Guid(uid);
            var result = AuditQuerySystemPolicy(new[] {guid});
            foreach (var info in result)
            {
                return (int) info.AuditingInformation;
            }

            return -1;
        }
    }
}
'@
Add-Type -TypeDefinition $TypeDefinition -Language CSharp

$result = [Audit.AuditPol]::GetPolicy("0CCE9211-69AE-11D9-BED3-505054503030")
$success = ($result -band 1) -ne 0;
$failure = ($result -band 2) -ne 0;
$none = ($result -band 4) -ne 0;
Write-Output "Success: $success, Failure: $failure, None: $none";

Upvotes: 2

Related Questions