/GS (Puffersicherheitsü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[-]

Hinweise

/GS ist standardmäßig aktiviert. Wenn Sie erwarten, 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. Bei der Funktionseingabe wird der zugewiesene Speicherplatz mit einem Sicherheitscookies geladen, das einmal beim Modulladevorgang 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 Pufferüberlaufsicherheitsprüfung 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 zugewiesen wurde.

  • 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; };

Für die /GS-Compileroption muss das Sicherheitscookies initialisiert werden, bevor eine Funktion ausgeführt wird, die das Cookie verwendet. Das Sicherheitscookies muss sofort beim Eintrag zu einer EXE oder DLL initialisiert werden. Dies erfolgt automatisch, wenn Sie die standardmäßigen VCRuntime-Einstiegspunkte verwenden: Standard CRTStartup, w Standard CRTStartup, WinMainCRTStartup, wWinMainCRTStartup oder _DllMainCRTStartup. Wenn Sie einen alternativen Einstiegspunkt verwenden, müssen Sie das Sicherheitscookies manuell initialisieren, indem Sie __security_init_cookie aufrufen.

Geschützte Informationen

Die /GS-Compileroption 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 die Absenderadresse 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 nackt 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 zu schreiben, der keine Pufferüberläufe enthält.

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);
}

Siehe auch

MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile