6 Stimmen

Ich habe erfolgreich advapi32's LsaEnumerateAccountRights() von C# aus aufgerufen. Wie kann ich nun das Array von LSA_UNICODE_STRING, das zurückgegeben wird, unmarshalling?

Es ist ein Zeiger auf ein Array von LSA_UNICODE_STRING Strukturen. Ich habe einen Code gefunden, der den umgekehrten Weg geht, d.h. eine LSA_UNICODE_STRING aus einer C#-Zeichenkette. Das können Sie im folgenden Abschnitt über den Hilfscode sehen.

Was ich bis einschließlich der Aufforderung zur LsaEnumerateAccountRights() scheint gut zu funktionieren. Es werden sinnvolle Werte für den Array-Zeiger und für die Anzahl zurückgegeben.

Ich bin ratlos, wie ich die unter diese verflixten Saiten. Hilfe, bitte? Bitte schön?

UPDATE: Die Hilfsfunktion von nobugz in seiner Antwort unten ist so gut wie richtig, man muss nur die Länge durch UnicodeEncoding.CharSize . Dank ihm kann ich jetzt die ERSTE Zeichenkette im Array sehen. Siehe die Aktualisierungen am Ende der beiden Codeabschnitte unten.

Wie zum Teufel kann ich nun Zeigerarithmetik betreiben?

UPDATE 2.5: Siehe Antwort für den Funktionscode. Ich habe den alten, "falschen" Code verloren.

11voto

JCCyC Punkte 15224

Ich habe es gefunden! Unter dieser Blogbeitrag . Der geänderte Code unten funktioniert jetzt vollständig. Er ist sogar 64-Bit-sicher!

Der Hauptcode:

IntPtr sid = IntPtr.Zero;
int sidSize = 0;
StringBuilder domainName = new StringBuilder();
int nameSize = 0;
int accountType = 0;

LookupAccountName("\\\\" + tbHost.Text, tbUsername.Text, sid, ref sidSize,
    domainName, ref nameSize, ref accountType);
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);

bool result = LookupAccountName("\\\\" + tbHost.Text, tbUsername.Text, sid, ref sidSize,
    domainName, ref nameSize, ref accountType);

myResults.Text += String.Format("LookupAccountName(): Result {0}, SID {1}\n", result, sid);

LSA_UNICODE_STRING systemName = string2LSAUS("\\\\" + tbHost.Text);
IntPtr policyHandle = IntPtr.Zero;
LSA_OBJECT_ATTRIBUTES objAttrs = new LSA_OBJECT_ATTRIBUTES();
uint retVal = LsaOpenPolicy(ref systemName, ref objAttrs,
                    POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, out policyHandle);

myResults.Text += String.Format("LsaOpenPolicy(): Result {0}, Policy Handle {1}\n", retVal, policyHandle);

IntPtr rightsArray = IntPtr.Zero;
ulong rightsCount = 0;
long lretVal = LsaEnumerateAccountRights(policyHandle, sid, out rightsArray, out rightsCount);
retVal = LsaNtStatusToWinError(lretVal);

if (retVal != 0)
    throw new System.ComponentModel.Win32Exception((int)retVal);

myResults.Text += String.Format("LsaEnumerateAccountRights(): Result {0}, RightsArray {1}, Count {2}\n",
    retVal, rightsArray, rightsCount);

LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING();
for (ulong i = 0; i < rightsCount; i++)
{
    IntPtr itemAddr = new IntPtr(rightsArray.ToInt64() + (long)(i * (ulong) Marshal.SizeOf(myLsaus)));
    myLsaus = (WinNetUtils.LSA_UNICODE_STRING)Marshal.PtrToStructure(itemAddr, myLsaus.GetType());
    string thisRight = WinNetUtils.LSAUS2string(myLsaus);
    NonBlockingPrint(wmiResults, "Right #{0}: {1}\n", i+1, thisRight);
}
LsaClose(policyHandle);

Die Hilfsfunktionen, Importe usw:

public const int POLICY_VIEW_LOCAL_INFORMATION = 0x1;
public const int POLICY_LOOKUP_NAMES = 0x00000800;

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
public static extern UInt32 LsaNtStatusToWinError(
    long Status);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = true)]
public static extern bool ConvertStringSidToSid(
    string StringSid, out IntPtr pSid);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = true)]
public static extern bool LookupAccountName( 
    string lpSystemName, string lpAccountName, 
    IntPtr psid, ref int cbsid, 
    StringBuilder domainName, ref int cbdomainLength, 
    ref int use );

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
public static extern UInt32 LsaOpenPolicy(
    ref LSA_UNICODE_STRING SystemName,
    ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
    Int32 DesiredAccess,
    out IntPtr PolicyHandle );

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern long LsaEnumerateAccountRights(
    IntPtr PolicyHandle, IntPtr AccountSid,
    out /* LSA_UNICODE_STRING[] */ IntPtr UserRights,
    out ulong CountOfRights); 

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern long LsaClose(
            IntPtr PolicyHandle);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LSA_UNICODE_STRING 
{ 
  public UInt16 Length; 
  public UInt16 MaximumLength; 
  public IntPtr Buffer; 
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LSA_OBJECT_ATTRIBUTES
{
    public IntPtr RootDirectory;
    public IntPtr SecurityDescriptor;
    public IntPtr SecurityQualityOfService;
    public LSA_UNICODE_STRING ObjectName;
    public UInt32 Attributes;
    public UInt32 Length;
}

public static LSA_UNICODE_STRING string2LSAUS(string myString)
{
    LSA_UNICODE_STRING retStr = new LSA_UNICODE_STRING();
    retStr.Buffer = Marshal.StringToHGlobalUni(myString);
    retStr.Length = (UInt16)(myString.Length * UnicodeEncoding.CharSize);
    retStr.MaximumLength = (UInt16)((myString.Length + 1) * UnicodeEncoding.CharSize);
    return retStr;
}

public static string LSAUS2string(LSA_UNICODE_STRING lsaus)
{
    char[] cvt = new char[lsaus.Length / UnicodeEncoding.CharSize];
    Marshal.Copy(lsaus.Buffer, cvt, 0, lsaus.Length / UnicodeEncoding.CharSize);
    return new string(cvt);
}

0 Stimmen

Sie sollten Ihre Antwort aus der Frage herausziehen und sie hier einfügen.

0 Stimmen

Sie müssen auch sicher sein, dass Sie LsaClose() aufrufen, um das Handle zu schließen.

0 Stimmen

Erledigt und erledigt. Leider habe ich den ursprünglichen, nicht funktionierenden Code verloren, so dass die Frage irgendwie unvollständig aussieht.

2voto

Hans Passant Punkte 894572

Das sollte für Sie funktionieren:

    private static string LSAUS2String(LSA_UNICODE_STRING lsa) {
        char[] cvt = new char[lsa.Length];
        Marshal.Copy(lsa.Buffer, cvt, 0, lsa.Length);
        return new string(cvt);
    }

0 Stimmen

Es scheint, dass ich Marshal.PtrToStructure() auf jedes Mitglied des Arrays verwenden muss, aber wie kann ich das Array durchlaufen? Zeiger Arithmetik???

0 Stimmen

PtrToStructure? Nein, es ist ein Array von Char. Marshal.Copy kopiert es aus dem IntPtr in das char[]. Dann ist es einfach.

0 Stimmen

Entschuldigung, ich sprach von dem übergeordneten Array, dem Array von LSA_UNICODE_STRING's. Ich habe es jetzt zum Laufen gebracht (siehe oben). Vielen Dank für die Hilfe!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X