2014-11-03 10 views
5

Ich weiß, dass ein Programmstapel etwas sieht wie folgt aus (von hoch bis niedrig):Ist es möglich,% eax mit Pufferüberlauf zu überschreiben?

EIP | EBP | local variables 

Aber wo könnte ich %eax und die anderen allgemeinen Register finden? Ist es möglich, sie mit einem Pufferüberlauf zu überschreiben?

Update: Am Ende musste ich nicht einmal %eax überschreiben, weil es sich herausgestellt hat, dass das Programm irgendwann auf die Benutzereingabe %eax zeigte.

+2

Dies hängt von der Aufrufkonvention in Gebrauch zu verschütten, und möglicherweise auf die Optimierungsentscheidungen des Compilers. – Mark

+1

Ein besserer Titel für Ihre Frage könnte sein "Ist es möglich, ein Register mit einem Pufferüberlauf zu überschreiben?" weil, wie gesagt, es eine falsche Prämisse voraussetzt, streng (obwohl zufällig zufällig in mindestens einem Zusammenhang wahr ist) – codenheim

+0

Sie haben Recht, ich änderte es. – LonelyWebCrawler

Antwort

6

Ein Register, per Definition, ist nicht im RAM. Register befinden sich in der CPU und haben keine Adressen, so dass Sie sie nicht mit einem Pufferüberlauf überschreiben können. Es gibt jedoch sehr wenige Register, daher verwendet der Compiler sie als eine Art Cache für die am meisten verwendeten Stapelelemente. Dies bedeutet, dass, während Sie nicht in die Register stricto sensu überlaufen können, früher oder später im Register überschriebene Werte im RAM geladen werden.

(In Sparc-CPU ist die Register-as-Stapel-Cache-Richtlinie auch fest verdrahtet.)

In Ihrem Schema, EIP und EBP nicht auf dem Stapel ist; die entsprechenden Slots auf dem Stack sind Bereiche, von denen diese beiden Register reloaded werden (beim Funktionsexit). EAX hingegen ist ein allgemeines Register, das der Code hier und da verwenden wird, ohne eine strikte Konvention.

+0

Danke, das hätte ich wissen müssen. – LonelyWebCrawler

+0

+1 für "sensu stricto" – codenheim

2

EAX wird wahrscheinlich nie auf dem Stapel erscheinen. Bei den meisten x86-Compilern ist EAX das 32-Bit-Rückgabewert-Register und wird niemals auf dem Stack gespeichert oder vom Stack wiederhergestellt (RAX in 64-Bit-Systemen).

Dies soll nicht heißen, dass ein Pufferüberlauf nicht verwendet werden kann, um den Inhalt von EAX zu verändern, indem ausführbarer Code auf den Stapel gelegt wird; Wenn die Codeausführung auf dem Stack vom Betriebssystem nicht deaktiviert wurde, kann dies geschehen, oder Sie können eine falsche Rückgabeadresse auf dem Stack erzwingen, die die Kontrolle an eine Codefolge überträgt, die einen Wert in EAX lädt abziehen. Wenn der von einer Funktion zurückgegebene Wert bekanntermaßen in einer lokalen Variablen gespeichert wird, würde ein Stack-Smash, der diese Variable ändert, den Wert in EAX ändern, aber das Optimieren von Compilern kann das Stack-Layout nach Belieben ändern, also ein Exploit, der funktioniert auf einer Version möglicherweise vollständig auf einer neuen Version oder einem Hotfix fehlschlagen.

+0

Danke für die Details. Es macht alles Sinn, außer diesem: "Für die meisten x86-Compiler ist EAX das 32-Bit-Rückgabewert-Register". Ich dachte, EAX wäre nur ein allgemeines Register. Sind die Rückgabewerte nicht an anderer Stelle gespeichert? – LonelyWebCrawler

+1

Verschiedene Betriebssysteme haben unterschiedliche Aufrufkonventionen, aber ich habe noch nie eine gesehen, die EAX (oder AX oder RAX) nicht benutzt hat, um den Rückgabewert einer Funktion zu notieren. Nachdem der CALL ausgeführt wurde, wird normalerweise der Wert in EAX überprüft oder gespeichert. –

+0

Danke, ich wusste es nicht. – LonelyWebCrawler

2

Siehe Thomas Pornin (+1) und Flouders (+1) Antworten, sie sind gut. Ich möchte eine ergänzende Antwort hinzufügen, auf die angespielt, aber nicht ausdrücklich hingewiesen wurde.

Obwohl das „where“ der ursprünglichen Frage (mindestens so formuliert) erscheint auf der falschen Annahme zu basieren, die% eax auf dem Stapel befindet, und wobei ein Register, ist es nicht Teil des Stapels auf x86 (obwohl Sie jede Hardware-Register-Set auf einem Stapel emulieren können, und einige Architekturen tun dies tatsächlich, aber das ist nicht relevant), übrigens, Register werden häufig aus dem Stapel verschüttet/gefüllt. Es ist also möglich, den Wert eines Registers mit einem Stapelüberlauf zu zerschlagen, wenn das Register auf den Stapel verschüttet wurde. Dies würde erfordern, dass Sie den Verschüttungsmechanismus des jeweiligen Compilers kennen, und für diesen Funktionsaufruf müssten Sie wissen, dass% eax verschüttet wurde, wohin es verschüttet wurde, und diesen Stapelspeicherort stampfen, und wenn es der nächste ist gefüllt von seiner Speicherkopie erhält es den neuen Wert. So unwahrscheinlich es auch scheint, diese Angriffe werden normalerweise durch das Lesen von Quellcode und das Wissen über den betreffenden Compiler inspiriert, so dass es nicht wirklich so weit hergeholt ist.

Siehe für weitere Lesung zu registrieren diese

gcc argument register spilling on x86-64

https://software.intel.com/en-us/articles/dont-spill-that-register-ensuring-optimal-performance-from-intrinsics

+0

Danke für die Informationen, ich werde es lesen. Es scheint genau das zu sein, was ich brauche. – LonelyWebCrawler