Warum kann diese Instruktion nicht angesprungen werden?



  • Hallo,

    ich hatte vor einiger Zeit eine Präsentation über API HotPatching. Für alle die nicht so genau wissen wovon ich rede.
    Seit dem XP SP2 wurden viele Funktionsprologe wie dieser hier:

    7731a328 55               push    ebp
    7731a329 8bec             mov     ebp,esp
    

    gegen neue "ausgetaucht" bzw erweitert:

    7731a321 90               nop
    7731a322 90               nop
    7731a323 90               nop
    7731a324 90               nop
    7731a325 90               nop 
    7731a326 8bff             mov     edi,edi
    7731a328 55               push    ebp
    7731a329 8bec             mov     ebp,esp
    

    Das ermöglicht uns zur Laufzeit Funktionen "auszutauschen" ohne das System neu starten zu müssen.
    Funktionsweise:

    Die Instruktion

    7731a326 8bff             mov     edi,edi
    

    ist nichts anderes als ein 2 Byte NO-OP. Diese wird beim HotPatsching gegen einen Short JMP getauscht.
    Die 5 NOPs dadrüber werden gegen einen FAR JMP zur gepatchten Funktion ersetzt. Dar Hintergedanke mit den 2 JMPs ist das Thema Thread safety.
    Beispiel:
    Das ist unsere Funktion die ungepatcht ist. Diese hat natürlich 0 Sinn;-)

    01001175 8bff             mov     edi,edi
       01001177 53               push    ebx
       01001178 50               push    eax
       01001179 53               push    ebx
       0100117a 51               push    ecx
       0100117b 52               push    edx
       0100117c 5a               pop     edx
       0100117d 59               pop     ecx
       0100117e 5b               pop     ebx
       0100117f 58               pop     eax
       01001180 5b               pop     ebx
       01001181 c3               ret
    

    Thread 1 kommt jetzt daher und führt die erste Instruktion bei 01001175 aus und hat als nächste Instruktion die 01001177 drin.
    Nun kommen wir mit unserem API HotPatch und ersetzen die Funktion wie folgt:

    01001175 ea871100011b00   jmp     001b:01001187
       0100117c 5a               pop     edx
       0100117d 59               pop     ecx
       0100117e 5b               pop     ebx
       0100117f 58               pop     eax
       01001180 5b               pop     ebx
       01001181 c3               ret
    

    Das ganze ist natürlich absolut fatal weil, nachdem wir fertig sind, Thread 1 die Instruktion ausführen möchte, die nun mitten in der neuen Instruktion bei 01001175 liegt.

    Nun meine Frage:
    Wieso kann der Prozessor nicht "mitten in" die Anweisung bei 01001175 springen und da "irgendwas" ausführen?
    Also die von Microsoft werden sich schon was dabei gedacht haben. Ganz klar. Und das das nicht funktioniert glaube ich ja auch aber wieso geht das nicht und wer erkennt, was eine komplette Anweisung ist und was nicht?



  • secondsun schrieb:

    Wieso kann der Prozessor nicht "mitten in" die Anweisung bei 01001175 springen und da "irgendwas" ausführen?

    Also technisch gesehen kann er es. Er würde dann allerdings versuchen die Sprungadresse selbst (871100011b00) als Befehl zu interpretieren, was mindestens Chaos verursacht.

    wer erkennt, was eine komplette Anweisung ist und was nicht?

    Wenn ich deine Beschreibung lese, dann läuft das Patching glaub ich anders ab. Also der Patch überschreibt das mov edi,edi mit einem short jump und nicht mit einem far jump (was vermutlich eh eher ein near jump sein soll). Die ungepatchte Funktion muss so aussehen:

    01001170 90               nop
       01001171 90               nop
       01001172 90               nop
       01001173 90               nop
       01001174 90               nop
       01001175 8bff             mov     edi,edi
       01001177 53               push    ebx   -
       01001178 50               push    eax     \
       01001179 53               push    ebx     |
       0100117a 51               push    ecx     |
       0100117b 52               push    edx     |
       0100117c 5a               pop     edx      > Das wird eh nicht angerührt, weil das der "echte" Code ist.
       0100117d 59               pop     ecx     |
       0100117e 5b               pop     ebx     |
       0100117f 58               pop     eax     |
       01001180 5b               pop     ebx     |
       01001181 c3               ret           -/
    

    Die nops werden vom near jump zur neuen Funktion überschrieben und das mov edi, edi wird mit dem short jump zum near jump überschrieben. (In der Reihenfolge, was dann die thread safety halbwegs erhalten sollte. Ob das auf Multiprozessorsystemen noch klappt, müsste man mal sehen ;))

    ; Die Opcodes schlag ich nicht nach, deswegen nur lustige Buchstaben^^
       01001170 aabbccddee            jmp     neue_funktion
       01001175 xxyy                  jmp     01001170
    


  • Guten morgen;-)

    Das kurze Beispiel wo der Code mit überschrieben wird, war ja nur mal ein bisschen schwachsinniger Code um mal zu zeigen was ich meine. Ist natürlich korrekt was du gesagt hast;-) Sonst wäre das ganze ja mal kein bisschen Thread safe.

    Aber was ich ja wissen wollte, also ob der Prozessor den COde trotzdem ansteuern kann, ist damit dann ja geklärt und das es ein Chaos verursachen würde ist auch klar:-)

    Danke nochmal;-)


Log in to reply