2015-06-18 14 views
5

Ich habe eine Trace-Anweisung und möchten Funktionsaufrufe und Returns extrahieren.Unterschiede zwischen Call, Push + ret und Push + Jump in Assembly

fand ich, dass außer call Anweisung, push + jmp und push + ret können für Funktionsaufruf verwendet werden? Zuerst möchte ich sicher sein, dass das korrekt ist? und wenn ja, was sind die Unterschiede zwischen ihnen?

Auch wenn push + ret ist Art von Anruf so was wäre das Ende oder die Rückkehr einer Funktion? Sehen Sie nur ret ohne push Anweisung davor?

Antwort

4

Vereinfacht ausgedrückt:

Anruf Adresse

Dies wird die aktualisierte Programmzähler schieben (die nach dem call auf die Anweisung verweist) auf den Stapel dann in die Adresse springen angegebenen (Adressierungsmodi können gelten).

ret

Dieser Befehl intern springt und die Stapeladresse aus und springt zu. Dies ist gut mit call abgestimmt, so dass es zu der Anweisung nach dem vorherigen call zurückkehren kann.

jmp Adresse

Dieses einfach auf die gegebene Adresse springt (Adressierungsarten sind möglich). Es macht überhaupt nichts mit dem Stack.


So können Sie auch dies tun:

push address 
ret 

Welche an die Adresse wird angezeigt und springen, die auf den Stapel geschoben wurde, wie oben beschrieben. Es ist eine clevere Art, einen indirekten Sprung in einem Mikroprozessor zu machen, der indirekte Adressierungsmodi in ihren Sprungbefehlen nicht unterstützt.

Die Folge:

push address 
jmp someplace 

einfach springen zu irgendwo und nicht den Stapel beeinflussen oder verwenden Sie die Adresse , die auf den Stapel geschoben wurde. Wenn Adresse die Anweisung nach jmp ist, entspricht das ungefähr call someplace.

Für Befehlssätze, die einen indirekten Adressierung Sprung nicht unterstützen, ich habe diese nette kleine Behelfslösung gesehen:

push address 
ret 

Welche, was auch immer springt address ist.

+0

Ungewöhnliche Variationen davon werden häufig verwendet, wenn der Autor will die wahre Funktionalität des Codes (zum Beispiel Malware und „kopiergeschützte“ kommerzielle Software) verschleiern. –

+0

Ist 'reet' im Wesentlichen nicht 'Pop und springt indirekt zur aufgeplatzten Adresse'? –

+0

@JohnHascall ja es ist ... "duh" meinerseits. : p Ich dachte "no' call', no'ret' ". :) – lurker

6

Ja, Sie haben Recht.

Wenn eine call ausgegeben wird, ist die auf den Stapel geschobene Rücksprungadresse die nächste Adresse, an der die Ausführung fortgesetzt werden soll (die Adresse, die unmittelbar auf die aktuelle Anweisung folgt). Im Wesentlichen ist es eine atomare push, gefolgt von einer jmp.

Dies bedeutet, dass, wenn Sie manuell push und dann jmp, die Funktion, die Sie in später springen ret und alle Zugriffsstapel, die in der Funktion ausgeglichen sind, an die Adresse zurück, die Sie vorher gedrückt.

In ähnlicher Weise können Sie push und dann ret eine Anrufrückgabe simulieren, aber dies stellt Sie nicht in der Lage, später wieder zurückzukehren. Diese Art von Verhalten wird häufiger verwendet, um Disassemblierer abzuschütteln, wodurch es schwieriger wird, festzustellen, mit welcher Adresse der Code tatsächlich mit einem einfachen Disassembler angesteuert wird.

+0

"Diese Art von Verhalten wird häufiger verwendet, um Disassembler loszuwerden" Weißt du, ob IDA Pro über Funktionen verfügt, um diese Taktiken korrekt als Anrufe/Rückgaben zu interpretieren? Aus allgemeiner Perspektive, in welche Richtung würden Sie einen Code zerlegen, der diese Verschleierungstaktik verwendet? edit: ein bisschen mehr Suche ergab diesen Thread, der auf Ihre Antwort verweist und meine Frage beantwortet: http://reverseengineering.stackexchange.com/questions/10911/automatisch-decode-pushret-call-into-jmp – SullX