Verständnisproblem: CALL und Adresse



  • Guten Tag,

    ich bin aktuell dabei mich etwas mit Reverse Engineering auseinander zu setzen und habe dazu eine (vermeintlich) einfache Frage.

    Ich habe diese Befehlszeile:

    Adresse        Op-Codes      Darstellung von OllyDbg
    ---------------------------------------------------------
    102C83D0    /$ 8B5424 04     MOV EDX,DWORD PTR SS:[ESP+4]
    

    Mein nächstes Ziel ist, alle Codestellen zu finden, die auf diese Adresse "zeigen". Genauer genommen gibt es im Code einige Stellen, die einen CALL auf die Adresse 0x102C83D0 absetzen.

    Im Debugging-Programm OllyDbg kann ich einfach Rechtsklick auf den Befehl machen und "Find references to -> Selected command" auswählen. Ich habe nun versucht das nachzubauen, scheitere aber daran, zu verstehen, wie der ASM Code aussehen muss.

    Beispiel: Eine Referenz sieht so aus:

    Adresse        Op-Codes      Darstellung von OllyDbg
    ---------------------------------------------------------
    103340AF    ./ E8 1C43F9FF   CALL meinedll.102C83D0
    

    Also befindet sich die Referenz an der Stelle 0x103340AF - das ist soweit richtig, oder?
    Der erste Op-Code ist der E8 . Das ist dann vermutlich der CALL -Befehl.
    Und nun komme ich zu der Stelle, die nicht verstehen kann: Woher weiß der Computer, dass die Op-Codes 1C43F9FF auf die Stelle 0x102C83D0 zeigen?

    Ich müsste nun wissen, wie man die Op-Codes berechnet, damit ich danach suchen kann.

    Ein Hinweis noch: Es gibt mehrere Referenzen, die ich alle benötige. Bei allen sieht der Op-Code nach dem E8 -Befehl _anders_ aus. Meine Vermutung: Das ist irgendeine relative Berechnung der Adresse - fragt sich nur, wie.

    Ich bin dankbar für eine ausführliche Erklärung oder eine kurze Antwort. Aber ich möchte es möglichst auch verstehen.

    Gracias!



  • [url=http://www.intel.com/products/processor/manuals/]Intel® 64 and IA-32 Architectures Software Developer's Manual
    Volume 2A: Instruction Set Reference, A-M
    [/url] (Seite 190):

    A relative offset (rel16 or rel32) is generally specified as a label in assembly code. But
    at the machine code level, it is encoded as a signed, 16- or 32-bit immediate value.
    This value is added to the value in the EIP(RIP) register. In 64-bit mode the relative
    offset is always a 32-bit immediate value which is sign extended to 64-bits before it
    is added to the value in the RIP register for the target calculation. As with absolute
    offsets, the operand-size attribute determines the size of the target operand (16, 32,
    or 64 bits). In 64-bit mode the target operand will always be 64-bits because the
    operand size is forced to 64-bits for near branches.

    Daher:

    0x103340AF (Adresse von E8) + 0x5 (Größe von E8 + Operand in Bytes) + 0xFFF9431C (Operand (Low-Endian!)) = 0x[u]1[/u]102C83D0 (die 1 steht, da nur 32 Bit große Register, ins S-Flag)
    


  • Danke, das hat mir auf jeden Fall schon mal geholfen, und ich verstehe das auch 🙂

    Nun ist aber die Frage, wie ich mit der Zusätzlichen 1 umgehe.

    Mein aktueller Ansatz ist: Nach allen E8 suchen, dann bei jedem Fund:

    (0x102C83D0 + 4294967296L) - E8-Position - 0x5 = Op-Codes-Big (Big-Endian oder wie?)

    Dazu zwei Fragen:

    1.) Wie kriege ich die Op-Codes-Big nun zu einem Low-Endian umformen, so dass aus fff9431c das wird: 1c43f9ff ?
    2.) Wie löse ich das _ordentlich_ mit der Zahl 4294967296L ?

    Gruß und Danke



  • Ich muss mich kurz noch berichtigen: diese zusätzliche 1 ist natürlich am gesetzten Carry- und nicht am Sign-Flag zu erkennen.

    Die Reihenfolge der Bytes kannst du mit der x86-Anweisung BSWAP (Seite 174 in dem oben genannten "Buch") beeinflussen.

    Wenn du in C oder x86-ASM codest kann dir diese 1 egal sein. Bei C nimmst du einfach einen vorzeichenlosen 32 Bit großen Typ (z.B. unsigned int).

    Was du mit 4294967296L und der Gleichung machen möchtest versteh ich nicht. Soll der Operand von CALL (E8) ermittelt werden?

    unsigned __int32 operand = 0x1102C83D0 - 0x103340AF - 0x5;
    

    Du solltest aber auch beachten, dass diverse CALLs existieren und deren Operanden nicht nur 16, 32 oder 64Bit groß sein können, sondern auch relativ oder absolut! Weiteres steht ja in dem PDF.



  • Hi,

    die große Zahl brauch ich ja, damit ich die "1" da vorne weg kriege. Ich programmiere in C (bzw. C++) und habe von ASM noch nicht wirklich die Ahnung.

    Hintergrund ist wie gesagt, dass ich die Adresse zu der ich die Referenzen suchen möchte, erst zur Laufzeit herausbekomme (durch Suche nach bestimmten Bytes im Memory des Programms). In meinem Fall wäre das halt 0x102C83D0 . Jetzt müsste ich ja (aus meiner Sicht) das ganze mit der Zahl 4294967296L addieren, um auf 0x1102C83D0 zu kommen. Dann müsste ich nach allen E8 im Memory suchen, um dann irgendwie zu berechnen, ob der CALL auf meine gesuchte Stelle zeigt. Man, ist das alles kompliziert. Und wenn es dann noch mehrere Fälle gibt, dass eine Adresse auch absolut sein kann... Oh man.

    Gracias!



  • Versuchs doch mal per Breakpoints


Anmelden zum Antworten