Windows Notification Facility: Die am wenigsten dokumentierte Angriffsfläche

Unter dem Schnitt befindet sich eine Übersetzung der Präsentation "Die Windows-Benachrichtigungsfunktion: Die bisher undokumentierteste Kernel-Angriffsfläche", die Alex Ionescu und Gabrielle Viala auf der BlackHat 2018-Konferenz vorgestellt haben .




Was ist die Windows Notification Facility (WNF)?


Die Windows-Benachrichtigungsfunktion ist ein Benachrichtigungsmechanismus (sowohl im Kernel als auch im Benutzermodus verfügbar), der auf einem Publisher-Subscriber- Modell ( pubsub , Publisher / Subscriber) basiert . Der Mechanismus wurde in Windows 8 hinzugefügt: teilweise, um einige langjährige Designbeschränkungen im Betriebssystem zu lösen, aber auch, um als Grundlage für die Implementierung von Push-Benachrichtigungen zu dienen, die iOS / Android ähneln.


Das Hauptmerkmal ist, dass es sich um ein blindes Modell (meistens ohne Registrierung) handelt, das ein ungeordnetes Abonnement und eine ungeordnete Veröffentlichung ermöglicht. Dies bedeutet, dass ein Verbraucher eine Benachrichtigung abonnieren kann, noch bevor die Benachrichtigung von seiner Quelle veröffentlicht wurde. Und dass derjenige, der die Ereignisse generiert, nicht verpflichtet ist, die Benachrichtigung im Voraus zu "registrieren".


Darüber hinaus unterstützt der Mechanismus:


  • dauerhafte und vorübergehende Benachrichtigungen
  • monoton zunehmende eindeutige Kennungen
  • Nutzlastpuffer (bis zu 4 Kilobyte) für jedes Ereignis
  • Thread-Pool-Benachrichtigungsmodell mit gruppenbasierter Serialisierung
  • Ein bereichsbereichsbasiertes Sicherheitsmodell, das Sicherheitsbeschreibungen über den Standard- DACL / SACL- Mechanismus implementiert


Warum WNF erschien


Stellen Sie sich ein kanonisches Beispiel vor: Es gibt einen Treiber, der wissen möchte, dass ein Volume mit Lese- und Schreibzugriff verbunden wurde. Um Sie darüber zu informieren, meldet Autochk (ein Analogon von fsck unter Windows) ein Ereignis namens VolumesSafeForWriteAccess. Um ein Ereignis zu melden, müssen Sie jedoch zuerst das Ereignisobjekt selbst erstellen.


Wir müssen auch wissen, dass Autochk bereits an der Lautstärke arbeitet, aber das Ereignis, auf das wir warten, noch nicht signalisiert hat. Schlechte Lösung: Setzen Sie sich mit sleep () in eine Schleife, prüfen Sie, ob ein Ereignis vorhanden ist, und warten Sie, wenn das Ereignis erstellt wird.


Nach dem Beenden der Windows-Anwendung werden jedoch alle Deskriptoren geschlossen. Und wenn das Objekt keine Deskriptoren hat, wird es zerstört. Wer wird diese Veranstaltung abhalten?


Ohne WNF besteht die Lösung darin, dass der Betriebssystemkern ein Ereignis generiert, bevor Treiber geladen werden, und dass Autochk es wie ein Verbraucher öffnet, aber anstatt zu warten, sollte es dieses Ereignis signalisieren.



Statusnamen WNF


In der WNF-Welt ist ein Statusname eine 64-Bit-Nummer. Aber es gibt einen Trick - tatsächlich ist es eine codierte Struktur. Der Statusname hat eine Version , eine Lebensdauer , einen Bereich , ein Datenpersistenzflag und eine eindeutige Seriennummer .


typedef struct _WNF_STATE_NAME_INTERNAL { ULONG64 Version:4; ULONG64 NameLifetime:2; ULONG64 DataScope:4; ULONG64 PermanentData:1; ULONG64 Unique:53; } WNF_STATE_NAME_INTERNAL, *PWNF_STATE_NAME_INTERNAL; 

Diese Daten sind jedoch nur verfügbar, wenn wir eine 64-Bit-Zahl mit einer magischen Konstante pro-XOR verwenden:


 #define WNF_STATE_KEY 0x41C64E6DA3BC0074 


Lebensdauer des Statusnamens


Der WNF-Statusname kann sein (WNF_STATE_NAME_LIFETIME):


  • bekannt
  • permanent
  • hartnäckig
  • vorübergehend

Die ersten drei sind den entsprechenden Schlüsseln in der Registrierung zugeordnet, in denen Statusinformationen gespeichert werden:


  • Bekannte Namen befinden sich in HKLM \ SYSTEM \ CurrentControlSet \ Control \ Notifications
  • Persistente Namen befinden sich in HKLM \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Notifications
  • Persistente Namen befinden sich in HKLM \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ VolatileNotifications

Bekannte Namen haben ihre eigene Besonderheit: Sie können nicht registriert werden. Ein solcher Name sollte bereits zum Zeitpunkt des Systemstarts in der Registrierung vorhanden sein. Persistente und persistente Namen erfordern das enthaltene SeCreatePermanentPrivilege-Privileg (wie andere globale Objekte), um sie zu erstellen. Persistente Namen befinden sich außerhalb des Registrierungsprozesses, während persistente Namen einen Systemneustart überleben.



Datenumfang


Der Datenbereich definiert die erste Sicherheitsgrenze um den WNF-Statusnamen und bestimmt, wer ihn sieht und Zugriff darauf hat. Der Gültigkeitsbereich des Statusnamens kann sein:


  • das System
  • Auto
  • Benutzersitzung
  • der Benutzer
  • der Prozess

Zusätzlich zur Bereitstellung von Sicherheitsgrenzen können WNF-Bereiche verwendet werden, um verschiedene Dateninstanzen für denselben Namen bereitzustellen. Der Kernel umgeht (wie bei anderen Sicherheitsmechanismen) die Statuszugriffsprüfungen. Das TCB-Privileg ermöglicht den bereichsübergreifenden Zugriff auf WNF-Statusnamen.


Der Bereich "System" und der Bereich "Maschine" sind globale Bereiche. Sie haben keine eigenen Bezeichner (sie verwenden unterschiedliche globale Container). Der Bereich der Benutzersitzung verwendet die Sitzungskennung (Sitzungs-ID) als ID. Der Bereich eines bestimmten Benutzers verwendet die SID dieses Benutzers als Kennung. Die Adresse des EPROCESS-Objekts ist die Kennung des Prozessbereichs.



Sequenznummern


Um die Eindeutigkeit sicherzustellen, hat jeder Statusname eine eindeutige 51-Bit-Sequenznummer. Bekannte Namen enthalten ein 4-stelliges Familien-Tag in ihrer Seriennummer, und die verbleibenden 21 Bits werden als eindeutige Kennung verwendet. Permanente Namen speichern ihre inkrementelle Nummer mit dem Registrierungswert "SequenceNumber". Persistente und temporäre Namen verwenden einen gemeinsamen Inkrementierungszähler, der sich in einer globalen Variablen befindet. Diese Daten werden für jeden Container (pro Silo) separat gespeichert und verarbeitet und sind in PspHostSiloGlobals-> WnfSiloState verfügbar.


In Microsoft hat jeder WNF-Name eine "freundliche" Kennung, die im Code verwendet wird. Manchmal wird er im globalen Namespace mit demselben Namen gespeichert. Zum Beispiel das Symbol nt! WNF_BOOT_DIRTY_SHUTDOWN, das den Wert 0x1589012fa3bc0875 hat. Nach XOR mit der magischen Konstante WNF_STATE_KEY erhalten wir den Wert 0x544f4f4200000801, der bitweise interpretiert werden kann als:


 BOOT1, Well-Known Lifetime, System Scope, Version 1 


Systemaufrufe für die Arbeit mit WNF


Mit Kernel-Systemaufrufen können Sie WNF-Statusnamen registrieren und löschen, WNF-Statusnamendaten veröffentlichen und empfangen sowie verschiedene Benachrichtigungen von WNF erhalten.



Registrieren Sie den WNF-Statusnamen


Mit Ausnahme bekannter Namen (wie bereits erwähnt) kann der WNF-Statusname registriert werden, während das Betriebssystem ausgeführt wird:


 NTSTATUS ZwCreateWnfStateName ( _Out_ PWNF_STATE_NAME StateName, _In_ WNF_STATE_NAME_LIFETIME NameLifetime, _In_ WNF_DATA_SCOPE DataScope, _In_ BOOLEAN PersistData, _In_opt_ PCWNF_TYPE_ID TypeId, //      _In_ ULONG MaximumStateSize, //   4-  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor // **  ); 

Es gibt einen symmetrischen Systemaufruf ZwDeleteWnfStateName, mit dem Sie den registrierten Statusnamen löschen können (außer bei bekannten).



Veröffentlichen Sie WNF-Statusdaten


Zum Festlegen oder Ändern der WNF-Statusnamensdaten können Sie den Systemaufruf ZwUpdateWnfStateData verwenden:


 NTSTATUS ZwUpdateWnfStateData ( _In_ PCWNF_STATE_NAME StateName, _In_reads_bytes_opt_(Length) const VOID* Buffer, _In_opt_ ULONG Length, //   ,   MaximumSize,    _In_opt_ PCWNF_TYPE_ID TypeId, //      _In_opt_ const PVOID ExplicitScope, //  , SID ,  (ID)  _In_ WNF_CHANGE_STAMP MatchingChangeStamp, //     _In_ LOGICAL CheckStamp //         ); 

Es gibt einen symmetrischen Systemaufruf ZwDeleteWnfStateData, um die Daten des WNF-Statusnamens zu löschen (zu bereinigen).



Abrufen von WNF-Statusdaten


Um die WNF-Statusnamensdaten anzufordern, kann der folgende Systemaufruf verwendet werden (die meisten Parameter ähneln der Update-Funktion):


 NTSTATUS ZwQueryWnfStateData ( _In_ PCWNF_STATE_NAME StateName, _In_opt_ PCWNF_TYPE_ID TypeId, _In_opt_ const VOID* ExplicitScope, _Out_ PWNF_CHANGE_STAMP ChangeStamp, _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer, _Inout_ PULONG BufferSize //   0,      ); 

Die wahre Stärke liegt in der Tatsache, dass für die API-Funktionen Update und Query kein registrierter WNF-Statusname erforderlich ist. Und wenn der Name nicht temporär ist (und der aufrufende Code über ausreichende Berechtigungen verfügt), kann eine Instanz des Namens in Echtzeit registriert werden!



WNF-Benachrichtigungen


Bisher haben wir angenommen, dass der Verbraucher weiß, wann er die Datenerfassungsfunktion aufrufen muss. Es gibt aber auch eine Blockierung des Lesens , die mit einem Benachrichtigungssystem funktioniert (das dem tatsächlichen Publisher-Subscriber-Modell näher kommt).


Zunächst muss der Prozess das Ereignis durch Aufrufen der Funktion ZwSetWnfProcessNotificationEvent registrieren. Anschließend müssen Sie die Funktion ZwSubscribeWnfStateChange aufrufen und eine Ereignismaske angeben, um die Abonnement-ID für die Ausgabe abzurufen. Es gibt zwei Arten von Ereignissen:


  • Datenbenachrichtigungen:
    • 0x01 - Datenauftritt
    • 0x10 - Namenszerstörung
  • Meta-Metanotifikationen
    • 0x02 - Erscheinen eines Teilnehmers, der Datenbenachrichtigungen erhält (Datenabonnent)
    • 0x04 - Erscheinen eines Abonnenten, der Meta-Benachrichtigungen erhält (Meta-Abonnent)
    • 0x08 - das Erscheinen eines Abonnenten, der Datenbenachrichtigungen und Meta-Benachrichtigungen erhält (generischer Abonnent)

Dann müssen Sie auf das aufgezeichnete Ereignis warten. Und jedes Mal, wenn das Ereignis zu einem Signal wird, müssen Sie die Funktion ZwGetCompleteWnfStateSubscription aufrufen, die WNF_DELIVERY_DESCRIPTOR zurückgibt.


Diese Low-Level-API-Funktionen haben jedoch ein Problem (danke an Gabi für die Untersuchung): Jeder Prozess kann nur ein registriertes Ereignis haben.



High Level User Mode API (ntdll)


Wenn es um Benachrichtigungen geht, werden die Dinge kompliziert, sodass die RTL-Ebene von ntdll.dll eine einfachere Oberfläche bietet:


 NTSTATUS RtlSubscribeWnfStateChangeNotification ( _Outptr_ PWNF_USER_SUBSCRIPTION* Subscription, _In_ WNF_STATE_NAME StateName, _In_ WNF_CHANGE_STAMP ChangeStamp, _In_ PWNF_USER_CALLBACK Callback, _In_opt_ PVOID CallbackContext, _In_opt_ PCWNF_TYPE_ID TypeId, _In_opt_ ULONG SerializationGroup, _In_opt_ ULONG Unknown ); 

Tatsächlich müssen Systemdienste nicht direkt aufgerufen werden: Verwenden Sie einfach eine einzelne Ereigniswarteschlange, die von ntdll.dll gesteuert wird.


Hinter den Kulissen wird der Inhalt von WNF_DELIVERY_DESCRIPTOR in Rückrufparameter konvertiert:


 typedef NTSTATUS (*PWNF_USER_CALLBACK) ( _In_ WNF_STATE_NAME StateName, _In_ WNF_CHANGE_STAMP ChangeStamp, _In_opt_ PWNF_TYPE_ID TypeId, _In_opt_ PVOID CallbackContext, _In_ PVOID Buffer, _In_ ULONG BufferSize); 

Für jedes neue Abonnement wird ein Eintrag vorgenommen, der in die Liste aufgenommen wird, auf die die globale Variable RtlpWnfProcessSubscriptions verweist. Die Liste basiert auf einem der Felder WNF_NAME_SUBSCRIPTION vom Typ LIST_ENTRY. Jedes von WNF_NAME_SUBSCRIPTION verfügt wiederum über ein anderes LIST_ENTRY-Feld zum Organisieren einer Liste von WNF_USER_SUBSCRIPTION mit einem Rückruf und Kontext.



High Level Kernel Level API (Ex)


WNF bietet auch nahezu identische Funktionen für den Kernelmodus-Code (der vom Treiber verwendet werden kann): sowohl durch exportierte Systemaufrufe als auch über API-Funktionen auf hoher Ebene zur Laufzeit (Ex-Layer).


Die ExSubscribeWnfStateChange-Funktion akzeptiert den Statusnamen, Typmasken und die Adresse der Rückruffunktion + Kontext als Eingabe und gibt einen Abonnementdeskriptor zurück. Die Rückruffunktionen erhalten den Zielnamen, die Ereignismaske, die Änderungsbezeichnung, jedoch nicht den Puffer oder dessen Größe.


Die ExQueryWnfStateData-Funktion liest basierend auf dem übergebenen Abonnementdeskriptor die aktuellen Statusdaten. Tatsächlich ruft jeder Rückruf die ExQueryWnfStateData-Funktion auf, um die mit der Benachrichtigung verknüpften Daten abzurufen.


Sowohl für Kernelmodus-Abonnements als auch für Benutzermodus-Abonnements erstellt WNF (zum Verfolgen von Abonnements) eine Instanz der Struktur WNF_SUBSCRIPTION. Im Benutzermodus werden jedoch einige Felder nicht ausgefüllt, z. B. Rückruf und Kontext, da im Benutzermodus die Adressen der Handler von ntdll.dll gespeichert und verarbeitet werden.



WNF-Datenstrukturen



Von einem Übersetzer : siehe nächster Abschnitt.



WNF-Analyse-Dienstprogramme


Von einem Übersetzer : An dieser Stelle sei noch einmal daran erinnert, dass die Präsentation nicht nur von Alex, sondern auch von Gabrielle Viala durchgeführt wurde . Insbesondere gehört seine Urheberschaft zum unten beschriebenen WnfCom-Modul. Darüber hinaus hat Gabrielle die internen Strukturen von WNF ausreichend detailliert beschrieben (siehe Abbildung im vorherigen Abschnitt). Die meisten Folien fehlen leider im PDF der Präsentation (als Original angegeben) oder sind ausschließlich durch Überschriften gekennzeichnet. Aber:



Und vom Übersetzer : Wenn jemand die aktuelle Übersetzung durch den Inhalt von Gabrielle-Folien ergänzen oder die Übersetzung des wörtlichen Transkripts aus einem beliebigen Teil des Videos der Rede erweitern möchte - willkommen. Um das Hinzufügen / Ändern großer Blöcke zu vereinfachen, kann ich die Übersetzungsquelle auf github (oder einem anderen Versionskontrollserver) veröffentlichen.



Wnfcom


WnfCom ist ein Python-Modul ( Github-Quellcode ), das Interoperabilität über WNF zeigt. Hauptmerkmale:


  • Ermöglicht das Lesen / Schreiben von Daten aus vorhandenen Instanzinstanzen
  • ermöglicht es Ihnen, temporäre Statusnamen zu erstellen (als Server )
  • Mit dieser Option können Sie eine Instanz eines clientseitigen Objekts abrufen , die Benachrichtigungen zum Ändern einer bestimmten Instanz eines Namens verarbeitet

Anwendungsbeispiel:


 >>> from wnfcomimport Wnfcom >>> wnfserver = Wnfcom() >>> wnfserver.CreateServer() [SERVER] StateNamecreated: 41c64e6da5559945 >>> wnfserver.Write(b"potatosoup") Encoded Name: 41c64e6da5559945, Clear Name: 6e99931 Version: 1, Permanent: No, Scope: Machine, Lifetime: Temporary, Unique: 56627 State update: 11 bytes written 

 >>> from wnfcomimport Wnfcom >>> wnfclient = Wnfcom() >>> wnfclient.SetStateName("41c64e6da5559945") >>> wnfclient.Listen() [CLIENT] Event registered: 440 [CLIENT] Timestamp: 0x1 Size: 0xb Data:00000000: 70 6F 74 61 74 6F 20 73 6F 75 70 potato soup 


Wnfdump


WnfDump ist ein in C geschriebenes Befehlszeilenprogramm. Die ausführbare Datei finden Sie unter https://github.com/ionescu007/wnfun, indem Sie das Unterverzeichnis der erforderlichen Bittiefe auswählen. Das Dienstprogramm kann verwendet werden, um nach Informationen zu WNF-Statusnamen zu suchen:


  • -d ( D ump) Gibt alle WNF-Statusnamen mithilfe einer registrierungsbasierten Aufzählung aus. Es kann mit folgenden Optionen ergänzt werden:
    • -v ( V erbose) Eine ausführliche Ausgabe, die einen hexadezimalen Speicherauszug von WNF-Statusdaten enthält.
    • -s (Sicherheit) Sicherheitsbeschreibungen - SDDL-Berechtigungszeichenfolgen für den WNF-Statusnamen.
  • -b ( B rute-force) Direkte Aufzählung temporärer WNF-Statusnamen (mehr dazu weiter unten)
  • -i (Informationen) Zeigt Informationen zu einem einzelnen angegebenen WNF-Statusnamen an
  • -r (Lesen) Liest Daten aus dem angegebenen WNF-Statusnamen
  • -w (Schreiben) Schreiben Sie Daten in den angegebenen WNF-Statusnamen
  • -n (Benachrichtigung) Registrieren Sie einen Benachrichtigungsteilnehmer für den angegebenen WNF-Statusnamen (im Folgenden wird ein spezifischerer Anwendungsfall mit Edge beschrieben).


WNF-Angriffsfläche


In diesem Abschnitt (genauer gesagt in seinen Unterabschnitten) werden mögliche Angriffe und interessante sensible WNF-Daten erörtert.



Privilegierte Datenoffenlegung


Beim Lesen der Tausenden von WNF-Statusnamen, die im System vorhanden sind, können mehrere festgestellt werden, deren Daten sehr interessant aussehen. Unter ihnen waren einige, deren Daten Zeigern oder anderen privilegierten Daten verdächtig ähnlich sind.


Nach dem Spielen auf mehreren Computern war es in einigen Fällen möglich, eine Reihe, einen Stapel und andere privilegierte Informationen zu finden, die über Berechtigungsgrenzen hinweg offengelegt wurden. Fehler- / Schwachstellenberichte wurden im Juli an MSRC übermittelt, aber im November (nach der Präsentation) korrigiert. Zum Beispiel: 4 Kilobyte Stapel sind durch das WNF_AUDC * -Ereignis durchgesickert!


Die Hauptprobleme sind die gleichen wie in früheren Studien von j00ro, taviso und anderen. Bestimmte WNF-Statusnamen enthalten codierte Datenstrukturen mit verschiedenen Auffüll- und / oder Ausrichtungsproblemen. In einigen Fällen tritt nicht initialisierter Speicher aus.
Vom Übersetzer : Übersetzung des einleitenden Teils des Dokuments Erkennen der Offenlegung des Kernelspeichers mit x86-Emulation und Taint-Tracking von Mateusz Jurczyk aka j00ro .



Ermittlung von Statusnamen und Berechtigungen


Der erste Ansatz bestand darin, alle möglichen Statusnamen zu ermitteln, die böswillig manipuliert werden konnten. Bei bekannten, dauerhaften und dauerhaften Namen ist die Aufzählung durch Aufzählung von Registrierungsschlüsseln möglich. Dann können die gefundenen Werte mit benutzerfreundlichen Bezeichnern verglichen werden (es gibt mehrere Stellen, an denen Sie sie finden können :))


Dann können wir uns auch den Sicherheitsdeskriptor in der Registrierung ansehen (dies ist das erste, was sich im Datenpuffer befindet). Die Sicherheitsbeschreibung ist nicht kanonisch: Sie hat keinen Eigentümer und keine Gruppe, ist also technisch nicht gültig. Es ist jedoch kein Problem, einen falschen Eigentümer und eine falsche Gruppe zu ersetzen, um den Sicherheitsdeskriptor zu reparieren .



Erkennung von temporären Statusnamen und deren Berechtigungen


Bei temporären Namen funktionieren die oben beschriebenen Tricks jedoch nicht: Sie befinden sich nicht in der Registrierung. Und nur der Kernel speichert Datenstrukturen für sie (! Wnf) im Speicher. Aber temporäre Namen sind eigentlich gar nicht so schwer zu erzwingen:


  • Version ist immer wichtig 1
  • Die Lebensdauer ist immer wichtig WnfTemporaryStateName
  • Das permanente Flag wird immer gelöscht (der Name des temporären Status kann keine permanenten Daten enthalten).
  • Bereich (Bereich) kann einen von 4 Werten annehmen

Ja, aber die verbleibende Sequenznummer beträgt 51 Bit! In der Tat ... aber vergessen Sie nicht, dass die Seriennummern monoton wachsen. Bei temporären Namen wird die Sequenz bei jedem Start auf 0 zurückgesetzt. Herkömmlicherweise können Sie ein Fenster mit einer Million Seriennummern erstellen: Überprüfen Sie in einer Schleife die Existenz jedes Namens (beginnend mit 0), indem Sie ZwQueryWnfStateNameInformation mit der angeforderten Informationsklasse WnfInfoStateNameExist aufrufen (vorausgesetzt, der Zugriffsfehler zeigt auch das Vorhandensein eines Namens an). Wenn keine weiteren Millionen Namen vorhanden sind, können Sie die Suche beenden.


Temporäre Namenssicherheitsbeschreibungen (wie andere temporäre Namensdaten) werden im Kernel gespeichert. Daher ist die einzige Möglichkeit, sie anzufordern, die Erweiterung! Wnf beim Debuggen des Kernelmodus. Aber wir können:


  • Machen Sie eine Schlussfolgerung zu den Leseberechtigungen, wenn Sie versuchen, Daten zu lesen.
  • Um zu schließen, dass die Aufzeichnung durch den Versuch, Daten zu schreiben, erlaubt ist. Es ist jedoch zu bedenken, dass ein erfolgreiches Schreiben von nur 0 Bytes die Daten zerstört, die der echte Verbraucher noch nicht erhalten hat. Und wieder gibt es einen Trick: Wir können den entsprechenden Änderungsstempel anwenden. Wir versuchen, mit dem Label 0xFFFFFFFF zu schreiben: Das Label wird nach der Zugriffsprüfung überprüft, daher führt der Fehlerwert zu einem Verlust der Schreibberechtigung.

Dies gibt uns keine vollständige Sicherheitsbeschreibung, aber wenn wir den Code mit unterschiedlichen Berechtigungen ausführen, können wir uns ein Bild von den Einschränkungen für verschiedene Systemkonten machen (Low IL / User / Admin / SYSTEM).



Abonnenten auflisten


In der Struktur WNF_PROCESS_CONTEXT ist eines der Felder der Listenkopf (LIST_ENTRY) aller Abonnements dieses Prozesses. Jedes Abonnement ist eine separate Instanz von WNF_SUBSCRIPTION.


Abonnenten im Kernel-Modus gehören in erster Linie dem Systemprozess. Mit dem Befehl! List debugger können Sie Handler und ihre Parameter ausgeben, die im Systemprozess WNF_SUBSCRIPTION registriert sind. Es ist erwähnenswert, dass in einigen Fällen ein Ereignisaggregator (CEA.SYS) verwendet wird, der die tatsächlichen Rückrufadressen in seiner Kontextstruktur verbirgt.


Wir können diesen Ansatz für Prozesse im Benutzermodus wiederholen, aber die Rückrufadresse ist NULL, da dies Abonnenten im Benutzermodus sind. Daher müssen wir dem Benutzerbereich des Prozesses beitreten, die Tabelle RtlpWnfProcessSubscriptions abrufen und dann die Liste der WNF_USER_SUBSCRIPTION-Instanzen sichern, von denen jede bereits die Rückrufadresse enthält. Leider ist dieses Zeichen statisch, was bedeutet, dass es sich nicht um offene Zeichen handelt, sondern durch Zerlegen gefunden werden kann. Auch hier lohnt es sich (analog zum CEA.SYS-Kernelmodus) darauf zu achten, dass viele der Benutzermodus-Handler den Ereignisaggregator (EventAggregation.dll) verwenden, der den Rückruf in seinem Kontext speichert.



Interessante und sensible WNF-Staatsnamen


Dieser Abschnitt enthält einige interessante Beispiele dafür, wie einige WNF-Statusnamen Systeminformationen anzeigen.



Ermitteln des Systemstatus und des Benutzerverhaltens mithilfe von WNF


Einige WNF-Kennungen können verwendet werden, um Informationen über den Status der Maschine abzurufen, die Sie interessiert:


  • WNF_WIFI_CONNECTION_STATUS - Drahtloser Status
  • WNF_BLTH_BLUETOOTH_STATUS - ähnlich, aber für Bluetooth (auch WNF_TETH_TETHERING_STATE)
  • WNF_UBPM_POWER_SOURCE - Zeigt die Stromquelle (Batterie oder Netzteil) an.
  • WNF_SEB_BATTERY_LEVEL - enthält den Batteriestand
  • WNF_CELL_ * - unter Windows Phone enthält Informationen über: Netzwerk, Nummer, Signalstärke, EDGE oder 3G, ...

WNF :


  • WNF_AUDC_CAPTURE/RENDER — ( PID), /
  • WNF_TKBN_TOUCH_EVENT — ,
  • WNF_SEB_USER_PRESENT/WNF_SEB_USER_PRESENCE_CHANGED — Windows


API


, API , API , , /. WNF . , , WNF .


: WNF_SHEL_(DESKTOP)_APPLICATION_(STARTED/TERMINATED) modern- ( , ) DCOM, Win32. — ShellExecute: Explorer, cmd.exe, ...


, WNF API , :


  • WNF_SHEL_LOCKSCREEN_ACTIVE —
  • WNF_EDGE_LAST_NAVIGATED_HOST — URL, ( ) Edge

: Edge



WNF


WNF, . : WNF_FSRL_OPLOCK_BREAK — , (/), PID' !


WNF , . : WNF_SHEL_DDC_(WNS/SMS)_COMMAND – 4 , .


, WNF, . : WNF_CERT_FLUSH_CACHE_TRIGGER ( ), WNF_BOOT_MEMORY_PARTITIONS_RESTORE, WNF_RTDS_RPC_INTERFACE_TRIGGER_CHANGED, ...



WNF


:


  • WriteProcessMemory —
  • ( ) —
  • (Atom) —
  • — , WM_COPYDATA DDE,
  • GUI — ( ) ,

WNF :


  • WNF, (, )
  • Rtl/ZwQueryWnfStateData WNF

, :


  • APC s
  • (Remote Threads)
  • (Changing Thread Context)
  • " window long " — , ,

WNF_USER_SUBSCRIPTION ( WNF_NAME_SUBSCRIPTION, RtlpWnfProcessSubscriptions). ( CFG ), ( 5 6 ).


, : , , , -.




WNF SEB_, ( S ystem E vents B roker). SystemEventsBrokerServer.dll SystemEventsBrokerClient.dll API . , SEB SEB, .


CEA.SYS EventAggregation.dll. " " (Event Aggregation Library), , : , , WNF , . WNF, . .




: .






, Windows Notification Facility Alex' Gabrielle. ( ) redp .



WNF ( ) wincheck . , Gabrielle Viala , redp, : http://redplait.blogspot.com/search/label/wnf .




PoC ( github ) explorer ( — notepad). modexp : Callback WNF_USER_SUBSCRIPTION. :


  • explorer.exe
  • WNF_USER_SUBSCRIPTION
  • RWX- , WriteProcessMemory (, VirtualAllocEx + WriteProcessMemory)
  • WNF_USER_SUBSCRIPTION ( WriteProcessMemory)
  • ntdll!NtUpdateWnfStateData(...) ,
  • WNF_USER_SUBSCRIPTION

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


All Articles