/GS (Puffer-Sicherheitsüberprüfung)

Aktualisiert: November 2007

Erkennt bestimmte Pufferüberläufe, die die Rücksprungadresse überschreiben. Dies ist eine verbreitete Technik, um Code anzugreifen, der Größenbeschränkungen von Puffern nicht überwacht. Pufferüberläufe werden dabei durch Sicherheitsprüfungen erkannt, die in den kompilierten Code eingefügt werden.

/GS[-]

Hinweise

/GS ist standardmäßig aktiviert. Verwenden Sie /GS-, wenn Sie davon ausgehen, dass die Anwendung keinerlei Sicherheitsrisiken ausgesetzt ist.

Weitere Informationen über /GS finden Sie unter Compiler Security Checks In Depth.

Der Compiler fügt Prüfungen in Funktionen ein, wenn diese mit lokalen Zeichenfolgenpuffern arbeiten oder (auf x86-Systemen) über eine Ausnahmebehandlung verfügen. Ein Zeichenfolgenpuffer wird als Array definiert, wobei die Elementgröße 1 oder 2 Bytes und die Gesamtgröße des Arrays mindestens 5 Bytes beträgt oder ein beliebiger mit _alloca reservierter Puffer ist.

Der Compiler fügt auf allen Plattformen ein Cookie ein, um die Rücksprungadresse der Funktion zu schützen, falls die Funktion über lokale Zeichenfolgenpuffer verfügt. Dieses Cookie wird bei Funktionsende überprüft. Es wird außerdem überprüft, wenn auf 64-Bit-Betriebssystemen Rahmen entladen werden oder auf x86-Systemen eine beliebige Form der Ausnahmebehandlung für Funktionen durchgeführt wird. Auf x86-Systemen fügt der Compiler zusätzlich ein Cookie ein, um die Adresse des Ausnahmehandlers der Funktion zu schützen. Dieses Cookie wird beim Entladen von Rahmen überprüft.

Durch /GS wird vorrangig versucht, direkte Pufferüberläufe in die Rücksprungadresse zu ermitteln. Auf Computern mit Aufrufkonventionen, durch die die Rücksprungadresse von Funktionsaufrufen auf dem Stapel gespeichert wird, lassen sich Pufferüberläufe leichter ausnutzen. So verwendet z. B. die x86-Architektur Aufrufkonventionen, durch die die Rücksprungadresse von Funktionsaufrufen auf dem Stapel gespeichert wird.

Bei Funktionen, die vom Compiler als überlaufgefährdet und problematisch eingestuft werden, reserviert der Compiler vor der Rückgabeadresse Speicherplatz auf dem Stapel. Beim Funktionsstart wird der reservierte Platz mit einem Sicherheitscookie geladen, der beim Laden des Moduls einmal berechnet wird. Bei Funktionsende wird dann eine Hilfsfunktion aufgerufen, die sicherstellt, dass sich der Wert des Cookies nicht geändert hat.

Wenn sich die Werte unterscheiden, wurde der Stapel möglicherweise überschrieben, und der Prozess wird einfach beendet. Vor Visual C++ 2005 wurde ein Dialogfeld angezeigt, das darüber informierte, dass der Stapel überschrieben wurde.

/GS bietet auch Schutz vor verwundbaren Parametern, die einer Funktion übergeben werden. Ein verwundbarer Parameter ist ein Zeiger, ein C++-Verweis oder eine C-Struktur (C++-POD-Typ), die einen Zeiger, einen Zeichenfolgenpuffer oder einen C++-Verweis enthält.

Ein verwundbarer Parameter wird vor dem Cookie und den lokalen Variablen zugeordnet. Durch einen Pufferüberlauf kann dieser Parameter überschrieben werden. Der in der Funktion enthaltene Code, der diesen Parameter verwendet, kann für einen Angriff ausgenutzt werden, bevor der Rücksprung aus der Funktion erfolgt. Dadurch wird die Sicherheitsprüfung umgangen. Um diese Gefahr zu minimieren, erstellt der Compiler während des Funktionsprologs eine Kopie der verwundbaren Parameter und legt diese unterhalb des Speicherbereichs ab, in dem sich sämtliche Puffer befinden.

In den folgenden Situationen bietet der Compiler keinen Sicherheitsschutz vor verwundbaren Parametern:

  • Bei Funktionen, die keinen Puffer enthalten.

  • Wenn die Optimierungen (/O-Optionen (Code optimieren)) nicht aktiviert werden.

  • Bei Funktionen mit variabler Argumentliste (...).

  • Bei Funktionen, die mit naked (C++) markiert sind.

  • Bei Funktionen, die Inlineassemblycode in der ersten Anweisung enthalten.

  • Wenn ein Parameter nur auf eine Art und Weise verwendet wird, die im Falle eines Pufferüberlaufs höchstwahrscheinlich nicht ausgenutzt werden kann.

/GS erfordert Initialisierung des Sicherheitscookies. Dieses Cookie muss initialisiert werden, bevor Funktionen ausgeführt werden können, die das Cookie verwenden. Das Sicherheitscookie muss beim Einstieg in eine EXE oder DLL initialisiert werden. Dies geschieht automatisch, wenn die CTR-Standardeinstiegspunkte (mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup oder _DllMainCRTStartup) verwendet werden. Die Initialisierung muss jedoch manuell über einen Aufruf von__security_init_cookie ausgeführt werden, wenn Sie einen anderen Einstiegspunkt verwenden.

/GS wird für verwaltete Funktionen unterstützt, wenn sie mit /clr (Common Language Runtime-Kompilierung) kompiliert werden.

/GS bietet keinen vollständigen Schutz vor Sicherheitsangriffen durch Pufferüberläufe. Wenn ein Objekt z. B. einen Puffer und eine vtable enthält, könnte der Pufferüberlauf die vtable überschreiben und so einen Angriff ermöglichen.

Sie sollten auch bei Verwendung von /GS immer darauf achten, sicheren Code zu schreiben. Das heißt, Sie sollten von Anfang an sicherstellen, dass der Code keine Pufferüberläufe aufweist. /GS kann Ihre Anwendung vor Pufferüberläufen schützen, die trotzdem im Code verbleiben.

So legen Sie diese Compileroption in der Visual Studio-Entwicklungsumgebung fest

  1. Öffnen Sie das Dialogfeld Eigenschaftenseiten des Projekts. Ausführliche Informationen finden Sie unter Gewusst wie: Öffnen von Projekteigenschaftenseiten.

  2. Klicken Sie auf den Ordner C/C++.

  3. Klicken Sie auf die Eigenschaftenseite Codegenerierung.

  4. Ändern Sie die Eigenschaft Puffer-Sicherheitsüberprüfung.

So legen Sie diese Compileroption programmgesteuert fest

Beispiel

In diesem Beispiel wird ein Puffer überschrieben. Dies bewirkt, dass die Anwendung zur Laufzeit fehlschlägt.

// compile with: /c /W1
#include <cstring>
#include <stdlib.h>
#pragma warning(disable : 4996)   // for strcpy use

// Vulnerable function
void vulnerable(const char *str) {
   char buffer[10];
   strcpy(buffer, str); // overrun buffer !!!

   // use a secure CRT function to help prevent buffer overruns
   // truncate string to fit a 10 byte buffer
   // strncpy_s(buffer, _countof(buffer), str, _TRUNCATE);
}

int main() {
   // declare buffer that is bigger than expected
   char large_buffer[] = "This string is longer than 10 characters!!";
   vulnerable(large_buffer);
}

Siehe auch

Referenz

Compileroptionen

Festlegen von Compileroptionen