/GS (Puffer-Sicherheitsüberprüfung)

Erkennt einige Pufferüberläufe, welche die Rückgabeadresse einer Funktion, eine 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.

Syntax

/GS[-]

Bemerkungen

/GS ist standardmäßig aktiviert. Wenn Sie davon ausgehen, dass Ihre Anwendung keine Sicherheitsrisiken hat, verwenden Sie /GS-. 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 Funktionseintrag wird der zugeordnete Speicherplatz mit einem Sicherheitscookie geladen, das einmal beim Laden des Moduls berechnet wird. Bei Funktionsende und beim Entladen von Rahmen auf 64-Bit-Betriebssystemen wird dann eine Hilfsfunktion aufgerufen, die sicherstellt, dass sich der Wert des Cookies nicht geändert hat. Ein abweichender Wert gibt an, dass der Stapel möglicherweise überschrieben wurde. Ein abweichender Wert führt dazu, dass der Prozess beendet wird.

GS-Puffer

Eine Sicherheitsüberprüfung des Pufferüberlaufs wird für einen GS-Puffer ausgeführt. Ein GS-Puffer kann einer der Folgenden sein:

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

  • Eine Datenstruktur, die größer als 8 Bytes ist und keine Zeiger enthält.

  • Ein Puffer, der mithilfe der _alloca-Funktion zugeordnet wird.

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

Beispielsweise werden GS-Puffer durch die folgenden Anweisungen deklariert.

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 vierte Anweisung deklariert 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; };

Die /GS-Compileroption erfordert, dass das Sicherheitscookie initialisiert wird, bevor eine Funktion ausgeführt wird, die das Cookie verwendet. Das Sicherheitscookie muss sofort beim Eintrag in eine EXE- oder DLL-Datei initialisiert werden. Dies erfolgt automatisch, wenn Sie die Standardeinstiegspunkte für VCRuntime verwenden: mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup oder _DllMainCRTStartup. Wenn Sie einen alternativen Einstiegspunkt verwenden, müssen Sie das Sicherheitscookie manuell initialisieren, indem Sie __security_init_cookie aufrufen.

Geschützte Informationen

Die Compileroption /GS schützt die folgenden Elemente:

  • Die Rückgabeadresse eines Funktionsaufrufs.

  • Die Adresse eines Ausnahmehandlers für eine Funktion.

  • Anfällige Funktionsparameter.

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

Wird auf x86-Systemen ein Ausnahme-Handler verwendet, fügt der Compiler ein Sicherheitscookie ein, um die Adresse des Ausnahmehandlers zu schützen. Dieses Cookie wird beim Entladen von Rahmen überprüft.

/GS schützt anfällige Parameter , die an eine 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.

Der Compiler erstellt keine Kopien verwundbarer Parameter, wenn folgende Bedingungen erfüllt sind:

  • Funktionen enthalten keinen GS-Puffer.

  • Optimierungen (/O-Optionen) sind nicht aktiviert.

  • Funktionen verfügen über eine variable Argumentliste (...).

  • Funktionen, die mit naked gekennzeichnet sind.

  • Funktionen enthalten Inlineassemblycode in der ersten Anweisung.

  • 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 schützt nicht vor allen Pufferüberlaufsicherheitsangriffen. Wenn ein Objekt beispielsweise 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 ohne Pufferüberläufe zu schreiben.

So legen Sie diese Compileroption in Visual Studio fest

  1. Öffnen Sie das Dialogfeld Eigenschaftenseiten des Projekts. Weitere Informationen erhalten Sie unter Set C++ compiler and build properties in Visual Studio (Festlegen der Compiler- und Buildeigenschaften (C++) in Visual Studio).

  2. Wählen Sie die Eigenschaftenseite Konfigurationseigenschaften>C/C++>Codegenerierung aus.

  3. Ändern Sie die Eigenschaft Puffersicherheitsprüfung .

So legen Sie diese Compileroption programmgesteuert fest

Beispiel

In diesem Beispiel wird ein Pufferüberlauf stattfinden. 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);
}

Weitere Informationen

MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile