Frage zu erzeugtem assembler code
-
TheBigW schrieb:
Hab es jetzt nochmal umgestrickt und es funktioniert so auch mit Variante 2
sub esp, 0x10 mov DWORD PTR[esp], 0x05 mov DWORD PTR[esp+4], 0x10 mov DWORD PTR[esp+8], 0x15 mov DWORD PTR[esp+0x0C], 0x20 call StackTest
Aber die Reihenfolge ist noch falsch. Das, was zuletzt gepusht wurde, befindet sich ja oben auf dem Stack also direkt am Stackpointer. Du müsstest die 0x20 also nach esp schieben, die 0x05 nach esp+0x0C, damit die Reihenfolge der von deiner Variante 1 entspricht. Die Parameterübergabe ist übrigens von rechts nach links. iVal4 wird also zuerst gepusht.
Hast du für die Angelegenheit mit den nicht initialisierten Parametern auf dem Stack ein konkretes Beispiel mit Quellcode? Sind diese Argumente überhaupt erforderlich bei der Art, wie diese Funktion genutzt wird?
-
hermes schrieb:
masterofx32 schrieb:
hermes schrieb:
allokieren möchte.
Müsste man dann nicht eigentlich nicht zum Stackpointer 0x444 addieren anstatt zu subtrahieren?Nein, der Stack "wächst" negativ im Speicher also von den hohen Adressen zu den niedrigen Adressen.
Genau von oben nach unten, ich habe 0x100 Bytes für den Stack reserviert und einen Stackpointer-Wert von 0xff, dann wäre bei 0x00 Schluss.
Um zusätzlich 10 Byte Stack zu allocieren müsste ich doch zum Stackpointer
10 Byte addieren um auf die gewünschten Stack von 0xff+10Byte zu kommen.
Subtrahieren vom Stack würde den Stack doch verkleinern.
Aber es werden doch 444Byte zusätzlich Stack benötigt.Wenn ich das richtig verstanden habe, sprichst du davon, die Größe des Stackspeichers zu ändern? Das wird normalerweise nicht gemacht und das Betriebssystem reserviert ihn beim Start des Threads mit ausreichender Größe.
Bei deinem Stack mit einem ursprünglichen Stackpointer von 0xFF liegt noch nichts auf der gedachten Stack-Struktur. Wenn man jetzt etwas auf den Stack legt, verringert sich ja der Stackpointer und zeigt auf das obere Element des Stacks (das unterste im Speicher, weil er ja "auf dem Kopf" steht). Ist man bei einem Stackpointer von 0x00 angelangt und will etwas zusätzliches auf den Stack legen, erzeugt das einen Stack Overflow. Wenn man also vom Stackpointer subtrahiert, legt man virtuell ein Element beliebiger Größe auf den Stack, auf den man mit PUSH normalerweise nur DWORDs ablegen kann. Der übrige Stackspeicher, der vor dem Stackspeicher liegt enthält undefinierte Werte.
-
Hast du für die Angelegenheit mit den nicht initialisierten Parametern auf dem Stack ein konkretes Beispiel mit Quellcode? Sind diese Argumente überhaupt erforderlich bei der Art, wie diese Funktion genutzt wird?
Vielleicht "veralbert" mich hier auch IDA. Ich hatte dort auch schon mehrfach, das mir IDA Funktionsargumente, die nachweißlich Ptr waren als int verkaufen wollte.
Zu meinem Problem:
push ebp mov ebp, esp and esp, 0FFFFFFF8h sub esp, 74h push ebx push esi mov esi, ecx push edi push ecx mov edx, [ebp+arg_0] mov eax, esp mov [esp+84h+var_70], esp push 40002716h mov dword ptr [esi+720h], 2 sub esp, 14h mov ecx, esp push eax mov [ecx], edx mov edx, [ebp+arg_4] mov [ecx+4], edx mov edx, [ebp+arg_8] mov [ecx+8], edx mov edx, [ebp+arg_C] mov [ecx+0Ch], edx mov dx, [ebp+arg_10] mov [ecx+10h], dx call sub_10043F00 // sollte laut IDA 6 argumente haben..
zu meiner Schande muß ich gestehen, das ich den mov - Block vor dem Aufruf bisher ignoriert habe, weil da ja nichts mit dem Stack passiert.
Wenn ich hier die push - anweisungen Zähle, müßte die Funktion als 6. Parameter
ebp bekommen. Was soll das?
-
Von dem "sub esp, 14h" kommen mal 5 Argumente, d.h. das 6. ist dann das "push eax", so wie ich das sehe.
-
Richtig, das ist aber der Funktionsanfang. D.h. push ebx und push esi greifen auf register zu, die IMO ja dann keinem dfinierten Wert haben. Das sind also nur push's, die dazu dienen den Inhalt der Register zu sichern (werdem am Ende zurückgeschrieben ).
Was ich dort dann nicht verstehe, ist, dass zwischen dem push eax und dem call dann das sub esp, 14h kommt. D.h. doch dann in diesem Fall, das 5 Argumente auf den Stack kommen, die total zufällig belegt/undefiniert sind.
-
TheBigW schrieb:
D.h. doch dann in diesem Fall, das 5 Argumente auf den Stack kommen, die total zufällig belegt/undefiniert sind.
die bleiben aber nicht lange undefiniert. Im prinzip kann man allerdings nicht sagen, wieviele parameter hier übergeben werden, ohne den quelltext zu kennen, der uns, wie üblich in diesem forum, vorenthalten wird... schliesslich muss nicht jedes einzelne dword tatsächlich ein eigenständiger parameter sein (wenn ich gar nichts weiss, würde ich auf 3 parameter schliessen, der zweite eine struktur von 20 byte).
wozu diese diskussionen ins blaue hinein gut sein sollen, entzieht sich meinem verständnis.
-
der uns, wie üblich in diesem forum, vorenthalten wird...
sorry, das war nicht meine Absicht, aber ich finde es auch immer etwas unhöflich, zig- Seiten Quelltext zu posten und zu erwarten, das einfach mal jemand die Mühe macht da durchzusteigen. Es ist halt 'ne ganze Menge code und da hab ich mich wohl oder übel auf den Aufruf der Funktion eingeschränkt.
schliesslich muss nicht jedes einzelne dword tatsächlich ein eigenständiger parameter sein (wenn ich gar nichts weiss, würde ich auf 3 parameter schliessen, der zweite eine struktur von 20 byte).
Das wußte ich z.B. schonmal nicht. Ich dachte immer, das strukturen dort wie Arrays behandelt werden und dort wird ja meist immer die Adresse des ersten Elements übergeben, da ja dort wie bei einer struct alle Elemente im Speicher nebeneinander liegen.
Das kommt dabei raus, wenn man wie Ich Assembler vom Disassembler lernt...
Wie gesagt, ich poste auch liebend gerne den code, aber das werden dann für die zwei Funktionen schon 3-4 Seiten.Trotzdem vielen Dank für Eure bisherige Hilfe
-
es genügt ja schon der relevante teil des quelltextes, d.h. der betreffende funktionsaufruf, und die deklaration der aufgerufenen funktion (ggf. definition der parametertypen - eben alle definitionen dies auch der compiler haben will).
-
TheBigW schrieb:
D.h. doch dann in diesem Fall, das 5 Argumente auf den Stack kommen, die total zufällig belegt/undefiniert sind.
Schau dir doch mal an, was die darauffolgenden movs machen.
-
Aua, da hast du wohl recht. Wenn ich das richtig verstehe werden dort die an die Funktion übergebenen argument in die vorher mit sub 14h bereitgestellten Speicherbereiche geschrieben und somit initialisiert.
Danke das wars, jetzt ist es in etwa klar. Sorry, ich bin halt immer davon ausgegangen, das Argumente immer mit push auf den Stack gelegt werden und hab diesen mov - Block in meiner Betrachtung weggelassen.
in der aufgerufenen Funktion passiert nichts besonderes, dort wird wirklich nur auf besagte 6 einzelne Argumente zugegriffen und die liegen dort genauso, wie sie in dem Move-block vor dem Funktionsaufruf initialisiert werden. Z.B. ist das 5. Argument ein WORD, was super zu
mov dx, [ebp+arg_10] mov [ecx+10h], dx
passt. Es ist also wirklich nur ein "normaler" Funktionsaufruf und mein Weltbild ist wieder gerade.
Tatsächlich wird so die Übergabe einer struct "By Value" realisiert. Ich hab es gerade noch einmal an einem Beispiel durchgespielt.Danke für Eure Hilfe, das Brett vor meinem Kopf ein bisschen abzuschrauben
-
hermes schrieb:
allokieren möchte.
Müsste man dann nicht eigentlich nicht zum Stackpointer 0x444 addieren anstatt zu subtrahieren?masterofx32 schrieb:
Nein, der Stack "wächst" negativ im Speicher also von den hohen Adressen zu den niedrigen Adressen.
ok,man will ja nicht mehr auf den Stack packen sonder für eigene Zwecke
Stack-Speicher benutzen.Warum wird dem Programm dann nicht gleich genügend Speicher reserviert?