Wie Sie richtig bemerken, wird diese Routine, wenn sie mit einer call
dann [ebp+4]
ist die Absenderadresse. Das heißt aber nicht, dass dies eine schlechte Idee ist.
Angenommen, die Routine wird mit einer call
. Zu diesem Zeitpunkt ist die "Rücksprungadresse", die auf den Stapel geschoben wird, die Adresse des Bytes, das unmittelbar auf die call
Opcode. Nennen wir diese Adresse x . Die Routine extrahiert dann aus der Adresse x zwei 32-Bit-Worte, eines an der Adresse x und einer unter der Adresse x+4 . Es subtrahiert das zweite Wort vom ersten Wort und speichert das Ergebnis in eax
. Schließlich speichert die Routine den Wert zurück x+8 im Stapelplatz [ebp+4]
, was zur Folge hat, dass die ret
erreicht ist, wird die Ausführung an der Adresse x+8 . Mit dieser Hypothese sieht die Routine wie eine Möglichkeit aus, ganze Zahlen zu subtrahieren, die sich in der Mitte des Codes befinden, etwa so:
call yourroutine
dd 56478634
dd 18943675
mov ebx, eax ; an example instruction
Hier ist die call
kehrt zum mov
Anweisung, und zu diesem Zeitpunkt eax
enthält den Wert 37534959 (das ist 18943675 subtrahiert von 56478634).
Als Code-Routine ist sie nicht sonderlich nützlich, da sie eine komplizierte Methode zum Laden von eax
mit einem konstanten Wert, der fest kodiert ist (der Codebereich ist während der Ausführung normalerweise schreibgeschützt). Man könnte sich vorstellen, dass eine solche Routine als Teil der Laufzeitunterstützung für dynamische Verknüpfung auf einer bestimmten Architektur erscheinen könnte (dynamische Verknüpfung ist ein heikles Thema).
Nehmen wir nun stattdessen an, dass die Routine mit einer jmp
. [ebp+4]
bezeichnet nun das, was sich zu diesem Zeitpunkt oben auf dem Stapel befand. Die Routine nimmt diesen Wert (nennen wir ihn y ), erhalten Sie die beiden Wörter unter Adressen y と y+4 berechnet das Subtraktionsergebnis in eax
und speichert dann y+8 zurück in die [ebp+4]
Steckplatz. Schließlich ist die ret
interpretiert diesen Slot als Rücksprungadresse, d.h. die Adresse eines Codes, zu dem die Ausführung springen soll. Es spielt keine Rolle, dass keine call
Opcode an der Erzeugung dieser Adresse beteiligt war; ret
wird sich dennoch darauf stürzen. Dieses Mal könnte der Aufrufcode wie folgt aussehen:
push foobar
jmp yourroutine
... ; unreached code
foobar:
dd 56478634
dd 18943675
mov ebx, eax ; an example instruction
Diesmal sieht es nach einem parametrisierten Sprung mit einer inhärenten Belastung von eax
. Ein solcher Code kann in der Implementierung von einigen Interpreter für Threaded Code . Als Hausaufgabe bin ich mir jedoch ziemlich sicher, dass dies nicht beabsichtigt war (Interpreter für threaded Code sind noch haariger als dynamisches Linking).