Wie erkennt Visual Studio 2013 Pufferüberlauf?

8

Visual Studio 2013 C ++ - Projekte verfügen über den Schalter /GS , um die Überprüfung der Puffer-Sicherheitsüberprüfung zur Laufzeit zu aktivieren. Wir haben seit dem Upgrade auf VS 2013 viele weitere STATUS_STACK_BUFFER_OVERRUN-Fehler festgestellt und vermuten, dass es etwas mit der verbesserten Überprüfung des Pufferüberlaufs im neuen Compiler zu tun hat. Ich habe versucht, dies zu überprüfen und besser zu verstehen, wie Pufferüberlauf erkannt wird. Mich beunruhigt die Tatsache, dass ein Pufferüberlauf gemeldet wird, selbst wenn der durch eine Anweisung aktualisierte Speicher nur den Inhalt einer anderen lokalen Variablen auf dem Stapel im selben Umfang ändert! Es muss also nicht nur überprüft werden, dass die Änderung den Speicher nicht beschädigt, der einer lokalen Variablen "gehört", sondern dass sich die Änderung nicht auf eine andere lokale Variable als diejenige auswirkt, auf die von der einzelnen Update-Anweisung verwiesen wird. Wie funktioniert das? Hat es sich seit VS 2010 geändert?

Bearbeiten: Hier ist ein Beispiel, das einen Fall illustriert, den Mysticial nicht behandelt:

%Vor%

Die Ausgabe ist 4 , was darauf hinweist, dass der zu überschreibende Speicher innerhalb der Grenzen von buffer1 liegt (unmittelbar nach buffer2 ), aber dann endet das Programm mit einem Pufferüberlauf. Technisch gesehen sollte es als Pufferüberlauf betrachtet werden, aber ich weiß nicht, wie es erkannt wird, da es immer noch im Speicher der lokalen Variablen ist und nichts außerhalb von lokalen Variablen wirklich korrumpiert.

Dieser Screenshot mit Memory-Layout beweist es. Nach einer Zeile wurde das Programm mit dem Pufferüberlauffehler abgebrochen.

Ich habe gerade den gleichen Code in VS 2010 ausprobiert, und obwohl der Debug-Modus den Pufferüberlauf (mit einem Puffer-Offset von 12) erfasst hat, hat er im Freigabe-Modus nicht abgefangen (mit einem Puffer-Offset) von 8). Also glaube ich, dass VS 2013 das Verhalten des Schalters /GS verschärft hat.

Bearbeiten 2: Mit diesem Code konnte ich mich sogar an die Überprüfung des VS 2013 Bereichs vorbeischleichen. Es hat immer noch nicht festgestellt, dass ein Versuch, eine lokale Variable zu aktualisieren, tatsächlich eine andere aktualisierte:

%Vor%     
BlueMonkMN 10.09.2015, 21:26
quelle

2 Antworten

0

Sie sehen eine Verbesserung des / GS-Mechanismus, der zuerst VS2012 hinzugefügt wurde. Ursprünglich / GS könnte Pufferüberläufe erkennen, aber es gibt immer noch ein Loop-Loch, wo angreifender Code den Stack stampfen kann, aber den Cookie umgehen kann. Etwa so:

%Vor%

Wenn der Angreifer den Wert von index manipulieren kann, hilft das Cookie nicht. Dieser Code wird jetzt in:

umgeschrieben %Vor%

Einfach nur Indexüberprüfung. Wenn diese Funktion ausgelöst wird, wird die App sofort mit __fastfail () beendet, wenn kein Debugger angeschlossen ist. Backgrounder ist hier .

>     
Hans Passant 11.09.2015, 13:35
quelle
1

Von der MSDN-Seite auf /GS in Visual Studio 2013:

  

Sicherheitsüberprüfungen

     

Bei Funktionen, die der Compiler als Pufferüberlauf-Probleme erkennt, ordnet der Compiler dem Stack vor der Rücksprungadresse Platz zu. Beim Funktionseintrag wird der zugewiesene Speicherplatz mit einem Sicherheitscookie geladen, das beim Laden des Moduls einmal berechnet wird. Beim Funktions-Exit und während des Frame-Abwickelns auf 64-Bit-Betriebssystemen wird eine Hilfsfunktion aufgerufen, um sicherzustellen, dass der Wert des Cookies immer noch derselbe ist. Ein anderer Wert zeigt an, dass ein Überschreiben des Stapels aufgetreten sein könnte. Wenn ein anderer Wert erkannt wird, wird der Prozess beendet.

Für weitere Details verweist dieselbe Seite auf Compiler-Sicherheitschecks :

  

Was / GS tut

     

Die / GS-Option bietet einen "Speed ​​Bump" oder einen Cookie zwischen dem Puffer und der Rücksprungadresse. Wenn ein Überlauf über die Rücksprungadresse schreibt, muss er den zwischen ihn und den Puffer gelegten Cookie überschreiben, was zu einem neuen Stapellayout führt:

     
  • Funktionsparameter
  •   
  • Funktion Rücksendeadresse
  •   
  • Rahmenzeiger
  •   
  • Cookie
  •   
  • Ausnahme-Handler-Frame
  •   
  • Lokal deklarierte Variablen und Puffer
  •   
  • Callee speichert Register
  •   

Der Cookie wird später genauer untersucht. Die Ausführung der Funktion ändert sich mit diesen Sicherheitsüberprüfungen. Wenn eine Funktion aufgerufen wird, befinden sich die ersten auszuführenden Anweisungen im Prolog der Funktion. Ein Prolog reserviert mindestens Platz für die lokalen Variablen auf dem Stapel, z. B. die folgende Anweisung:

%Vor%
  

Dieser Befehl reserviert 32 Byte für die Verwendung durch lokale Variablen in der Funktion. Wenn die Funktion mit / GS kompiliert wird, werden die Funktionen prolog weitere vier Bytes beiseite legen und drei weitere Anweisungen wie folgt hinzufügen:

%Vor%
  

Der Prolog enthält eine Anweisung, die eine Kopie des Cookies abruft, gefolgt von einer Anweisung, die ein logisches xor des Cookies und der Rückgabeadresse ausführt, und schließlich eine Anweisung, die das Cookie auf dem Stapel direkt unter der Absenderadresse speichert . Von diesem Punkt an wird die Funktion wie gewohnt ausgeführt. Wenn eine Funktion zurückkehrt, ist das letzte, was ausgeführt wird, der Epilog der Funktion, der das Gegenteil des Prologs ist. Ohne Sicherheitsprüfungen wird der Stapelspeicherplatz zurückgewonnen und zurückgegeben, z. B. die folgenden Anweisungen:

%Vor%
  

Bei der Kompilierung mit / GS werden die Sicherheitsüberprüfungen ebenfalls in den Epilog eingefügt:

%Vor%
  

Die Stack-Kopie des Cookies wird abgerufen und folgt dann mit der XOR-Anweisung mit der Absenderadresse. Das ECX-Register sollte einen Wert enthalten, der dem ursprünglichen Cookie entspricht, das in der Variablen __security_cookie gespeichert ist. Der Stapelspeicherplatz wird dann zurückgewonnen, und dann wird anstelle des Befehls RET der JMP-Befehl für die Routine __security_check_cookie ausgeführt.

     

Die Routine __security_check_cookie ist einfach: Wenn der Cookie unverändert war, führt er die Anweisung RET aus und beendet den Funktionsaufruf. Wenn der Cookie nicht übereinstimmt, ruft die Routine report_failure auf. Die Funktion report_failure ruft dann __security_error_handler (_SECERR_BUFFER_OVERRUN, NULL) auf. Beide Funktionen sind in der Datei seccook.c der C-Laufzeitdatei (CRT) definiert.

    
Nikos Athanasiou 10.09.2015 23:20
quelle