PowerShell: Registry-Hives laden, bearbeiten und entladen – Teil 2

Im vorherigen Post habe ich den Standard-Weg gezeigt, schnell und einfach mit „fremden“ Registry Hives innerhalb von PowerShell zu hantieren. Doch was ist, wenn ihr auf einen Aufruf von nativen DOS-Programmen keine Lust habt? Oder das Antivirus-Programm eures Vertrauens es doof findet, dass ein PowerShell-Skript so etwas versucht? Es gibt zwei Lösungsansätze, um diesen unschönen Punkt zu umgehen:

Hive mit Windows-API laden

Das Verhalten von REG LOAD und REG UNLOAD kann in PowerShell nachgebaut werden, indem man sich genau der API-Methoden bedient, die auch REG.EXE selbst dafür benutzt: RegLoadKey und RegUnLoadKey. Beide sind aus der System-DLL advapi32.dll exportiert. Die P/Invoke-Definitionen sind

[DllImport("advapi32.dll", SetLastError=true)]
static extern Int32 RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

bzw.

[DllImport("advapi32.dll", SetLastError=true)]
static extern Int32 RegUnLoadKey(UInt32 hKey, string lpSubKey);

Der PowerShell-Code, um das Ganze abzubilden, sieht demnach so aus:

$defreg = @'
[DllImport("advapi32.dll", SetLastError=true)]
static public extern Int32 RegLoadKey(UInt32 hKey, 
                                      String lpSubKey, 
                                      String lpFile);

[DllImport("advapi32.dll", SetLastError=true)]
static public extern Int32 RegUnLoadKey(UInt32 hKey, 
                                        String lpSubKey);
'@

# Name und Namespace sind volkommen beliebig, 
# solange sie nicht etwas Vorhandenes doppeln
$reg = Add-Type -MemberDefinition $defreg -Name "Reg" -Namespace "AdvAPI32" -PassThru
$reg::RegLoadKey([uint32]'0x80000003', "PSTest", "C:\\TEMP\\NTUSER.DAT")
# Gewünschte Registry-Operationen
$reg::RegUnLoadKey([uint32]'0x80000003', "PSTest")

Die einzige Herausforderung dabei ist, dass RegLoadKey – so wie übrigens auch REG LOAD – die aktivierte SE_RESTORE_NAME Berechtigung benötigt, sonst gibt die Funktion das Ergebnis 1314 (0x522) zurück, das lt. der Liste ERROR_PRIVILEGE_NOT_HELD bedeutet. Um die Berechtigung zu aktivieren, kann man entweder das PoshPrivilege-Modul von Boe Prox einsetzen oder den einzigen benötigten System-Aufruf selbst tätigen. Auch hier kommt uns die Windows API und P/Invoke zur Hilfe:


$defpriv = @'
using System;
using System.Runtime.InteropServices;
public class Privileges
{
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr hToken,
                                                      bool DisallowAll,
                                                      ref TokPriv1Luid newst,
                                                      int len,
                                                      IntPtr prev,
                                                      IntPtr relen);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    internal static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool OpenProcessToken(IntPtr h, 
                                                 int acc, 
                                                 ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, 
                                                     string name, 
                                                     ref long pluid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
        public int Count;
        public long Luid;
        public int Attr;
    }

    internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
    internal const int TOKEN_QUERY = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    internal const string SE_RESTORE_NAMETEXT = "SeRestorePrivilege";

    static public bool SetRestorePrivilige()
    {
        try
        {
            bool retVal;
            TokPriv1Luid tp;
            IntPtr hProcess = GetCurrentProcess();
            IntPtr hToken = IntPtr.Zero;
            retVal = OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref hToken);
            tp.Count = 1;
            tp.Luid = 0;
            tp.Attr = SE_PRIVILEGE_ENABLED;
            retVal = LookupPrivilegeValue(null, SE_RESTORE_NAMETEXT, ref tp.Luid);
            retVal = AdjustTokenPrivileges(hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
            return retVal;
        }
        catch
        {
            return false;
        }
    }
}
'@

Add-Type -TypeDefinition $defpriv
[Privileges]::SetRestorePrivilige()

Das Beispiel beinhaltet freilich keine Fehlerbehandlung, die man für den produktiven Einsatz noch hinzufügen müsste.

Offline Registry Library nutzen

Wesentlich eleganter als das Reinladen der Hives in die System-Registry ist die Benutzung der Offline Registry Library aus dem Windows Driver Kit (WDK). Das hat auch zwei weitere charmante Vorteile neben der Nicht-Benutzung nativer DOS-Programme:

  1. Im Gegensatz zu REG LOAD oder der Registry API, ist das geladene Hive nicht generell im System sichtbar, sondern nur für den Prozess, der die Datei geöffnet hat. Dadurch wird vermieden, dass andere Prozesse parallele Änderungen vornehmen oder Handles erzeugen können, welche dem ursprünglichen Prozess das Entladen des Hive erschweren.
  2. Die Zugriffsrechte der einzelnen Schlüssel werden nicht berücksichtigt – der gesamte Inhalt ist sowohl lesend als auch schreibend zugänglich. Dennoch können Sicherheitsbeschreibungen gelesen und geschrieben werden, was die wirklich vollständige Bearbeitung der Registry ermöglicht.

Library besorgen

Die DVD des EWDK ist 12GB groß, sie muss aber nicht installiert werden, denn die DLL findet sich bereits im entpackten Zustand unter <DVD>:\Program Files\Windows Kits\10\Redist\offreg\<CPU-Architektur> .

Library einbinden

Das Einbinden benötigter Funktionen aus der Library erfolgt ähnlich wie oben mittels Platform Invoke. Allerdings gibt es bei einigen Funktionen Hindernisse, die es geboten erscheinen lassen, das Thema im Teil 3 dieses Posts separat zu behandeln.

3 Kommentare

    • Kommt demnächst. In der Zwischenzeit verweise ich auf meinen Vortrag „Going native“ auf der (virtuellen) PSConfEU. Dort habe ich Offline Registry als Beispiel genommen.

      • Hallo Evegnij,

        habe mir das Video „Going native“ von der PSConfEU angeschaut und muss sagen: Hut ab. Meinen Respekt hast Du. Habe versucht das Codebeispiel zu Offreg soweit es für mich im Video lesbar war abzutippen und zu verstehen. Leider hagelt es bei der Ausführung die wildesten Fehlermeldungen. Ist es Dir möglich die Codebeispiele dazu irgendwo hochzuladen, so dass ich diese analysieren und verstehen kann. Für mich ist das eine total neue Thematik, in die ich mich gerade einarbeite. Vieles war für mich im Video sehr gut verständlich. Einiges hinterfrage ich noch.

        Baue gerade eine Funktion in PS, die für alle Benutzer die Möglichkeit gibt neue Keys und Registry Items zu erstellen und vorhandene Registry Items zu editieren. Den Weg über die PS cmdlet habe ich soweit laufen. Leider muss ich ab und ab beoachten, das der Hive nicht sauber abgehangen wurde. Daher möchte ich mich nun an Offreg versuchen. Vielen Dank

        Michael

Antworten

Deine E-Mail-Adresse wird nicht veröffentlicht.


*


Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.