2012-12-14 8 views
8

Ich muss einen Standardsystemaufruf (z. B. SYS_mkdir) durch meine eigene Implementierung ersetzen.Abfangen von Systemaufrufen im Linux-Kernelmodul (Kernel 3.5)

Wie ich in einigen Quellen, einschließlich this question auf Stackoverflow lesen, wird das sys_call_table nicht als Symbol seit Kernel-Version 2.6 exportiert.

Ich habe versucht, den folgenden Code:

#include <linux/module.h> 
    #include <linux/kernel.h> 
    #include <linux/unistd.h> 
    #include <asm/syscall.h> 

    int (*orig_mkdir)(const char *path); 

    .... 

    int init_module(void) 
    { 
      orig_mkdir=sys_call_table[__NR_mkdir]; 
      sys_call_table[__NR_mkdir]=own_mkdir; 
      printk("sys_mkdir replaced\n"); 
      return(0); 
    } 

    .... 

Leider erhalte ich Compiler-Fehler:

error: assignment of read-only location ‘sys_call_table[83]’ 

Wie kann ich das Systemaufruf ersetzen?

EDIT: Gibt es eine Lösung ohne Kernel-Patch?

+0

versuchen mit Typumwandlung zu 'char *' dann –

+2

zuweisen kann [diese] (http://www.linuxforums.org/forum/kernel/133982-cannot-modify-sys_call_table.html) und [ dies] (http://stackoverflow.com/questions/2103315/linux-kernel-system-call-hooking-example) ist hilfreich für Sie –

+0

Es gibt keine universelle Lösung ohne Patching. –

Antwort

0

Zuerst müssen Sie den Speicherort von sys_call_table bestimmen. Siehe here.

Bevor Sie in die gerade gefundene Systemtabelle schreiben, müssen Sie ihre Speicherseiten beschreibbar machen. Überprüfen Sie dazu here und wenn das nicht funktioniert, versuchen Sie this.

6

Ja, es gibt eine Lösung ohne Patchen/Neuaufbau des Kernels. Verwenden Sie die Kprobes Infrastruktur (oder SystemTap).

Dies ermöglicht es Ihnen, "Sonden" (Funktionen) an beliebigen Punkten im Kernel mit einem Kernel-Modul zu platzieren.

Durch Ändern der sys_call_table wird jetzt verhindert, dass ähnliche Dinge verhindert werden (es ist schreibgeschützt) & wird als dreckiger Hack betrachtet! Kprobes/Jprobes/etc sind eine "saubere" Möglichkeit, dies zu tun. Auch die Dokumentation und samples in der Kernel-Source-Baum ist ausgezeichnet (siehe unter dem Kernel src tree-Documentation/kprobes.txt).

+1

kprobes/systemtap lässt Sie * den Systemaufruf-Handler * nicht ersetzen, sondern kann ihn ergänzen/ergänzen. – fche

+0

Hey, kprobes verwendet patchen :) –

+0

@fche: ja, ich stimme zu. Der Punkt war, dass der Effekt ähnlich ist. @ IlyaMatveychikov: AFAIK, nein, kprobes ist eine In-Kernel-Funktion; Sie müssen keinen Patch anwenden. Auch die meisten Distributionen haben kprobes aktiviert. – kaiwan

7

das funktioniert für mich.

Siehe Linux Kernel: System call hooking example und https://bbs.archlinux.org/viewtopic.php?id=139406

asmlinkage long (*ref_sys_open)(const char __user *filename, int flags, umode_t mode); 
asmlinkage long new_sys_open(const char __user *filename, int flags, umode_t mode) 
{ 
    return ref_sys_open(filename, flags, mode); 
} 

static unsigned long **aquire_sys_call_table(void) 
{ 
    unsigned long int offset = PAGE_OFFSET; 
    unsigned long **sct; 

    while (offset < ULLONG_MAX) { 
    sct = (unsigned long **)offset; 

    if (sct[__NR_close] == (unsigned long *) sys_close) 
     return sct; 

    offset += sizeof(void *); 
    } 
    print("Getting syscall table failed. :("); 
    return NULL; 
} 


// Crazy copypasted asm stuff. Could use linux function as well... 
// but this works and will work in the future they say. 
static void disable_page_protection(void) 
{ 
    unsigned long value; 
    asm volatile("mov %%cr0, %0" : "=r" (value)); 

    if(!(value & 0x00010000)) 
    return; 

    asm volatile("mov %0, %%cr0" : : "r" (value & ~0x00010000)); 
} 

static void enable_page_protection(void) 
{ 
    unsigned long value; 
    asm volatile("mov %%cr0, %0" : "=r" (value)); 

    if((value & 0x00010000)) 
    return; 

    asm volatile("mov %0, %%cr0" : : "r" (value | 0x00010000)); 
} 


static int __init rootkit_start(void) 
{ 

    //Hide me 

    print("loaded"); 

    if(!(sys_call_table = aquire_sys_call_table())) 
    return -1; 

    disable_page_protection(); 
    { 
    ref_sys_open = (void *)sys_call_table[__NR_open]; 
    sys_call_table[__NR_open] = (unsigned long *)new_sys_open; 
    } 
    enable_page_protection(); 
    return 0; 
} 

static void __exit rootkit_end(void) 
{ 
    print("exiting"); 

    if(!sys_call_table) { 
    return; 
    } 

    disable_page_protection(); 
    { 
    sys_call_table[__NR_open] = (unsigned long *)ref_sys_open; 
    } 
    enable_page_protection(); 
} 
0

Verwendung LSM infrustructure.

Siehe LSM Haken path_mkdir oder inode_mkdir für Details. Eine Frage, die gelöst werden muss, ist, wie man sein eigenes LSM-Modul registriert, während das System es nicht explizit erlaubt. Siehe die Antwort für Details hier:

How can I implement my own hook function with LSM?

0

Das Problem aufgrund der Tatsache verursacht wird, dass sys_call_table nur gelesen wird. Um den Fehler zu vermeiden, müssen Sie vor der Manipulation der sys_call_table diese ebenfalls schreibbar machen. Der Kernel bietet eine Funktion, um dies zu erreichen. Und diese Funktion wird als set_mem_rw() angegeben.

Fügen Sie einfach den unten Code-Schnipsel vor den sys_call_table

set_mem_rw((long unsigned int)sys_call_table,1); 

In der Exit-Funktion des Kernel-Moduls zu manipulieren, vergessen Sie bitte nicht die sys_call_table zurück um wieder zurück zu lesen only.It wie unten erreicht werden .

set_mem_ro((long unsigned int)sys_call_table,1);