Страница 1 из 2
Экспорт символов ядра и таблица системных вызовов
Добавлено: 12 дек 2011, 04:05
Olej
Это уже достаточно сложные вопросы из области ядра 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, если кого интересует, может смотреть там ... сюда же я собираюсь выбрасывать только относительно "чистый" материал, резюме
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 12 дек 2011, 12:43
Olej
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>" );
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 12 дек 2011, 12:48
Olej
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
...
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 12 дек 2011, 12:54
Olej
Я колебался, показывать ли это... поскольку, при желании, это прямой путь к написанию вирусов (в том числе, помимо созидательных приложений).
Потому как получив таблицу sys_call_table дальше подменять системные вызовы на свои обработчики - это уже проще простого.
Но, с другой стороны, придурки - они и сами придумают, а сама возможность и техника - интересные.
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 12 дек 2011, 20:50
Olej
Там же (в обсуждении -
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
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 13 дек 2011, 00:51
Olej
Olej писал(а):
Но он не настолько новый, чтоб это могло создавать неприятности:
Ага, ща-аз
Код: Выделить всё
[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 не экспортируется.
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 13 дек 2011, 00:58
Olej
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
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 13 дек 2011, 17:03
Olej
Olej писал(а):
- ядро 2.6.35 - всё и компилируется и работает ОК.
Т.е. возможность эта появляется меж ядрами 2.6.32 и 2.6.35 (между Fedora 12 и Fedora 12, между летом 2010 и весной 2011)
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 17 дек 2011, 16:48
Olej
Olej писал(а):Olej писал(а):
- ядро 2.6.35 - всё и компилируется и работает ОК.
Т.е. возможность эта появляется меж ядрами 2.6.32 и 2.6.35 (между Fedora 12 и Fedora 12, между летом 2010 и весной 2011)
Как ту же возможность реализовать в более ранних ядрах?
А вот так
:
- используя другой вызов 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 - пока нашли!)
Re: Экспорт символов ядра и таблица системных вызовов
Добавлено: 17 дек 2011, 16:54
Olej
Olej писал(а):
Как ту же возможность реализовать в более ранних ядрах?
А вот так
:
1. вообще то, этот вызов kallsyms_on_each_symbol - он, как мне кажется, гораздо более гибкий для какой-то более сложной работы, чем более поздний kallsyms_lookup_name, это просто какая-то lite версия
2. всё это подробно описано, вошло в новую редакцию (№111)
проекта книги: "Модули ядра Linux" (смотрите в титуле: "редакция №....").