2012-12-14 11 views
8

Muszę zastąpić standardowe wywołanie systemowe (np. SYS_mkdir) moją własną implementacją.Przechwytywanie wywołania systemowego w module jądra Linux (jądro 3.5)

Jak czytałem w niektórych źródłach, w tym this question na Stackoverflow, sys_call_table nie jest eksportowany symbol od wersji 2.6 jądra.

Próbowałem następujący kod:

#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); 
    } 

    .... 

Niestety otrzymuję błąd kompilatora:

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

Jak mogę zastąpić wywołanie systemowe?

EDYCJA: Czy istnieje rozwiązanie bez łatania jądra?

+0

spróbować z obsadą do typu char * '' następnie przypisać –

+2

może być [to] (http://www.linuxforums.org/forum/kernel/133982-cannot-modify-sys_call_table.html) i [ this] (http://stackoverflow.com/questions/2103315/linux-kernel-system-call-hooking-example) jest pomocny dla ciebie –

+0

Nie ma uniwersalnego rozwiązania bez łatania. –

Odpowiedz

0

Najpierw musisz określić lokalizację sys_call_table. Zobacz here.

Przed zapisaniem do znajdującej się w systemie tabeli systemowej należy ustawić zapisywanie stron pamięci. Dla tego sprawdzenia here, a jeśli to nie zadziała, spróbuj this.

6

Tak, istnieje rozwiązanie bez łatania/odbudowywania jądra. Użyj infrastruktury Kprobes (lub SystemTap).

Umożliwi to umieszczenie "sond" (funkcji) w dowolnym punkcie (punktach) w jądrze przy użyciu modułu jądra.

Wykonanie podobnych czynności przez zmodyfikowanie tabeli sys_call_table jest teraz zablokowane (jest tylko do odczytu). & jest uważany za brudny hack! Kprobes/Jprobes/etc są "czystym" sposobem, aby to zrobić. Ponadto, dokumentacja i samples dostarczone w drzewie źródeł jądra jest doskonałe (patrz pod drzewo src jądra - Documentation/kprobes.txt).

+1

Funkcja kprobes/systemtap nie pozwoli ci * zastąpić * obsługi wywołania systemowego, ale może ją uzupełnić/poprzedza. – fche

+0

Hej, kprobes używa łatania :) –

+0

@fche: tak, zgadzam się. Chodzi o to, że efekt jest podobny .. @ IlyaMatveychikov: AFAIK, no, psprobes jest wbudowaną funkcją jądra; nie musisz stosować żadnej poprawki. Ponadto większość dystrybucji ma włączoną obsługę kphrobów. – kaiwan

7

to działa dla mnie.

Zobacz Linux Kernel: System call hooking example i 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

Zastosowanie LSM infrustructure.

Szczegółowe informacje na temat haczyków LSM: path_mkdir lub inode_mkdir. Jednym z pytań, które należy rozwiązać, jest to, jak zarejestrować swój własny moduł LSM, podczas gdy system nie pozwala na to jednoznacznie. Patrz odpowiedź na szczegóły tutaj:

How can I implement my own hook function with LSM?

0

Problemem jest spowodowana faktem, że sys_call_table jest tylko do odczytu. Aby uniknąć błędu, przed manipulowaniem tabelą sys_call_table musisz również ją zapisać. Jądro zapewnia funkcję do osiągnięcia tego. Ta funkcja jest podana jako set_mem_rw().

Wystarczy dodać poniższy fragment kodu przed manipulowanie sys_call_table

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

W funkcji wyjścia modułu jądra, nie należy zapominać, aby powrócić do sys_call_table z powrotem do zapoznania only.It można osiągnąć jak poniżej .

set_mem_ro((long unsigned int)sys_call_table,1);  
Powiązane problemy