Stapelmanipulation in C ohne Inline-Assembly [geschlossen]

8

Ich habe mich auf einen Programmierwettbewerb vorbereitet und bin im Internet auf diese Frage gestoßen:

%Vor%

Die Lösung besteht darin, Code zu schreiben, der "hi there" anstelle von "there hi" ausgibt (es dürfen keine zusätzlichen Druckfunktionen verwendet werden und Code wird nur in den Kommentarblock geschrieben).

Da ich eine grundlegende Assembler-Programmierung durchgeführt habe, wurde mir klar, dass dies mit der Stack-Manipulation unter Verwendung der Ganzzahl x als Basis geschehen könnte.

Ich habe versucht, mit gdb die Rückgabeadresse der Funktionen zu finden und habe dann die Rückgabeadressen von a und b getauscht. Der Compiler löst einen Segmentierungsfehler aus, und daher nehme ich an, dass ich nicht die richtige Absenderadresse verwendet habe.

Wie berechne ich den Offset, um die Absenderadresse zu finden? Der Infoframe-Befehl auf gdb war nicht hilfreich, da die dort angegebene Stack-Adresse nicht funktionierte.

Ich führe dies auf Linux mit gcc.

    
Justeeson Sebastin 09.12.2016, 23:00
quelle

3 Antworten

6

Ich bin mir nicht sicher, ob das Folgende zählt. Es ist tragbar auf POSIX. Im Grunde genommen ändern Sie den Puffer von printf vor dem ersten Aufruf und manipulieren diesen, bevor er zum Terminal

geleert wird %Vor%

Sie erhalten Warnungen, die Bibliotheksfunktionen memcpy und exit implizit zu deklarieren. Es ist legal auf C89, obwohl entmutigt. Aber in deinem Fall ist kein Trick zu schmutzig, denke ich. Sie können das Memcpy vermeiden, indem Sie die Zeichen manuell kopieren. Sie können exit vermeiden, indem Sie stattdessen stdout bis freopen umleiten. Sie können BUFSIZ in große Konstanten ändern, wenn das System eine merkwürdig kleine Puffergröße (kleiner als 9) aufweist. Es gibt Varianten dieser Lösung, bei denen Sie das \n nicht manuell einfügen müssen und stattdessen das Programm normal von main beenden und das printf("\n") für das Zeilenende verwenden muss

    
Yan Zhou 10.12.2016 08:40
quelle
4

Dieses Problem kann nur gelöst werden, wenn Sie den Stack auf die gleiche Weise zerstören, wie ein Angreifer den Stapel eines Prozesses zerstört.

Und um den Stack zu versminen, kann man nur dann machen, wenn man jedes Detail der Implementierung des Compilers kennt, das Problem ist sonst unlösbar.

Wenn Sie die Details der Kompilierung (insbesondere die Stack-Struktur) kennen, können Sie die Adresse der lokalen x-Variablen verwenden, um die Adressen des aktuellen Frames aus dem Stack (von FRAME_C) zu erhalten; In jedem Frame ist der Basiszeiger des vorherigen Frames und ändern Sie es.

Der Stapel sieht so aus:

%Vor%

Mit &x können wir die Position von FRAME_C ermitteln.

Eine Lösung ist

  1. um "Hi" in der Funktion c ()
  2. zu drucken
  3. Ändern Sie FRAME_B so, dass RET_A zu RET_MAIN
  4. wird
  5. Rückgabe von Funktion c () mit return

Die knifflige Operation ist 2. Wenn jedoch jeder Frame eine bekannte Größe hat, können wir den Rückgabezeiger RET_A des Frames B modifizieren und RET_MAIN so etwas erkennen:

%Vor%

Wie Sie sehen können, müssen Sie viele Details über die Implementierung des Compilers wissen, also ist dies keine tragbare Lösung.

Eine andere Lösung wäre, "hi, there" zu drucken und stdout auf /dev/null umzuleiten. Ich nehme an, dass exit () oder andere Compiler-abhängige Tricks nicht erlaubt sind, sonst hat das Problem keine Bedeutung für einen Wettbewerb.

    
alinsoar 09.12.2016 23:27
quelle
0

meine Lösung ist für x86 / x64 und für CL Compiler, aber denke für gcc gibt es auch.

question only - existieren für die Funktion äquivalent:

void ** _AddressOfReturnAddress();

und sind äquivalent für __declspec(noinline) - damit der Compiler keine bestimmte Funktion inline ausführt

lassen void* pb - ist die Adresse in void b() direkt nach c(); und void* pa ist die Adresse in void a() direkt nach b();

weil a und b fast gleich sind - das können wir annehmen

(ULONG_PTR)pa - (ULONG_PTR)&a == (ULONG_PTR)pb - (ULONG_PTR)&b;

und natürlich das Stacklayout in a und b müssen identisch sein. darauf basierend und Lösung. Nächster Code getestet / mit CL Compiler gearbeitet - sowohl auf x86 / x64 (Windows) als auch mit /Ox (Full Optimization) und mit /Od (Disable (Debug)) - alles hat funktioniert.

%Vor%     
RbMm 10.12.2016 10:02
quelle

Tags und Links