Patch Points
Date: 2013-09-13
Gestern hab ich ja über Selbstmodifizierende Binaries geschrieben. Das möchte ich heute etwas fortsetzen. Allerdings geht es diesmal nicht um dauerhafte Modifikation, sondern um Modifikation die während der Laufzeit bestehen bleibt. Aber theoretisch könnte man beides auch verbinden. Vor längerer Zeit habe ich mal darüber nachgedacht, dass man ja manchmal ein System dynamisch umkonfigurieren will. Dabei werden dann die unterschiedlichen Varianten über eine Wenn-Abfrage ausgewählt:
if (featureA.enabled()) { // Feature A; } if (featureB.enabled()) { // Feature B; }
Dies führt allerdings dazu, dass zur Laufzeit beständig
Funktionsaufrufe an die .enabled()
Funktionen gemacht werden. Der
dazu passende Assembler sieht dann ungefähr so aus:
e8 66 05 00 00 call 8048a6e <__enabled_featureA> 83 f8 17 cmp $0x17,%eax 75 ab jne 80484c0 <main+0x10>
Jetzt habe ich mir den Spass gemacht die
patch-point Bibliothek
zu schreiben. Sie löst das Problem dadurch, dass sie die Stelle, an
der solche Abfragen stehen entweder durch nop
Instruktionen ersetzt,
oder durch einen unbedingten Sprungbefehl. Das ganze wird dann noch
mit einem bischen synaktischem Zucker gewürzt, und dann sieht der
C-Code dazu so aus:
#include <patch_point.h> #include <stdio.h> patch_point_list ppl; void foo() { patch_point(&ppl, "pp") { printf("enabled\n"); } else { printf("disabled\n"); } } int main() { foo(); patch_point_disable(&ppl, "pp"); foo(); }
Dabei sieht das patch_point
macro etwas seltsam aus, aber es wird
vom Präprozessor zu einem if (__patch_point(&ppl, "pp") == 23
gemacht. Nach dem komplieren sieht der Code ungefähr so aus, wie das
Assembler-Fragment oben. Die Funktion __patch_point
sucht sich dann
über die Rücksprungaddresse die Stelle im Code raus, wo diese
Instruktionen stehen. Nach dem ersten Aufruf, patcht sich der
Funktionsaufruf selbst raus, und speichert die Stelle und weitere
Informationen in der patch point Liste ab. Der Code sieht dann so aus:
90 90 90 90 90 nop nop nop nop nop e9 99 02 00 00 jmp 804878d <main+0x10>
Mit dem Aufruf zu patch_point_disable
Wird der jmp
Befehl wieder
rausgepatcht, und der Code im Speicher sieht dann so aus:
90 90 90 90 90 nop nop nop nop nop 90 90 90 90 90 nop nop nop nop nop