LsaOpenPolicy : Attempted to read or write protected memory

A

Adrian Wallis

Hello,

I'm trying to call LsaOpenPolicy, but get the error
'System.AccessViolationException'.

I originally tried a conversion from working VB6 code and I've compared
the code with working C# code and cannot see where the problem lies -
can anyone help to point out the problem please:

Structure LSA_UNICODE_STRING
Dim Length As Short
Dim MaximumLength As Short
Dim Buffer As String
End Structure
Structure LSA_OBJECT_ATTRIBUTES
Dim Length As Integer
Dim RootDirectory As IntPtr
Dim ObjectName As IntPtr
Dim Attributes As Integer
Dim SecurityDescriptor As IntPtr
Dim SecurityQualityOfService As IntPtr
End Structure
Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
As IntPtr) As Int32
Private POLICY_ALL_ACCESS As Integer = &HF0FFF

Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
Dim SystemName(0) As LSA_UNICODE_STRING
SystemName(0) = New LSA_UNICODE_STRING
'initialize a pointer for the policy handle
Dim PolicyHandle As IntPtr = IntPtr.Zero
'these attributes are not used, but LsaOpenPolicy wants them to
exists
Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
ObjectAttributes.RootDirectory = IntPtr.Zero
ObjectAttributes.ObjectName = IntPtr.Zero
ObjectAttributes.Attributes = 0
ObjectAttributes.SecurityDescriptor = IntPtr.Zero
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
ObjectAttributes.Length = 24 ' IN C# :
Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
'get a policy handle
SystemName(0).Length = "192.168.1.1".Length * 2 ' Can't get
UnicodeEncoding.CharSize to work? How to declare?
SystemName(0).MaximumLength = ("192.168.1.1".Length + 1) * 2 '
Can't get UnicodeEncoding.CharSize to work? How to declare?
SystemName(0).Buffer = "192.168.1.1"
Dim ResultPolicy As UInteger
Dim Access = POLICY_ALL_ACCESS
ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)

Many thanks
Adrian
 
M

Mattias Sjögren

Adrian,
Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
As IntPtr) As Int32

The first parameter shouldn't be an array, just a single
LSA_UNICODE_STRING.

'these attributes are not used, but LsaOpenPolicy wants them to
exists
Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
ObjectAttributes.RootDirectory = IntPtr.Zero
ObjectAttributes.ObjectName = IntPtr.Zero
ObjectAttributes.Attributes = 0
ObjectAttributes.SecurityDescriptor = IntPtr.Zero
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
ObjectAttributes.Length = 24 ' IN C# :
Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));

FYI, all members are initialized to zero by default so doing it
explicitly isn't really needed.

And you can use Marshal.SizeOf from VB as well.


Mattias
 
A

Adrian Wallis

Thanks for that, the problem appears to be with the LSA_UNICODE_STRING
part.

If I set pass it as NOTHING it works fine and gets a handle to local
machine, the problem comes when I try to use it on a remote computer.

Having stepped through the C# version and the VB.NET version I cannot
see any differences in what is being passed, or how it's being passed.

I'm totallay stumped as to what's causing the error.
 
A

Adrian Wallis

I've managed to fix the first error with the following code:

Dim SystemName As LSA_UNICODE_STRING
SystemName = New LSA_UNICODE_STRING
UserAccount = "tenyas\zwan"
Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
'get a policy handle
SystemName = InitLSAString("")
Dim ResultPolicy As Integer
Dim Access = POLICY_ALL_ACCESS
ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)
If ResultPolicy <> 0 Then
Debug.Print(LsaNtStatusToWinError(ResultPolicy))
End If

which works fine. As soon as I add a remote machine name though, it
fails with error 1722 (RPC Server unavailable), I know this isn't the
case as it happens against any machine. I can only assume that the name
isn't being passed correctly as unicode?

Please help someone - it's driving me crazy.

Thanks
Adrian
 
A

Adrian Wallis

I've managed to fix the problem by changing the structure slightly:

Structure LSA_UNICODE_STRING
Dim Length As Short
Dim MaximumLength As Short

<System.Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)>
Dim buffer As String
End Structure

The full code if anyone wants is :

Structure LSA_UNICODE_STRING
Dim Length As Short
Dim MaximumLength As Short

<System.Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)>
Dim buffer As String
End Structure
Public Enum SID_NAME_USE
SidTypeUser = 1
SidTypeGroup = 2
SidTypeDomain = 3
SidTypeAlias = 4
SidTypeWellKnownGroup = 5
SidTypeDeletedAccount = 6
SidTypeInvalid = 7
SidTypeUnknown = 8
End Enum
Structure LSA_OBJECT_ATTRIBUTES
Dim Length As Integer
Dim RootDirectory As IntPtr
Dim ObjectName As IntPtr
Dim Attributes As Integer
Dim SecurityDescriptor As IntPtr
Dim SecurityQualityOfService As IntPtr
End Structure
Structure LSA_translated_sid
Dim use As SID_NAME_USE
Dim RelativeID As ULong
Dim DomainIndex As Long
End Structure
Public UserAccount As String
Dim PolicyHandle As IntPtr = IntPtr.Zero
Private Declare Function LsaNtStatusToWinError Lib "advapi32.dll"
(ByVal NTStatus As Int32) As Int32
Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
SystemName As LSA_UNICODE_STRING, ByRef ObjectAttributes As
LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
As IntPtr) As Int32
Private POLICY_ALL_ACCESS As Integer = &HF0FFF
Private Declare Auto Function LookupAccountName Lib "advapi32.dll"
(ByVal lpSystemName As String, ByVal lpAccountName As String, ByVal Sid
As IntPtr, ByRef cbSid As Integer, ByVal lpReferenceDomainName As
String, ByRef cchReferencedDomainName As Integer, ByRef peUse As
Integer) As Boolean
Private Declare Unicode Function LsaAddAccountRights Lib
"advapi32.dll" (ByVal PolicyHandle As IntPtr, ByVal AccountSid As
IntPtr, ByRef UserRights As LSA_UNICODE_STRING, ByVal CountOfRights As
Int32) As Int32
Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
Dim SystemName As LSA_UNICODE_STRING
SystemName = New LSA_UNICODE_STRING
UserAccount = "domain\user"
Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
'get a policy handle
SystemName = InitLSAString("192.168.1.1")
Dim ResultPolicy As Integer
Dim Access = POLICY_ALL_ACCESS
ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)
If ResultPolicy <> 0 Then
Debug.Print(LsaNtStatusToWinError(ResultPolicy))
End If
Dim tSID As IntPtr
Dim lngUse As Int32 = 0
tSID = fncLookupAccountName("192.168.1.1", "domain\user", tSID,
Nothing, lngUse)
Dim Privileges As LSA_UNICODE_STRING = New LSA_UNICODE_STRING
Privileges = InitLSAString("SeServiceLogonRight")
Dim test As Integer
test = LsaAddAccountRights(PolicyHandle, tSID, Privileges, 1)
Debug.Print(LsaNtStatusToWinError(test))
End Sub
Public Function fncLookupAccountName(ByVal strSystemName As String,
ByVal strName As String, ByVal tSID As IntPtr, ByRef
strReferencedDomainName As String, ByRef lngUse As Long) As Long
Dim ret As Boolean
Dim ptrSid As IntPtr
Dim cbSid As Integer
Dim refDomainName As New System.Text.StringBuilder
Dim cbRefDomainName As Integer
Dim peUse As SID_NAME_USE
'First get the buffer sizes
ret = LookupAccountName(strSystemName, strName, Nothing, cbSid,
Nothing, cbRefDomainName, peUse)
'Adjust the buffers to the needed size
ptrSid =
System.Runtime.InteropServices.Marshal.AllocHGlobal(cbSid)
refDomainName.EnsureCapacity(cbRefDomainName)
'Get the data again, now with the changed buffers
ret = LookupAccountName(strSystemName, strName, ptrSid, cbSid,
refDomainName.ToString, cbRefDomainName, peUse)
If ret Then
Return ptrSid
End If
End Function
Public Function InitLSAString(ByVal Input As String) As
LSA_UNICODE_STRING
Dim LSAString As New LSA_UNICODE_STRING
LSAString.Length = Input.Length *
System.Text.UnicodeEncoding.CharSize
LSAString.MaximumLength = (Input.Length + 1) *
System.Text.UnicodeEncoding.CharSize
LSAString.buffer = Input
Return LSAString
End Function

I hope this helps someone.
Adrian
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top