Share via


/GS (Puffer-Sicherheitsüberprüfung)

Erkennt einige Pufferüberläufe, die die Rückgabeadresse einer Funktion, Ausnahmehandleradresse oder bestimmte Typen von Parametern überschreiben. Einen Pufferüberlauf zu verursachen ist eine von Hackern verwendete Technik, um Code auszunutzen, der keine Puffergrößeneinschränkungen erzwingt.

/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. Weitere Informationen zum Unterdrücken der Pufferüberlauferkennung finden Sie unter safebuffers.

Sicherheitsüberprüfungen

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 und beim Endladen von Rahmen auf 64-Bit-Betriebssystemen wird dann eine Hilfsfunktion aufgerufen, die sicherstellt, dass sich der Wert des Cookies nicht geändert hat. Ein anderer Wert gibt an, dass der Stapel möglicherweise überschrieben wurde. Wenn ein anderer Wert erkannt wird, wird der Prozess beendet.

GS-Puffer

Eine Puffer-Overrrun-Sicherheitsüberprüfung wird auf einem GS-Puffer ausgeführt. Ein GS-Puffer kann einer der Folgenden sein:

  • Ein Array, das größer als 4 Bytes ist, verfügt über mehr als zwei Elemente und einen Elementtyp, der kein Zeigertyp ist.

  • Eine Datenstruktur, deren Größe mehr als 8 Bytes ist und keine Zeiger enthält.

  • Ein mit der _alloca-Funktion reservierter Puffer.

  • Irgendeine Klasse oder Struktur, die einen GS-Puffer enthält.

Die folgenden Anweisungen deklarieren z. B. GS-Puffer.

    char buffer[20];
    int buffer[20];
    struct { int a; int b; int c; int d; } myStruct;
    struct { int a; char buf[20]; };

Die folgenden Anweisungen deklarieren jedoch keine GS-Puffer. Die ersten beiden Deklarationen enthalten Elemente des Zeigertyps. Die dritte und vierten Anweisungen deklarieren Arrays, deren Größe zu klein ist. Die fünfte Anweisung deklariert eine Struktur, deren Größe auf einer x86-Plattform nicht mehr als 8 Bytes beträgt.

    char *pBuf[20];
    void *pv[20];
    char buf[4];
    int buf[2];
    struct { int a; int b; };

Sicherheitscookies initialisieren

Die /GS-Compileroption erfordert, dass das Sicherheitscookie initialisiert wird, bevor eine Funktion, die das Cookie verwendet, ausgeführt wird. 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. Wenn Sie einen alternativen Einstiegspunkt verwenden, müssen Sie das Sicherheitscookie manuell initialisieren, indem Sie __security_init_cookie aufrufen.

Geschützte Informationen

Die /GS-Compileroption schützt folgende Elemente:.

  • Die Rückgabeadresse eines Funktionsaufrufs.

  • Die Adresse eines Ausnahmehandlers für eine Funktion.

  • Anfällige Funktionsparameter.

/GS versucht auf allen Plattformen, Pufferüberläufe in die Rücksprungadresse zu ermitteln. Auf Plattformen wie x86 und x64 mit Aufrufkonventionen, durch die die Rücksprungadresse eines Funktionsaufrufes auf dem Stapel gespeichert wird, lassen sich Pufferüberläufe leichter ausnutzen.

Auf x86-Systemen fügt der Compiler zusätzlich ein Sicherheitscookie ein, um die Adresse des Ausnahmehandlers der Funktion zu schützen, falls eine Funktion einen Ausnahme-Handler verwendet. Dieses Cookie wird beim Entladen von Rahmen überprüft.

/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 oder einen GS-Puffer enthält.

Ein verwundbarer Parameter wird vor dem Cookie und den lokalen Variablen zugeordnet. Durch einen Pufferüberlauf kann dieser Parameter überschrieben werden. Und der in der Funktion enthaltene Code, der diesen Parameter verwendet, könnte einen Angriff verursachen, bevor der Rücksprung aus der Funktion erfolgt und die Sicherheitsprüfung ausgeführt wird. 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 erstellt der Compiler keinen Kopien verwundbarer Parameter:

  • Bei Funktionen, die keinen GS-Puffer enthalten.

  • Optimierungen (/O Optionen) sind nicht aktiviert.

  • Funktionen mit variabler Argumentliste (...).

  • Funktionen, die mit naked markiert sind.

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

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

Nicht geschützte Informationen

Die /GS-Compileroption bietet keinen 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 beschädigen.

Auch wenn Sie /GS verwenden, versuchen Sie immer, sicheren Code zu schreiben, der keine Pufferüberläufe hat.

So legen Sie diese Compileroption in Visual Studio fest

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und klicken Sie dann auf Eigenschaften.

    Weitere Informationen finden Sie unter Gewusst wie: Öffnen von Projekteigenschaftenseiten.

  2. Klicken Sie im Dialogfeld Eigenschaftenseiten 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 überlaufen. Dadurch versagt die Anwendung zur Laufzeit.

// 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