Feage zu Jumps im Virtual Address Space
-
Hallo, ich habe mir folgendes Programm geschrieben:
[Ja ich weiss das dass iner Endlosschleife läuft das war noch von einem Experiment.]00401000 <ModuleEntryPoint> /$ 68 00204000 PUSH console.00402000 ; /Title = "test" 00401005 |. E8 3A000000 CALL <JMP.&kernel32.SetConsoleTitleA> ; \SetConsoleTitleA 0040100A B8 02000000 MOV EAX,2 0040100F |. 83F8 03 |CMP EAX,3 00401012 74 0C JE SHORT console.00401020 00401014 68 E8030000 PUSH 3E8 00401019 E8 2C000000 CALL <JMP.&kernel32.Sleep> 0040101E |.^EB EA \JMP SHORT console.0040100A 00401020 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401022 |. 68 05204000 PUSH console.00402005 ; |Title = "ok" 00401027 |. 68 05204000 PUSH console.00402005 ; |Text = "ok" 0040102C |. 6A 00 PUSH 0 ; |hOwner = NULL 0040102E |. E8 23000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA 00401033 |. 68 E8030000 PUSH 3E8 ; /Timeout = 1000. ms 00401038 |. E8 0D000000 CALL <JMP.&kernel32.Sleep> ; \Sleep 0040103D |. 6A 00 PUSH 0 ; /ExitCode = 0 0040103F \. E8 0C000000 CALL <JMP.&kernel32.ExitProcess> ; \ExitProcess 00401044 $-FF25 5C204000 JMP DWORD PTR DS:[<&kernel32.SetConsoleT>; kernel32.SetConsoleTitleA 0040104A $-FF25 60204000 JMP DWORD PTR DS:[<&kernel32.Sleep>] ; kernel32.Sleep 00401050 .-FF25 64204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>; kernel32.ExitProcess 00401056 $-FF25 6C204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>] ; user32.MessageBoxA
Es geht hier um diesen Jump
00401012 74 0C JE SHORT console.00401020
Wenn ich jetzt z.b. das JE SHORT console.00401020 umändere in JE SHORT 0040100a
dann sehen die Opcodes dafür so aus: 74 F674 scheint ja für JE zu stehen und F6 für 0040100a wie kann ich berechnen das F6 = Adresse 0040100a ist?
-
Short Jumps sind relativ. Das F6 ist der Offset: 00401012 + F6 + 2 (Es wird hinter dem Sprungbefehl angefangen zu zählen) = 0040100a
-
Danke ich habs hinbekommen, ich hab das jetzt so gerechnet.
00401012(Quelle) <-- An dem Offset steht mein JE Befehl
0040100a(Ziel) <-- Dort will ich hin( 0040100a - 00401012 ) - 2 = FFFFFFFFFFFFFFF6
Dann hab ich mir die letzten beiden Werte angeschaut.
-
Oops hab noch was vergessen. Was genau bedeutet das dass die Jumps "relativ" sind?
Hat das was mit dem RVA(Relative Virtual Address) zu tun?
Also z.b. 00401000 das ist ja eine VA Adresse (Adresse die in den Speicher gemappt wurde vom PE Loader) im Hexeditor z.b. da würde ich ja die Adresse bei 00401000 finden.
Und noch eine Frage:
Z.b. im OllyDebugger auf der linken Seite die Spalte:
00401000 <ModuleEntryPoint> <-- ich meine die Spalte wo auch das hier steht
Die Werte die dort stehen nennt man doch Offset oder? Ich hab mal irgendwo gelesen das dass Adresse heisst und nicht Offset.
-
Festplatte schrieb:
Hat das was mit dem RVA(Relative Virtual Address) zu tun?
nein.
Hier ist gemeint, dass der immediate operand des JMP-Befehls ein relatives Offset ist. Die tatsächliche Sprungadresse muss als noch berechnet werden.Festplatte schrieb:
Die Werte die dort stehen nennt man doch Offset oder? Ich hab mal irgendwo gelesen das dass Adresse heisst und nicht Offset.
ein Offset bezieht sich immer auf Irgendetwas: in diesem Fall wäre 0x401000 ein Offset relativ zur Basis des Code Segments - da aber das flat model vorliegt, und die Basisadresse immer Null ist, handelt es sich um eine Adresse im (virtuellen) Adressraum.
-
Man sieht ja direkt am hexwert, wohin der Jump geht. In diesem Fall 12d vorwärts. Wenn es nach hinten geht, wird von 100h abgezogen, auch wieder ausgehend vom Ende des Jumpbefehls.
-
Wie das mit den short jumps funktioniert habe ich ja jetzt verstanden. Aber wie läuft das beim long Jump?
z.b.
JMP LONG 840000
Erstellt folgendes:
00401012 -E9 E9EF4300 JMP 00840000 00401017 90 NOP 00401018 90 NOP
Ich hab schon versucht es so zu berechnen wie ich es beim short jump machen würde aber das funktioniert leider beim
JUMP LONG
nicht.
-
Du must bedenken das alle diese Übersetzerprogramme versuchen den kürzesten Code zu erstellen.
Wenn es also nicht notwendig ist einen Long Jmp zu machen so wird er zugunsten eines anderen ersetzt.
-
Aber irgendwie muss man das doch berechnen können ...
-
Festplatte schrieb:
Aber irgendwie muss man das doch berechnen können ...
Zieladresse - (Adresse JMP + 5)
-
Bei long jump ist es ganz einfach so, dass das übliche Byte für die Addressenangabe nicht mehr ausreicht. Wenn man früher Far-Jumps gemacht hatte, dann ging es über mehrere Segmente, d.h. das Code-Segment musste mit verändert werden.
in Windows gibt es keine Segmente, alles flat.
(in debugx.com
-rx 386 regs on -a 900 1B1F:0900 jmp 100 1B1F:0903 -d 900 910 1B1F:0900 E9 FD F7 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1B1F:0910 00 - . -u 900 910 1B1F:0900 E9FDF7 JMP 0100 1B1F:0903 0000 ADD [BX+SI],AL 1B1F:0905 0000 ADD [BX+SI],AL 1B1F:0907 0000 ADD [BX+SI],AL 1B1F:0909 0000 ADD [BX+SI],AL 1B1F:090B 0000 ADD [BX+SI],AL 1B1F:090D 0000 ADD [BX+SI],AL 1B1F:090F 0000 ADD [BX+SI],AL -
Die Adresse da oben muss man jetzt so lesen:
E9 F7 (800 rückwärts, F8) FD (3 rückwärts) (gesamt F7FD)
-
nachtfeuer schrieb:
Bei long jump ist es ganz einfach so, dass das übliche Byte für die Addressenangabe nicht mehr ausreicht. Wenn man früher Far-Jumps gemacht hatte, dann ging es über mehrere Segmente, d.h. das Code-Segment musste mit verändert werden.
in Windows gibt es keine Segmente, alles flat.
Natürlich gibt es nach wie vor Segmente, nur das die meisten die Basis 0 haben. Far jumps oder calls sind auch möglich, aber nicht nutzbar, da windows segment discriptors nicht dokumentiert sind.
nachtfeuer schrieb:
Die Adresse da oben muss man jetzt so lesen:
E9 F7 (800 rückwärts, F8) FD (3 rückwärts) (gesamt F7FD)viel einfacher: (Adr. des nächsten Befehls) + Operand = 0x903 + 0xf7fd = 0x100
-
Danke.
00840000 - ( 00401012 + 5 ) = 43EFE9Btw. stimmt das was ich hier schreibe mit den Endians ?
43EFE9 Big Endian
E9EF43 Little Endian00401012 -E9 E9EF4300 JMP 00840000 E9EF4300 <-- Opcodes im Little Endian Format stimmte das?
-
die Zahl ist : unsinged long x = 0x0043EFE9 Little Endian: unsigned char x[4] = {0xE9,0xEF,0x43,0x00}; Big Endian : unsigned char x[4] = {0x00,0x43,0xEF,0xE9};