1 Punkte von GN⁺ 2025-05-13 | 1 Kommentare | Auf WhatsApp teilen
  • defendnot, entstanden während einer Reise nach Seoul, war ein Tool, das die Windows-Security-Center-(WSC-)Service-API direkt aufrief, um Windows Defender zu deaktivieren – und führte zu mehreren Tagen Reverse Engineering
  • Das frühere Tool no-defender nutzte bestehenden Antivirus-Code, um bei WSC zu registrieren, dass ein anderer Virenschutz vorhanden sei; nach rund 1,5k GitHub-Sternen wurde es auf DMCA-Antrag des Antivirus-Herstellers gelöscht
  • Zunächst ließen sich die COM-API-Aufrufe von WSC in etwa einer Stunde nachbilden, doch da WSC den aufrufenden Prozess verifiziert, wurde der Zugriff aus normalen Prozessen verweigert
  • Die Analyse zeigte, dass WSC die WinDefend-SID, Administratorrechte, Signatur und im PE-DllCharacteristics-Feld das ForceIntegrity-Flag prüfte; in der finalen Implementierung wurde Taskmgr.exe verwendet
  • In einer Umgebung mit arm64-MacBook, Remote-PC in den USA, 210 ms Latenz über Parsec und einer Shadow.tech-VM wurde die Implementierung abgeschlossen, nachdem ein ctx.bin-Pfadfehler und ein Problem mit Energiebedingungen beim Autorun behoben waren

Hintergrund: Wie es zu defendnot kam

  • defendnot ist ein Tool, das die Windows-Security-Center-Service-API direkt nutzt, um Windows Defender zu deaktivieren
  • Der Kern der Implementierung lag weniger im WSC-Aufruf selbst, sondern darin, die Schutz- und Prüfbedingungen sowie die unbequeme Arbeitsumgebung Schritt für Schritt zu umgehen
  • Ausführlichere technische Dokumentation zu WSC soll später von jemand anderem veröffentlicht werden

no-defender und DMCA vor einem Jahr

  • Das vor etwa einem Jahr veröffentlichte no-defender nutzte eine Windows-API für Antivirus-Produkte, um Windows Defender abzuschalten
  • Diese API ist dafür gedacht, dem System mitzuteilen: „Es gibt einen anderen Virenschutz, daher muss Defender keinen Scan ausführen“
  • Die Systemkomponente, die diesen Bereich verwaltet, ist das Windows Security Center (WSC)
  • no-defender funktionierte, indem es Third-Party-Code eines bestehenden Antivirus-Produkts nutzte und erzwang, dass sich dieses Produkt bei WSC registriert
  • Innerhalb weniger Wochen nach Veröffentlichung erhielt es rund 1,5k stars; nachdem der Hersteller des verwendeten Antivirus-Produkts einen DMCA-Takedown beantragt hatte, wurde der Repository-Inhalt gelöscht und die Sache beendet

Während der Seoul-Reise wieder mit der WSC-Analyse begonnen

  • Während eines Aufenthalts in einem Airbnb in Seoul schrieb MrBruh, der sich no-defender angesehen hatte, dass er untersuche, ob eine „saubere“ Implementierung ohne Antivirus-Binary möglich sei
  • Für CTFs oder x86-Reversing-Aufgaben nimmt der Autor normalerweise ein separates x86-Notebook mit, hatte auf dieser Reise aber nur ein M4Pro MacBook dabei
  • Trotz der ungünstigen Bedingungen ohne x86-Reversing-Hardware begann die WSC-Analyse in der Zeit, bevor die Freunde aufwachten

Tag 1: WSC-COM-API nachgebildet und erste Zugriffssperre

  • MrBruh stellte aktuelle WSC-Binaries bereit, und die zuvor genutzte WSC-Registrierungsimplementierung des Antivirus diente als Referenz
  • WSC bietet eine COM-API, die Antivirus-Produkte verwenden; die Aufrufe des bestehenden Antivirus ließen sich in etwa einer Stunde nachbilden
  • Zum Testen wurde arm64-Windows in Parallels gebootet, das Ergebnis war jedoch access denied
  • Aus früherer Erfahrung war bekannt, dass WSC den Prozess prüft, der die API aufruft; zunächst lag der Verdacht auf einer Signaturprüfung
  • Nachdem Code in den Prozess injiziert wurde, den der bestehende Antivirus für WSC-Aufgaben verwendete, funktionierten die COM-Aufrufe zur Registrierung eines neuen Antivirus und zur Statusaktualisierung korrekt

Versuch, die Antivirus-Binary zu entfernen

  • Damit das neue Projekt nicht erneut Einwände des bestehenden Antivirus-Anbieters auslöst, sollte statt der Antivirus-Binary eine vom System bereitgestellte Binary verwendet werden
  • Als erster Zielprozess wurde cmd.exe gewählt, doch die WSC-API-Aufrufe wurden verweigert
  • Ein Blick in wscsvc.dll zeigte Code, der prüfte, ob der aufrufende Prozess PPL ist
  • Ein per schlichtem CreateProcessA erzeugter Prozess war kein PPL-geschützter Prozess, und in dieser Nacht ging es nicht weiter

Tag 2: Eine unbequeme Remote-Debugging-Umgebung aufbauen

  • Auf dem arm64-MacBook war x86-Windows schwer vernünftig zu handhaben, und der Autor wollte vermeiden, in einer arm64-Umgebung zu arbeiten oder auf x64dbg verzichten zu müssen
  • Der Freund pindos erlaubte den Zugriff auf seinen PC, die Remote-Verbindung lief über Parsec
  • Da die Verbindung von Korea zu einem PC in den USA ging, lag die durchschnittliche Latenz bei etwa 210 ms
  • Der damalige Workflow war äußerst umständlich
    • Modul unter Windows arm64 in Parallels mit MSVC bauen
    • Build-Artefakte über einen Shared Folder mit dem Host teilen
    • Artefakte per AnyDesk in eine VM auf pindos’ PC kopieren
    • Den WSC-Service in einer Parsec-Umgebung mit 210 ms Latenz debuggen
  • Die Umgebung war so unbequem, dass Entwicklungs- und Analysegeschwindigkeit stark litten

WSC-Service-Debugging und WinDefend-SID

  • Der WSC-Service ist eine von svchost ausgeführte DLL; der wichtigste Faktor, der das Anhängen eines Debuggers verhinderte, war der PPL-Schutz
  • In der VM wurde der Testmodus aktiviert, und ein Treiber verwendet, der im Kernel-Mode mit wenigen Zeilen Code PPL beim Zielprozess entfernte
  • Der Punkt, an dem cmd.exe beim Versuch scheiterte, bei WSC einen Antivirus zu registrieren, war WscServiceUtils::CreateExternalBaseFromCaller
  • Diese Funktion imitiert den RPC-Client und prüft anschließend, ob das Token des aufrufenden Prozesses die WinDefend-SID enthält
  • Da das Verhalten von Windows-Tokens zu diesem Zeitpunkt nicht gut verstanden war, entstand die Einschätzung, man könne die Prüfung bestehen, indem man WinDefend imitiert
  • Unter Schlafmangel wurde zudem fälschlich interpretiert, dass auch die bestehende Antivirus-Binary diese IsMember-Prüfung bestehe

Versuch und Scheitern der WinDefend-Impersonation

  • Nach einigen Stunden Beschäftigung mit Windows-Tokens wurde eine Implementierung in Richtung eines Tokens mit enthaltener WinDefend-SID gebaut, um die WSC-Prüfung zu bestehen
  • Code wurde mit an cmd angehängter WinDefend-SID ausgeführt; obwohl der COM-Aufruf STATUS_SUCCESS zurückgab, wurde tatsächlich kein neuer Antivirus registriert
  • Dieser Ansatz erwies sich letztlich als nicht nützlich und musste am nächsten Tag erneut überprüft werden

Tag 3: Den echten Verifikationsalgorithmus rekonstruiert

  • Bei erneuter Prüfung zeigte sich, dass die bestehende Antivirus-Binary die WinDefend-SID-Prüfung nicht bestand
  • Wenn diese Prüfung bestanden wird, landet man beim WSC-Objekt von Windows Defender; allein mit WSC-Aufrufen lässt sich Defender aber nicht direkt deaktivieren, daher war das nutzlos
  • Der Code zur WinDefend-Impersonation wurde entfernt und der andere Zweig der Bedingung analysiert
  • In diesem Zweig wird für die aufrufende Binary Folgendes geprüft
    • ob der Prozess elevated ist
    • ob die Binary-Signatur gültig ist
    • ob in den DllCharacteristics des PE ein bestimmtes Flag gesetzt ist
  • Das in CSecurityVerificationManager::CreateExternalBaseFromPESettings geprüfte DllCharacteristics-Flag war ForceIntegrity
  • Code, der die Binary-Prüfung von WSC nachbildet, wurde im Ordner wsc-binary-check des defendnot-Repositorys erstellt und gegen System32-Binaries getestet

Taskmgr.exe verwendet und ctx.bin-Bug

  • Da der Freund seinen PC wieder selbst brauchte, wurde direkt per Parsec auf die VM zugegriffen; zusammen mit Software-Encoding wurde die Umgebung noch langsamer
  • Statt cmd.exe wurde Taskmgr.exe verwendet, doch es traten weiterhin RPC-Fehler auf
  • Wegen Latenz und Eingabeproblemen wurde das Debugging in derselben VM schwierig; auf Empfehlung wurden $30 für ein Abo bei shadow.tech bezahlt
  • Die Shadow.tech-VM hatte eine ältere Windows-Version, in der der wscsvc-Code noch nicht so stark wie in der neuesten Version in eine Funktion inline eingebettet war; auch das Decompiler-Ergebnis war besser lesbar
  • Die tatsächliche Fehlerursache war ein falscher AV-Name, der an WSC übergeben wurde
    • Um Daten von defendnot-loader an defendnot.dll zu übergeben, wurde ctx.bin mit serialisierten Parametern verwendet
    • Für die Statusverfolgung war separates IPC implementiert, doch für die Konfigurationsübergabe blieb die alte ctx.bin-Methode als Überbleibsel aus no-defender erhalten
    • Die Funktion zum Finden des ctx.bin-Pfads orientierte sich nicht am Basisordner von nodefend.dll, sondern am Basisordner des Moduls Taskmgr.exe
    • Dadurch wurde ein Null-Byte als AV-Name übergeben, und WSC lehnte diesen Buffer ab
  • Nach Behebung des Pfadproblems war der Test erfolgreich

Code aufräumen und Autorun-Problem

  • Um noch am selben Tag fertig zu werden, wurden bis 8 Uhr morgens Code aufgeräumt und zusätzliche Funktionen implementiert
  • Zu den zusätzlichen Funktionen gehörte, sich selbst zu autorun hinzuzufügen
  • Um 8 Uhr morgens funktionierte nur Autorun noch nicht richtig; nach dem Testen mehrerer Methoden ohne Erfolg ging der Autor schlafen
  • Am nächsten Tag stellte sich heraus, dass zwei Energieoptionen beim Erstellen der Aufgabe im Task Scheduler die Ursache waren
  • Da das Notebook nicht am Netzteil hing, wurde die Aufgabe nicht ausgeführt; nach Deaktivierung dieser Flags funktionierte Autorun
  • Danach wurde der Code noch einige Stunden weiter aufgeräumt und die Arbeit abgeschlossen

Fazit

  • Die Arbeit selbst machte Spaß, aber die über mehrere Tage wiederkehrenden Umgebungsprobleme und der Remote-Debugging-Workflow waren eine Erfahrung, die der Autor nicht wiederholen möchte
  • Insbesondere arm64-MacBook, Remote-x86-VM, hohe Latenz, langsames Encoding und der spät sichtbar gewordene Dateipfad-Bug erhöhten die Implementierungsschwierigkeit erheblich
  • Eine technischere WSC-Dokumentation soll später separat veröffentlicht werden

1 Kommentare

 
GN⁺ 2025-05-13
Hacker-News-Kommentare
  • Die invasivste, aber effektivste Methode, Defender auszuschalten, war, von einem Live-Linux-USB-Stick zu booten, C:\ProgramData\Microsoft\Windows Defender umzubenennen und an dieser Stelle eine leere Datei anzulegen

    • Gruppenrichtlinien funktionieren weiterhin sehr gut; ich habe in meinem Homelab einen lokalen Domain Controller, der für alle Nutzer nur die Defender-Richtlinien automatisch ändert
    • Ein populäres Produkt funktionierte im Grunde fast genauso und hat dabei ungefähr 25 % des gesamten Internets mit heruntergerissen
    • Seltsam, dass Windows solche Änderungen nicht über signierte Manifeste erkennt
  • Zur Einordnung: WSC steht für Windows Security Center

  • Die Formulierung the antivirus I was using hat mich ziemlich verwirrt. Ich habe nicht verstanden, warum der Anbieter dieses Antivirenprogramms dem Autor einen DMCA-Takedown schicken sollte
    Vermutlich ist gemeint, dass der Autor ein anderes Antivirenprogramm reverse-engineert und Teile davon in ein Open-Source-Projekt eingebaut hat. Da aber auch Titel wie Impersonating WinDefend auftauchen, frage ich mich am Ende, ob der Autor auf irgendeine Weise gegen das Urheberrecht verstoßen hat

    • Soweit ich es verstehe, hat er wohl die Hülle eines anderen Antiviren-Tools benutzt, um die Signaturanforderungen zu umgehen. Ich verstehe, dass das eine Grauzone ist, und denke, man könnte es vielleicht als transformative Nutzung sehen, aber ich bin kein Jurist
    • Genau. Er hat Teile eines bestehenden Antivirenprogramms kopiert und damit gegen das Urheberrecht verstoßen
      Direkt vor dem zitierten Absatz steht die Erklärung, dass „das Projekt Third-Party-Code eines bereits existierenden Antivirus verwendete und diesen Antivirus zwang, sich bei WSC als Antivirus zu registrieren“
  • Dieser Code wirkt verflucht:
    https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
    Falls ihr wissen wollt, was tatsächlich passiert, hier:
    https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...

    • Kann jemand, der sich mit C++-Magie auskennt, erklären, was da passiert und warum das als verflucht bezeichnet wird?
    • Wegen Zeitdruck wollte ich RAII für COM-bezogene Objekte nicht selbst direkt implementieren. Wird aber im nächsten Update geändert
    • Ich weiß nicht, was daran verflucht sein soll. Die Signatur an der Aufrufstelle würde ich persönlich etwas anders gestalten, aber ich nutze dieses Pattern in meinem eigenen Code auch an vielen Stellen
      In der Sprache D gibt es zum Beispiel ein Sprachkonzept für Statements, die am Ende eines Scopes ausgeführt werden
    • „Code is how you treat your co-workers“ – Michael Feather, https://x.com/mfeathers/status/1031176879577780224
      Kurz gesagt: Das ist nicht von einer KI geschrieben. Dieser Code verzögert einen Funktionsaufruf, bis ein Objekt den Scope verlässt. Die Implementierung erzeugt per C-Makro eine kürzere Syntax, die Teile der nötigen C-Lambda-/anonymen Funktionsdefinition weglässt, und generiert einen eindeutigen Variablennamen zur Verwaltung des verzögerten Aufrufs
      Allerdings vermeidet die resultierende Syntax die übliche Konvention, C-Makros in Großbuchstaben zu schreiben, und sieht auf den ersten Blick wie ein Funktionsaufruf über einen Objektzeiger aus. Wenn man mit diesem Pattern nicht vertraut ist oder erwartet, dass Makros anders kenntlich gemacht werden, kann das verwirrend sein
      Für manche ist es häufig und nützlich genug, dass man es in bestimmten Kontexten fast als Idiom ansehen kann. Eine technische Erklärung findet sich unter https://news.ycombinator.com/item?id=43959403#43960905; dort wird gut aufgeschlüsselt, wie das Makro funktioniert
  • Ich habe im Urlaub die virtuellen Desktops von Windows reverse-engineert, und das hat meinen Urlaub viel besser gemacht. Meine schönste Erinnerung vom letzten Jahr war die Erkenntnis, dass Reverse Engineering wirklich Spaß macht
    Ich habe auch viel Interessantes gelernt; unter Windows gibt es unterhalb von RPC eine undokumentierte Messaging-Schicht: https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....

  • Wenn das Profilbild eine Anime-Figur ist, weiß ich jedes Mal, dass der Beitrag gut sein wird. Für den Fall gespeichert, dass ich irgendwann wieder in eine eher miese Windows-Umgebung zurückmuss

  • Für alle, die sich wundern: WSC steht für Windows Security Center. Ich musste es auch nachschlagen

    • Im Artikel steht: „Der Teil des Systems, der dieses Chaos verwaltet, heißt Windows Security Center, kurz WSC“
  • Warum sollte man WSC überhaupt abschalten wollen?

    • Vielleicht wegen der Performance, vielleicht für Malware-Entwicklung oder Hacking
    • Als Angreifer könnte man auf den Glücksfall setzen, dass kein anderes Endpoint-Detection-and-Response-Produkt installiert ist. Wenn doch, wird es das ziemlich sicher abfangen
      Wenn man EDR-Anbieter ist: Das ist ein verschleierter API-Aufruf, mit dem sich die Windows Firewall unterdrücken oder deaktivieren lässt. CrowdStrike etwa kann meiner Einschätzung nach sowohl die Windows Firewall nutzen als auch eine eigene Implementierung
    • Es ist meine Hardware, also mache ich damit, was ich will
    • Jede Antivirensoftware ist mindestens ein Powervirus. Ich will nicht, dass sich jemand wie ein Kindermädchen einmischt und mir sagt, netcat.exe gehe nicht
    • Weil es keinen Grund gibt, sich absichtlich selbst ein Rootkit einzupflanzen
  • Ich habe vor Kurzem https://nostarch.com/windows-security-internals gelesen, und durch diesen Artikel hat das deutlich mehr Sinn ergeben
    Ich wusste schon grob, wie solche internen Abläufe unter Windows funktionieren, aber das Timing war gut. Das letzte Kapitel des Buchs geht ebenfalls ziemlich detailliert auf Tokens und SIDs ein, ähnlich wie es der Autor dieses Artikels behandelt