LsaAddAccountRights上的AccessViolation

时间:2014-07-08 03:42:06

标签: c# .net winapi pinvoke

我一直盯着这个......我在下面打电话给LsaAddAccountRights时获得了AccessViolation。我想我已经包含了相关细节。任何帮助表示赞赏!

导致AccessViolation的代码:

LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = new LSA_UNICODE_STRING(privilegeName);

//add the right to the account
retVal = LsaAddAccountRights(
    hPolicy, 
    sidBufferHandle.AddrOfPinnedObject(), 
    userRights, 
    1);

p / invoke声明为:

    [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
    private static extern Int32 LsaAddAccountRights(
        IntPtr PolicyHandle,
        IntPtr AccountSid,
        LSA_UNICODE_STRING[] UserRights,
        Int32 CountOfRights);

通过以下代码设置hPolicy,该代码确实有效并产生句柄:

LSA_OBJECT_ATTRIBUTES objAttrs = new LSA_OBJECT_ATTRIBUTES();

IntPtr hPolicy = IntPtr.Zero;

int access = (int)(
            LsaAccessPolicy.POLICY_AUDIT_LOG_ADMIN |
            LsaAccessPolicy.POLICY_CREATE_ACCOUNT |
            LsaAccessPolicy.POLICY_CREATE_PRIVILEGE |
            LsaAccessPolicy.POLICY_CREATE_SECRET |
            LsaAccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
            LsaAccessPolicy.POLICY_LOOKUP_NAMES |
            LsaAccessPolicy.POLICY_NOTIFICATION |
            LsaAccessPolicy.POLICY_SERVER_ADMIN |
            LsaAccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
            LsaAccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
            LsaAccessPolicy.POLICY_TRUST_ADMIN |
            LsaAccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
            LsaAccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
            );

int retVal = LsaOpenPolicy(
    IntPtr.Zero, // local machine
    ref objAttrs,
    access,
    out hPolicy);

sidBufferHandle设置如下:

SecurityIdentifier adminSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
int sidLen = adminSid.BinaryLength;
byte[] sidBuffer = new byte[adminSid.BinaryLength];
adminSid.GetBinaryForm(sidBuffer, 0);
GCHandle sidBufferHandle = GCHandle.Alloc(sidBuffer, GCHandleType.Pinned);

LSA_UNICODE_STRING的设置如下:

    [StructLayout(LayoutKind.Sequential)]
    private class LSA_UNICODE_STRING
    {

        public UInt16 Length;
        public UInt16 MaximumLength;
        public IntPtr Buffer;

        public LSA_UNICODE_STRING(string s)
        {
            this.Buffer = Marshal.StringToHGlobalUni(s);
            this.Length = (UInt16)(s.Length * UnicodeEncoding.CharSize);
            this.MaximumLength = (UInt16)((s.Length + 1) * UnicodeEncoding.CharSize);
        }

        ~LSA_UNICODE_STRING()
        {
            if (this.Buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(this.Buffer);
                this.Buffer = IntPtr.Zero;
            }
        }

        public static string PtrToString(IntPtr p)
        {
            Int16 length = Marshal.ReadInt16(p);
            Int16 maxLen = Marshal.ReadInt16(p + 2);
            IntPtr pBuffer = Marshal.ReadIntPtr(p + 4);

            char[] cvt = new char[length / UnicodeEncoding.CharSize];
            Marshal.Copy(pBuffer, cvt, 0, length / UnicodeEncoding.CharSize);
            return new string(cvt);
        }

    }

LSA_OBJECT_ATTRIBUTES设置如下(因为它没有真正使用):

    [StructLayout(LayoutKind.Sequential)]
    private struct LSA_OBJECT_ATTRIBUTES
    {
        public int Length;
        public IntPtr RootDirectory;
        public UInt16 ObjectName_Length;
        public UInt16 ObjectName_MaximumLength;
        public IntPtr ObjectName_Buffer;
        public UInt32 Attributes;
        public IntPtr SecurityDescriptor;
        public IntPtr SecurityQualityOfService;
    }

1 个答案:

答案 0 :(得分:2)

非托管函数声明是:

NTSTATUS LsaAddAccountRights(
  _In_  LSA_HANDLE PolicyHandle,
  _In_  PSID AccountSid,
  _In_  PLSA_UNICODE_STRING UserRights,
  _In_  ULONG CountOfRights
);

让我们专注于UserRights参数。那是PLSA_UNICODE_STRING类型。形容为:

  

指向LSA_UNICODE_STRING结构数组的指针。

然后是结构:

typedef struct _LSA_UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;

因此,PLSA_UNICODE_STRING是指向结构的指针。

这里的主要问题在于您如何在C#中声明LSA_UNICODE_STRING。您已将其声明为C#类。这使它成为引用类型而不是值类型。因此,在您的代码中,LSA_UNICODE_STRING[]是一个指针数组。但这与UserRights类型的非托管PLSA_UNICODE_STRING参数不兼容,该参数是结构数组

而不是

[StructLayout(LayoutKind.Sequential)]
private class LSA_UNICODE_STRING
{
    ....
}

你需要使用

[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
    ....
}

在p / invoke上,您应同时删除SetLastErrorPreserveSig设置。它们不适用于此处。该函数不调用SetLastError,并且没有重写COM参数。

您对LSA_OBJECT_ATTRIBUTES的声明也是错误的。你需要这样:

struct LSA_OBJECT_ATTRIBUTES
{
   public UInt32 Length;
   public IntPtr RootDirectory;
   public IntPtr ObjectName;
   public UInt32 Attributes;
   public IntPtr SecurityDescriptor;
   public IntPtr SecurityQualityOfService;
}

您需要将ObjectName封送到指向LSA_UNICODE_STRING的指针。

很可能会有更多的问题,但这是我在10分钟的评论中发现的全部内容。我希望这会有所帮助。

相关问题