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 JMP
s 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;-)