2016-07-20 24 views
1

Ich versuche zu verstehen ASM und Stack-Überlauf über https://schweigi.github.io/assembler-simulator/. Wie ich verstanden habe, schiebt ein normaler Stapelüberlauf über die Stapelgrenze hinaus in den RAM. Meine Frage ist, was passiert, wenn der Stapelüberlauf über RAM Grenzen hinaus schiebt.Stack Überlauf in Opcode PUSH (ASM)

Im Simulator, wenn Sie ein Programm mit dem Code haben:

PUSH 53 ; 53 or 0x35 is opcode for PUSH 
JMP 0 ; loop it 

Das Programm überschreibt sich in den Stapel über RAM schieben, Stapelzeiger auf -1 geht. Was würde in einem realen Szenario, echtes Programm passieren?

+1

Das hängt von Umständen wie Architektur und Betriebssystem ab. Sie erhalten normalerweise einen Fehler und Ihr Prozess wird beendet. – Jester

+1

Auf einem x86 konnte man nie "über __RAM Grenzen hinausschieben". Der Stapel wird glücklich in dem verfügbaren Adressraum (64 KB für echten Adressmodus, 4 GB für geschützten Modus) umbrechen. Die Ergebnisse werden jedoch katastrophal sein! – Fifoernik

+0

Stack wird normalerweise durch Register "Stack Pointer" (oder "sp" auf vielen CPUs wie Z80 oder x86) verwaltet. Wenn Sie etwas auf den Stapel schieben, heißt das, dass Sie den Wert in [sp], sub sp, value_size speichern. Und 'sub reg, # n' wird normalerweise einfach umgebrochen, also würde das Subtrahieren von '1' von' 0' '' 'mit' 0xFFFF' (unter Berücksichtigung der 16b-Plattform) füllen, und Sie würden wieder von oben auf 16B Speicher beginnen. – Ped7g

Antwort

2

Eine sehr schöne Definition von Wikipedia:

In Software, ein Stapelüberlauf tritt auf, wenn der Anruf Stapelzeiger überschreitet der Stapel gebunden. Der Aufruf-Stack kann aus einer begrenzten Menge von Adressraum bestehen, der oft zu Beginn des Programms festgelegt wird. Die Größe des Aufruf-Stacks hängt von vielen Faktoren ab, einschließlich der Programmiersprache Sprache, Maschinenarchitektur, Multithreading und des verfügbaren Speichers . Wenn ein Programm versucht, mehr Speicherplatz als auf dem Aufrufstapel verfügbar zu verwenden (dh wenn versucht wird, auf Speicher über die Grenzen des Aufruf-Stacks zuzugreifen, der im Wesentlichen ein Pufferüberlauf ist), wird der Stack typischerweise überlaufen was zu einem Programmabsturz führt.

Die Definition dessen, was der Stack gebunden ist, wie viel Speicher der Stack hat, ist keine universelle Sache. Einige (alte) Prozessoren haben einen eingebauten 8 oder 16 tiefen Stapel, den wir nur für Rücksprungadressen sehen können, Sie funktionieren zu tief, und Sie beginnen, Adressen zu überschreiben, die Sie später brauchen könnten.

Auf einem Windows/Linux/Mac-Computer, wo Sie in einem virtuellen Adressraum mit Schutz von außerhalb Ihres zugewiesenen Speicherplatzes wandern, ist es innerhalb der möglichen Design-Lösungen zu Ihrem Stack als eigenen geschützten Blob RAM zuweisen (getrennt von Programm, Daten und Heap), und wenn Sie sich von der Kante davon entfernen, erhalten Sie einen Speicherfehler wie bei einem Datenzugriff mit einer virtuellen Adresse, auf die Sie nicht zugreifen dürfen.

Es gibt keinen Zweifel, viele andere interessante Fälle, aber die normale RAM-basierte Ansicht eines Programms ist an einer niedrigeren Adresse haben Sie Ihr Programm und einige Daten, an der höheren Adresse haben Sie einen Stapel, der nach unten wächst, und das Zeug In der Mitte befindet sich der Heap im Wesentlichen oder ein Teil davon wird als Heap definiert, um Ihnen etwas Stapelspeicherplatz zu geben. Wenn Sie versuchen würden, das zu tun, was Sie beschrieben haben, würde der Stack mit dem Wert nach unten wachsen, bis er die von Ihnen ausgeführte Schleife überschreibt, und abhängig davon, wie der Prozessor arbeitet, kann er weiter fortfahren, wenn er abruft Cache, oder es wird versuchen, die Bytes auszuführen, mit denen Sie den Cache füllen, und abhängig davon, was diese abstürzen oder nicht. Wenn es versucht, diese Bytes auszuführen, dann ist es, wenn sie nicht stapelbasiert sind, nicht länger, den Cache mit Müll zu "füllen".

So ein "Stack-Überlauf" auf vielen Systemen bedeutet nur, dass Ihr Stack und Heap oder Stack und Programm kollidiert, die Software versucht, die gleichen Adressen für den Stack und für Daten und je nachdem wer liest und verwendet Schreiben, wenn bestimmt wird, wer schlechte Daten erhält oder schlechte Absenderadressen verwendet, usw. Wahrscheinlich führt dies zu einem Absturz, manchmal aber auch zu einem fürchterlich schlechten Verhalten.Sie können dies sehr einfach mit einer rekursiven Funktion testen, die Sie rekursiv aufrufen, bis sie abstürzt.

+0

Ihr Simulator und der Befehlssatz, den Sie gerade ausführen, könnten etwas Besonderes sein und Sie daran hindern, dies zu tun. Es ist möglich, es fügt eine Menge Code hinzu, um Ihre Toolchain und die Kombination von Bibliotheken usw. zu haben, um diese Kollision zu verhindern. Grundsätzlich wird jedes Mal, wenn der Stack benutzt wird, geprüft, ob er in den definierten Heap eindringt. –

+0

Ich denke, Valgrind kann verwendet werden, um nicht unbedingt einen Stack-Überlauf zu verhindern, aber indem man den Speicher füllt und dann bei einer Untersuchung sieht, wie tief der Stack ging oder wie hoch der Heap ging. –