2015-11-11 10 views
7

Ich arbeite an einem Projekt, bei dem ich 80% -90% der Systemaufruffunktionen auf OSX (10.10.5) haken muss. Ich mache das von einer Kernel-Erweiterung. Da ich viele Funktionen haken muss, möchte ich die ursprüngliche Kernelfunktion in einem Array von Funktionszeigern speichern, damit ich das Array schnell durchsuchen kann, um die ursprüngliche Funktion beim Abhaken wiederherzustellen.Speichern von SYSCALL-Funktionen im Array von Funktionszeigern

int (*kern_open)(struct proc *, struct open_args *, int *); 
    int mon_open(struct proc *p, struct open_args *uap, int *retval) { 
    kern_open = sysent[SYS_open].sy_call; 
    sysent[SYS_open].sy_call = mon_open; 

Dies funktioniert, wird die kern_open Funktion verwendet, um die ursprüngliche Kernfunktion zu speichern, die auf einen Systemaufruf s genannt. mon_open ist meine hooking-Funktion.

Was ich erreichen möchte, ist das Folgende; damit ich beim Abhaken einfach durch das KernSysCall-Array iterieren und die Funktionen wiederherstellen kann.

// global array of function pointers that all have the same func def. 
    static int (*KernSysCall[SYS_MAXSYSCALL])(struct proc *, struct args *, int *); 
    KernSysCall[SYS_open] = sysent[SYS_open].sy_call; 
    sysent[SYS_open].sy_call = mon_open; 

Wiederherstellen: sysent[SYS_open].sy_call = KernSysCall[SYS_open];

jedoch die ursprüngliche Kernfunktion innerhalb der Anordnung von Funktionszeiger speichert, wird eine Kernel-Panik verursacht. Ich konnte die lldb noch nicht anhängen, aufgrund eines error: KDP_REATTACH failed Fehlers. Ich hoffe, dass jemand weiß, was die Kernel-Panik verursacht.

Unten ist ein Protokoll der Kernel Panic.

Anonymous UUID:  052D64D2-A43C-99F8-D221-B591991E54AF 

Wed Nov 11 12:55:06 2015 

*** Panic Report *** 
panic(cpu 0 caller 0xffffff80093f0024): Kernel trap at 0x0000000000000000, type 14=page fault, registers: 
CR0: 0x0000000080010033, CR2: 0x0000000000000000, CR3: 0x00000000769bb018, CR4: 0x00000000001606e0 
RAX: 0x0000000000000000, RBX: 0xffffff80115e3fc0, RCX: 0x0000000000000001, RDX: 0xffffff80115e3fc0 
RSP: 0xffffff8068dabaf8, RBP: 0xffffff8068dabf50, RSI: 0xffffff80115e3f80, RDI: 0xffffff8010059cf0 
R8: 0xffffff7f8afaccdf, R9: 0xffffff8009ae2a18, R10: 0xffffff8009939740, R11: 0x0000000000000000 
R12: 0xffffff8010059cf0, R13: 0x0000000000000005, R14: 0xffffff80115e3f80, R15: 0xffffff801188b480 
RFL: 0x0000000000010282, RIP: 0x0000000000000000, CS: 0x0000000000000008, SS: 0x0000000000000010 
Fault CR2: 0x0000000000000000, Error code: 0x0000000000000010, Fault CPU: 0x0 VMM 

Backtrace (CPU 0), Frame : Return Address 
0xffffff8068dab790 : 0xffffff80092e4ed1 mach_kernel : _panic + 0xd1 
0xffffff8068dab810 : 0xffffff80093f0024 mach_kernel : _kernel_trap + 0x664 
0xffffff8068dab9e0 : 0xffffff800940de53 mach_kernel : trap_from_kernel + 0x26 
0xffffff8068daba00 : 0x0 
0xffffff8068dabf50 : 0xffffff800982c0c1 mach_kernel : _unix_syscall64 + 0x2f1 
0xffffff8068dabfb0 : 0xffffff800940e656 mach_kernel : _hndl_unix_scall64 + 0x16 

BSD process name corresponding to current thread: xpcproxy 
Boot args: debug=0x14e kext-dev-mode=1 -v keepsyms=1 kmem=1 

Mac OS version: 
14F27 

Kernel version: 
Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/DEVELOPMENT_X86_64 
Kernel UUID: C75BDFDD-9F27-3694-BB80-73CF991C13D8 
Kernel slide:  0x0000000009000000 
Kernel text base: 0xffffff8009200000 
__HIB text base: 0xffffff8009100000 
System model name: VMware7,1 (Mac-66F35F19FE2A0D05) 

System uptime in nanoseconds: 251264993940 
last loaded kext at 249789197520: my.kext 1 (addr 0xffffff7f8afa9000, size 57344) 
last unloaded kext at 116769666233: com.apple.driver.AppleFileSystemDriver 3.0.1 (addr 0xffffff7f8aed3000, size 16384) 
loaded kexts: 
my.kext 1 

[more kexts here] 

In Wunsch der Code für mon_open():

int 
mon_open(struct proc *p, struct open_args *uap, int *r) { 
    int error; 
    char processname[MAXCOMLEN+1]; 
    char intercepted_path[MAXPATHLEN]; 

    pid_t pid = proc_pid(p); 

    proc_name(pid, processname, sizeof(processname)); 

    size_t dummy = 0; 
    error = copyinstr((void *)uap->path, (void *)intercepted_path, MAXPATHLEN, &dummy); 
    if (!error) { 
     printf("[MYKEXT] open called with path: %s, PID: %d, processname: %s\n", intercepted_path, pid, processname); 
    } 

    return kern_open(p, uap, r); 
} 

Vielen Dank im Voraus!

+0

Eine einigermaßen gut geschriebene Frage! Sind Sie sicher, dass es die Zeile 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' ist, die die Panik verursacht? (Ich nehme an, '[SYS_open]' in der Frage sollte 'sysent [SYS_open]') sein. – immibis

+0

Danke. Das ist richtig. Ich bin mir fast 100% sicher. Die Deklaration des statischen Arrays verursacht keine Panik. Doing das gleiche Array-Ding mit Primitiven (e.x. int) verursacht keine Panik. Nur wenn ich 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call;' zuweiße. Der Rest ist so ziemlich wie die hässliche "array-less" -Lösung. – Joseph

+0

Beachten Sie, dass DTrace auch den sy_call verschiedener sysent-Einträge ändert. Wenn also irgendetwas in Ihrem System DTrace verwendet, können Sie und Ihr Hook sich gegenseitig auf die Füße treten. Stürzt es auf * Entladen * Ihres Kext, oder haken Sie ab, ohne zu entladen? Hast du deine Kernel-Panik symbolisiert, um genau zu sehen, was passiert? (Mit einem Kernel-Argument von 'keepyms = 1' wird der Kernel den Absturz für Sie symbolisieren) Um Ihnen zu helfen, Ihren LLDB-Fehler zu diagnostizieren, müssen Sie uns ein bisschen mehr Informationen über Ihre Einrichtung geben. – pmdj

Antwort

0

Erstaunlich dumm, habe ich vergessen, kern_open (der Rückgabewert von mon_open) auf den Funktionszeiger im Array. kern_open war NULL, so verursachte dies die NULL-Zeiger-Ausnahme. Jetzt funktioniert das Array der Funktionszeiger korrekt.

@pmdj, vielen Dank für Ihre Hilfe.

+0

Froh, dass Sie es behoben haben. Freut mich zu hören, dass ich den falschen Baum nicht vollständig angebetet habe. :-) – pmdj

0

Die 0x0-Zeile im Panikprotokoll zeigt an, dass entweder ein NULL-Funktionszeiger aufgerufen wird (in diesem Fall wahrscheinlicher) oder Sie den Stapel zerstört und einen Rückgabezeiger mit NULL überschrieben haben. Sind Sie sicher, dass Sie keine Syscalls "wiederherstellen", die Sie nie angeschaltet haben?

Damit lldb mit virtuellen Maschinen funktioniert, hängen die Anforderungen von den verschiedenen Virtualisierungsumgebungen ab. Mit VMWare Fusion sollte es einfach funktionieren, vorausgesetzt, Sie verwenden "Host-Only-Netzwerk" oder Bridge-Modus. Mit VirtualBox funktionierte es beim letzten Mal nur mit dem Virtio-Netzwerkgerät und ich konnte es bei Parallels überhaupt nicht funktionieren, aber das war vor einigen Jahren. Wenn Sie Ihrer VM einen seriellen Port hinzufügen und in eine Textdatei schreiben, können Sie sich unter Verwendung von kprintf() bei diesem Protokoll anmelden. Dies kann Ihnen hier helfen, da Sie Ihre Zeigerwerte beim Ein- und Aushängen ausdrucken können.

+0

Die Panik tritt auf, wenn diese ausgeführt werden: 'KernSysCall [SYS_open] = sysent [SYS_open] .sy_call; sysent [SYS_open] .sy_call = mon_open; '. Ich restauriere nur beim Entladen des Kext. Da ich das manuell mache, weiß ich, dass die Wiederherstellung nicht die Panik verursacht. Könnte es etwas mit falscher Zeigerdereferenzierung zu tun haben? (Ich bin ein bisschen C-noob). – Joseph

+0

Es stürzt ab, weil ein Prozess (xpcproxy) einen Syscall ausführt und entweder eine NULL-Funktion aufruft oder die aufgerufene Funktion einen Fehler enthält. Was ist der Code für 'mon_open'? (Wenn Sie es lieber nicht posten möchten, reduzieren Sie es auf etwas Minimales, das noch funktionieren sollte, dh rufen Sie die gespeicherte Funktion ptr auf, dann testen Sie das.) Ihre Array-Deklaration sieht für mich korrekt aus, aber es ist schwer zu sagen, weil C-Funktionszeiger Syntax ist verwirrend. Ich würde den Funktionszeigertyp "typedef" eingeben und dann das Array als ein Array dieser Typen deklarieren, nur um sicher zu gehen. – pmdj

+0

Ich habe den Code für mon_open() aded, aber ich bezweifle stark, dass das Problem in dieser Funktion ist, da die exakt gleiche Funktion in der oberen Lösung verwendet wird und gut funktioniert. Ich habe eine typedef erstellt: 'typedef int (* kern_f) (struct proc *, struct args *, int *); static kern_f array [SYS_MAXSYSCALL]; 'und danach in einer anderen Funktion:' array [SYS_open] = sysent [SYS_open] .sy_call; ' – Joseph