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 F6

    74 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 ) = 43EFE9

    Btw. stimmt das was ich hier schreibe mit den Endians ?

    43EFE9 Big Endian
    E9EF43 Little Endian

    00401012    -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};
    

Anmelden zum Antworten