我一直盯着这个......我在下面打电话给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;
}
答案 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上,您应同时删除SetLastError
和PreserveSig
设置。它们不适用于此处。该函数不调用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分钟的评论中发现的全部内容。我希望这会有所帮助。