Plattformsicherheit mit Ablaufsteuerungsschutz
Was ist der Ablaufsteuerungsschutz?
Beim Ablaufsteuerungsschutz (Control Flow Guard, CFG) handelt es sich um eine hochgradig optimierte Plattformsicherheitsfunktion, die erstellt wurde, um auf Speicherbeschädigungs-Sicherheitsrisiken zu reagieren. Durch die strikte Beschränkung der Orte, von denen aus eine Anwendung Code ausführen kann, wird es für Exploits wesentlich schwieriger, über Schwachstellen wie Pufferüberläufe beliebigen Code auszuführen. CFG erweitert frühere Technologien zur Exploit-Reduzierung wie /GS (Puffersicherheitsprüfung), Datenausführungsverhinderung (Data Execution Prevention, DEP) und Zufällige Anordnung des Adressraumlayouts (Address Space Layout Randomization, ASLR).
Die Verwendung von CFG kann Folgendes unterstützen:
- Verhindern von Speicherbeschädigungen und Ransomware-Angriffen
- Beschränken der Funktionen des Servers auf das, was zu einem bestimmten Zeitpunkt benötigt wird, um die Angriffsfläche zu reduzieren
- Es schwieriger machen, beliebigen Code durch Sicherheitsrisiken wie Pufferüberläufe auszunutzen
Dieses Feature ist in Microsoft Visual Studio verfügbar und wird in CFG-Aware-Versionen von Windows ausgeführt. Windows 10 und Windows 11 auf dem Client und Windows Server 2019 und höher serverseitig.
Entwickler werden dringend ermutigt, CFG für ihre Anwendungen zu aktivieren. Sie müssen CFG nicht für Ihren kompletten Code aktivieren; eine Mischung aus Code mit und ohne CFG wird einwandfrei ausgeführt. Wenn CFG jedoch nicht für den gesamten Code aktiviert wird, können Schwachstellen entstehen. Außerdem funktioniert CFG-fähiger Code auch in Windows-Versionen ohne CFG-Unterstützung einwandfrei und ist vollständig kompatibel.
Wie kann ich CFG aktivieren?
In den meisten Fällen ist es nicht erforderlich, den Quellcode zu ändern. Sie müssen nur eine Option zu Ihrem Visual Studio-Projekt hinzufügen, und der Compiler und Linker aktivieren CFG.
Die einfachste Methode besteht darin, zu Projekt | Eigenschaften | Konfigurationseigenschaften | C/C++ | Codegenerierung zu navigieren und Ja (/guard:cf) für den Ablaufsteuerungsschutz auszuwählen.
Alternativ können Sie /guard:cf zu Projekt | Eigenschaften | Konfigurationseigenschaften | C/C++ | Befehlszeile | Zusätzliche Optionen (für den Compiler) und /guard:cf zu Projekt | Eigenschaften | Konfigurationseigenschaften | Linker | Befehlszeile | Zusätzliche Optionen (für den Linker) hinzuzufügen.
Weitere Informationen finden Sie unter /guard (Ablaufsteuerungsschutz aktivieren ).
Wenn Sie Ihr Projekt über die Befehlszeile erstellen, können Sie dieselben Optionen hinzufügen. Wenn Sie beispielsweise ein Projekt mit dem Namen „test.cpp“ kompilieren, verwenden Sie cl /guard:cf test.cpp /link /guard:cf.
Sie haben auch die Möglichkeit, den Satz von icall-Zieladressen dynamisch zu steuern, die von CFG mithilfe von SetProcessValidCallTargets aus der Speicherverwaltungs-API als gültig betrachtet werden. Dieselbe API kann verwendet werden, um anzugeben, ob Seiten ungültige oder gültige Ziele für CFG sind. Die Funktionen VirtualProtect und VirtualAlloc behandeln standardmäßig einen bestimmten Bereich von ausführbaren und zugesicherten Seiten als gültige indirekte Aufrufziele. Es ist möglich, dieses Verhalten außer Kraft zu setzen, z. B. beim Implementieren eines Just-in-Time-Compilers durch Angabe von PAGE_TARGETS_INVALID beim Aufrufen von VirtualAlloc oder PAGE_TARGETS_NO_UPDATE beim Aufrufen von VirtualProtect, wie detailliert unter Speicherschutzkonstanten angegeben.
Wie erkenne ich, dass eine Binärdatei unter „Ablaufsteuerungsschutz“ steht?
Führen Sie das dumpbin-Tool (in der Visual Studio-Installation enthalten) aus der Visual Studio-Eingabeaufforderung mit den Optionen /headers und /loadconfig: dumpbin /headers /loadconfig test.exe aus. Die Ausgabe für eine Binärdatei unter CFG sollte zeigen, dass die Header-Werte „Guard“ und die Ladekonfigurationswerte „CF Instrumented“ und „FID-Tabelle vorhanden“ enthalten.
Wie funktioniert CFG wirklich?
Software-Schwachstellen werden häufig ausgenutzt, indem einem laufenden Programm unwahrscheinliche, ungewöhnliche oder extreme Daten übermittelt werden. Ein Angreifer kann beispielsweise einen Pufferüberlauf auslösen, indem er mehr Daten als erwartet an ein Programm weitergibt und dadurch den vom Programm für die Aufnahme einer Antwort reservierten Bereich überschreitet. Dadurch können benachbarte Arbeitsspeicheradressen beschädigt werden, die möglicherweise einen Funktionszeiger enthalten. Wenn das Programm dann diese Funktion aufruft, kann es zu einer unbeabsichtigten Speicheradresse springen, die vom Angreifer festgelegt wurde.
Eine starke Kombination aus Kompilierung und Laufzeitunterstützung von CFG implementiert jedoch die Steuerungsflussintegrität, die eng einschränkt, wo indirekte Aufrufanweisungen ausgeführt werden können.
Der Compiler führt die folgenden Aktionen aus:
- Fügt dem kompilierten Code einfache Sicherheitsprüfungen hinzu.
- Identifiziert den Satz von Funktionen in der Anwendung, die gültige Ziele für indirekte Aufrufe sind.
Die vom Windows-Kernel bereitgestellte Laufzeitunterstützung:
- Behält effizient den Status bei, der gültige indirekte Aufrufziele identifiziert.
- Implementiert die Logik, die überprüft, ob ein indirektes Aufrufziel gültig ist.
Zur Veranschaulichung:
Wenn eine CFG-Prüfung zur Laufzeit fehlschlägt, beendet Windows das Programm sofort und verhindert so jeden Exploit, der versucht, indirekt eine ungültige Adresse aufzurufen.