Экспорт символов ядра и таблица системных вызовов

Вопросы программного кода и архитектуры Linux

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 12 дек 2011, 04:05

Это уже достаточно сложные вопросы из области ядра Linux, но они принципиально важные ...

Я позже напишу достаточно обстоятельно, а пока в 2 слова (время позднее) в чём вопросы:

1. какие имена ядра из всех имён /proc/kallsyms экспортируются, а какие - нет, т.е. какие вызовы (может, и структуры данных) ядра можно использовать в программном коде своих модулей ядра, а какие не получится?

2. утверждается, что с версий ядра 2.6.х таблица системных вызовов ядра не экспортируется, вот эта:

Код: Выделить всё

[olej@notebook etc]$ cat /proc/kallsyms | grep sys_call_table
c07ab3d8 R sys_call_table
и это так и есть...
но уже предлагались способы (хакерские) "добычи" в коде модуля адреса этой таблицы... мне тоже кажется, что есть на то способы...

3. а это даёт путь подмены кода системных вызовов Linux, что а). даёт возможность для вирусописателей + б). может быть использовано и в созидательных целях, например для разного рода мониторинга...

P.S. я уже подробно описал постановку задачи ... в другом месте: http://linuxforum.ru/viewtopic.php?id=18789, если кого интересует, может смотреть там ... сюда же я собираюсь выбрасывать только относительно "чистый" материал, резюме ;-)

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 12 дек 2011, 12:43

Olej писал(а): но уже предлагались способы (хакерские) "добычи" в коде модуля адреса этой таблицы... мне тоже кажется, что есть на то способы...
Есть 1-й вариант такого модуля.
Вот код, кто интересуется ядром:

Код: Выделить всё

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/moduleparam.h>

static char* file = "/proc/kallsyms";
module_param( file, charp, 0 );
static int debug = 0;
module_param( debug, int, 0 );

static unsigned long hex2adr( char *b ) {
    unsigned long res = 0;
    char *p = b, *d;
    const char *dig = "0123456789abcdef";
    while( ( d = strchr( dig, *p ) ) != NULL ) {
        res = ( res << 4 ) + ( d - dig );
        p++;
    }
    return res;
}

int verify_close( unsigned long *a ) {
    extern int sys_close( int fd );
    int cmp;
    unsigned long ca = *( a + __NR_close );
    cmp = ( (void*)ca == (void*)sys_close ) ? 0 : 1;
    return cmp;
}

void put_table( char *b ) {
    int i;
    char table[ 120 ] = "sys_call_table : ";
    unsigned long *a;
    unsigned long s = hex2adr( b );
    a = (void*)s;
    printk( "+ sys_call_table address = %p\n", a );
    if( verify_close( a ) != 0 ) {
        printk( "+ sys_close address not valid!\n" );
        return;
    }
    for( i = 0; i < 10; i++ ) {
        unsigned long sa = *( a + i );
        sprintf( table + strlen( table ), "%p ", (void*)sa );
    }
    printk( "+ %s ...\n", table );
}

#define BUF_LEN 255
static int __init stread_init( void ) {
    struct file *f;
    size_t n = 0;
    char buff[ BUF_LEN + 1 ] = "";

    f = filp_open( file, O_RDONLY, 0 );
    if( IS_ERR( f ) ) {
        printk( "+ failed to open: %s\n", file );
        return -ENOENT;
    }
    printk( "+ openning file: %s\n", file );

    while( 1 ) {
       char *p = buff, *find;
       int k;
       *p = '\0';
       do {
           if( ( k = kernel_read( f, n, p++, 1 ) ) < 0 ) {
               printk( "+ failed to read\n" );
               return -EIO;
           };
           *p = '\0';
           if( 0 == k ) break;
           n += k;
           if( '\n' == *( p - 1 ) ) break;
       } while( 1 );
       if( ( debug != 0 ) && ( strlen( buff ) > 0 ) ) {
           if( '\n' == buff[ strlen( buff ) - 1 ] ) printk( "+ %s", buff );
           else printk( "+ %s|\n", buff );
       }
       if( 0 == k ) break;   // EOF

       if( NULL == ( find = strstr( buff, "sys_call_table" ) ) ) continue;
       put_table( buff );
    }
    
    printk( "+ close file: %s\n", file );
    filp_close( f, NULL );
    return -EPERM;
}

module_init( stread_init );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" );

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 12 дек 2011, 12:48

Olej писал(а): Есть 1-й вариант такого модуля.
Вот его выполнение:

Код: Выделить всё

[olej@notebook call_table]$ sudo insmod mod_rct.ko
insmod: error inserting 'mod_rct.ko': -1 Operation not permitted

[olej@notebook call_table]$ dmesg | tail -n50 | grep +
+ openning file: /proc/kallsyms
+ sys_call_table address = c07ab3d8
+ sys_call_table : c044ec61 c0444f63 c040929c c04e149d c04e12fc c04dec35 c04dea99 c0444767 c04dec60 c04ecb22  ...
+ close file: /proc/kallsyms
Проверка полученных цифр "обратным отсчётом":

Код: Выделить всё

[olej@notebook ~]$ cat /proc/kallsyms | grep c044ec61
c044ec61 T sys_restart_syscall
[olej@notebook ~]$ cat /proc/kallsyms | grep c0444f63
c0444f63 T sys_exit
[olej@notebook ~]$ cat /proc/kallsyms | grep c040929c
c040929c t ptregs_fork
[olej@notebook ~]$ cat /proc/kallsyms | grep c04e149d
c04e149d T sys_read
[olej@notebook ~]$ cat /proc/kallsyms | grep c04e12fc
c04e12fc T sys_write
[olej@notebook ~]$ cat /proc/kallsyms | grep c04dec35
c04dec35 T sys_open
[olej@notebook ~]$ cat /proc/kallsyms | grep c04dea99
c04dea99 T sys_close
[olej@notebook ~]$ cat /proc/kallsyms | grep c0444767
c0444767 T sys_waitpid
[olej@notebook ~]$ cat /proc/kallsyms | grep c04dec60
c04dec60 T sys_creat
[olej@notebook ~]$ cat /proc/kallsyms | grep c04ecb22
c04ecb22 T sys_link
А вот те же системные вызовы по кодам-номерам:

Код: Выделить всё

[olej@notebook etc]$ cat /usr/include/asm/unistd_32.h | head -n20
...
#define __NR_restart_syscall      0
#define __NR_exit                 1
#define __NR_fork                 2
#define __NR_read                 3
#define __NR_write                4
#define __NR_open                 5
#define __NR_close                6
#define __NR_waitpid              7
#define __NR_creat                8
#define __NR_link                 9
#define __NR_unlink              10
...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 12 дек 2011, 12:54

Я колебался, показывать ли это... поскольку, при желании, это прямой путь к написанию вирусов (в том числе, помимо созидательных приложений).
Потому как получив таблицу sys_call_table дальше подменять системные вызовы на свои обработчики - это уже проще простого.

Но, с другой стороны, придурки - они и сами придумают, а сама возможность и техника - интересные.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 12 дек 2011, 20:50

Там же (в обсуждении - http://linuxforum.ru/viewtopic.php?pid=234078#p234078) показали сискол (из числа новых), с которым это же делается элементарно просто:

Код: Выделить всё

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kallsyms.h>

static int __init ksys_call_tbl_init(void)
{
    void** sct = (void**)kallsyms_lookup_name("sys_call_table");
    printk(KERN_ALERT "sys_call_table = %lx\n", (long)sct);
    if(sct)
        printk(KERN_ALERT "%lx %lx %lx\n", (long)sct[0], (long)sct[1], (long)sct[2]);
    return -100500;
}

module_init(ksys_call_tbl_init);
MODULE_LICENSE( "GPL" );
Но он не настолько новый, чтоб это могло создавать неприятности:

Код: Выделить всё

[olej@nvidia ~]$ uname -r
2.6.35.14-96.fc14.i686.PAE

[olej@nvidia ~]$ cat /proc/kallsyms | grep kallsyms_lookup_name | grep T
c0469a0e T module_kallsyms_lookup_name
c046a0ae T kallsyms_lookup_name
или вот:

Код: Выделить всё

[olej@notebook ~]$ uname -r
2.6.32.9-70.fc12.i686.PAE

[olej@notebook ~]$ cat /proc/kallsyms | grep kallsyms_lookup_name | grep T
c046e815 T module_kallsyms_lookup_name
c04717f2 T kallsyms_lookup_name

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 13 дек 2011, 00:51

Olej писал(а): Но он не настолько новый, чтоб это могло создавать неприятности:
Ага, ща-аз :roll:

Код: Выделить всё

[olej@notebook call_table]$ uname -r
2.6.32.9-70.fc12.i686.PAE
[olej@notebook call_table]$ make
...
WARNING: "kallsyms_lookup_name" [/home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/call_table/mod_kct.ko] undefined!
...
- ядро 2.6.32 - имя kallsyms_lookup_name не экспортируется.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 13 дек 2011, 00:58

Olej писал(а):- ядро 2.6.32 - имя kallsyms_lookup_name не экспортируется.
Но

Код: Выделить всё

[olej@nvidia call_table]$ uname -r
2.6.35.14-96.fc14.i686.PAE
[olej@nvidia call_table]$ make
...

[olej@nvidia call_table]$ sudo insmod mod_kct.ko
insmod: error inserting 'mod_kct.ko': -100500 Success

[olej@nvidia call_table]$ dmesg | tail -n2
[ 7438.397186] sys_call_table = c07c2438
[ 7438.397190] c044e80c c0443af8 c0408a04
- ядро 2.6.35 - всё и компилируется и работает ОК.
Показанное 3-мя строчками начало таблицы системных вызовов (численно адреса все отличаются от примера ранее - другое ядро!) проверяем обратным поиском: что оно с себя представляет:

Код: Выделить всё

[olej@nvidia call_table]$ cat /proc/kallsyms | grep c07c2438
c07c2438 R sys_call_table
[olej@nvidia call_table]$ cat /proc/kallsyms | grep c044e80c
c044e80c T sys_restart_syscall
[olej@nvidia call_table]$ cat /proc/kallsyms | grep c0443af8
c0443af8 T sys_exit
[olej@nvidia call_table]$ cat /proc/kallsyms | grep c0408a04
c0408a04 t ptregs_fork

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 13 дек 2011, 17:03

Olej писал(а): - ядро 2.6.35 - всё и компилируется и работает ОК.
Т.е. возможность эта появляется меж ядрами 2.6.32 и 2.6.35 (между Fedora 12 и Fedora 12, между летом 2010 и весной 2011) :lol:

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 17 дек 2011, 16:48

Olej писал(а):
Olej писал(а): - ядро 2.6.35 - всё и компилируется и работает ОК.
Т.е. возможность эта появляется меж ядрами 2.6.32 и 2.6.35 (между Fedora 12 и Fedora 12, между летом 2010 и весной 2011) :lol:
Как ту же возможность реализовать в более ранних ядрах?
А вот так ;-) :
- используя другой вызов kernel API:

Код: Выделить всё

[olej@notebook call_table]$ uname -r
2.6.32.9-70.fc12.i686.PAE
[olej@notebook ~]$ cat /proc/kallsyms | grep T | grep kallsyms_*
c046ca7c T module_kallsyms_on_each_symbol
c046e815 T module_kallsyms_lookup_name
c0471581 T kallsyms_lookup
c04716ec T kallsyms_lookup_size_offset
c0471764 T kallsyms_on_each_symbol
c04717f2 T kallsyms_lookup_name
[olej@notebook build]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep kallsyms_*
0x00000000	kallsyms_on_each_symbol	vmlinux	EXPORT_SYMBOL_GPL
Вот вот этот вызов и используем (обратите внимание! - какой там интересный EXPORT).
Вот код модуля:

Код: Выделить всё

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kallsyms.h>

static int nsym = 0;
static unsigned long taddr = 0;

int symb_fn( void* data, const char* sym, struct module* mod, unsigned long addr ) {
   nsym++;
   if( 0 == strcmp( (char*)data, sym ) ) {
      printk( "+ sys_call_table address = %lx\n", addr );
      taddr = addr;
      return 1;
   }
   return 0;
};

static int __init ksys_call_tbl_init( void ) {
   int n = kallsyms_on_each_symbol( symb_fn, (void*)"sys_call_table" );
   if( n != 0 ) {
      int i;
      char table[ 120 ] = "sys_call_table : ";
      printk( "+ find in position %d\n", nsym );
      for( i = 0; i < 10; i++ ) {
         unsigned long sa = *( (unsigned long*)taddr + i );
         sprintf( table + strlen( table ), "%p ", (void*)sa );
      }
      printk( "+ %s ...\n", table );
   }
   else printk( "+ symbol not found\n" );
   return -EPERM;
}

module_init( ksys_call_tbl_init );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" );
Вот результаты:

Код: Выделить всё

[olej@notebook call_table]$ time sudo insmod mod_koes.ko
insmod: error inserting 'mod_koes.ko': -1 Operation not permitted
real    0m0.042s
user    0m0.005s
sys     0m0.027s
[olej@notebook call_table]$ dmesg | tail -n30 | grep +
+ sys_call_table address = c07ab3d8
+ find in position 25239
+ sys_call_table : c044ec61 c0444f63 c040929c c04e149d c04e12fc c04dec35 c04dea99 c0444767 c
[olej@notebook call_table]$ cat /proc/kallsyms | wc -l
69423
[olej@notebook call_table]$ cat /proc/kallsyms | grep c04dec35
c04dec35 T sys_open
(обратите внимание: всего в таблице 69423 имён, но мы перебрали только 25239 - пока нашли!)

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Экспорт символов ядра и таблица системных вызовов

Непрочитанное сообщение Olej » 17 дек 2011, 16:54

Olej писал(а): Как ту же возможность реализовать в более ранних ядрах?
А вот так ;-) :
1. вообще то, этот вызов kallsyms_on_each_symbol - он, как мне кажется, гораздо более гибкий для какой-то более сложной работы, чем более поздний kallsyms_lookup_name, это просто какая-то lite версия :lol:

2. всё это подробно описано, вошло в новую редакцию (№111) проекта книги: "Модули ядра Linux" (смотрите в титуле: "редакция №....").

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя