сабж. необходимо написать руткит для курсача.
на данный момент пытаюсь заставить работать код взятый из старых источников вроде "хакера". если конкретнее, то я хочу воспользоваться функцией скрытия каталогов. но на ядре 2.6.39, которое я взял для курсача, этот код не работает. в то же время, если верить копирайтам, исходник linux/fs/readdir.c не менялся с 2005 года. так что мне кажется странным то, что "патч" которому уже лет 5, не работает с исходниками которым лет 15. довольно отвлечённых разговоров, вопросы:
1 для того что бы скрыть все каталоги с именем abcde нужно перехватить системный вызов. самым лучшим вызовом для перехвата является getdents64 или можно сделать проще?
2 если я хочу написать свою реализацию getdents64 и снабдить её "фильтром", то где мне найти описание оригинального getdents'а?
3 можно ли сделать некий враппер для getdents64? я много пытался, но ничего не вышло. наверное из-за того что если это вообще можно, то есть какая-то специальная методика?
4 есть ли литература которая затрагивала бы программирование ядра в целом и работу с файловой подсистемой ядра linux в частности? ну или про руткиты. на нашем, буржуйском, испанском или французском языках.
ещё на всякий случай напишу, что:
я знаю, что ядро развивается очень динамично и что копирайты могут врать.
с ядром я работаю впервые.
Перехват сискола читающего содержимое директории в ядре linux
4 есть ли литература которая затрагивала бы программирование ядра в целом и работу с файловой подсистемой ядра linux в частности? ну или про руткиты. на нашем, буржуйском, испанском или французском языках.
лучше всего ИМХО:
"Linux Device Drivers" - переводится в нескольких местах, до конца ещё ни кто не перевёл.
Бовет Чезатти "Ядро linux" - есть на русском.
ещё говорят в "Linux kernel Internals" что-то неплохо описано...(не читал)
я знаю, что ядро развивается очень динамично и что копирайты могут врать.
изменения всегда можно посмотреть в гите на kernel.org
2 если я хочу написать свою реализацию getdents64 и снабдить её "фильтром", то где мне найти описание оригинального getdents'а?
grep -r getdents64 .
среди прочего выдаст fs/readdir.c
на данный момент пытаюсь заставить работать код взятый из старых источников вроде "хакера". если конкретнее, то я хочу воспользоваться функцией скрытия каталогов.
ссылку в студию. его здесь ни кто в глаза не видел...
1 для того что бы скрыть все каталоги с именем abcde нужно перехватить системный вызов. самым лучшим вызовом для перехвата является getdents64 или можно сделать проще?
в 2.6 перехват сисколов считается злом и sys_call_table не экспортируется... при большом желании можно нагуглить способы изменить её, но всё это грязные вещи... как всё это сделать без внедрения своего кода в ядро - не скажу...
ptrace может перехватить системный вызов, прочитать данные на входе и выходе, а так же модифицировать их.
ДОБАВЛЕНО: Где-то на wikipedia видел ссылку на исследовательскую работу, я её сохранил, однако эту статью на википедии не могу найти (зато нашлась статья Эякуляция на лицо :O)
[quote=atropos]4 есть ли литература которая затрагивала бы программирование ядра в целом и работу с файловой подсистемой ядра linux в частности? ну или про руткиты. на нашем, буржуйском, испанском или французском языках.
лучше всего ИМХО:
"Linux Device Drivers" - переводится в нескольких местах, до конца ещё ни кто не перевёл.
[/quote]
Неправда wink
Полный перевод от 2010-го года:
http://dmilvdv.narod.ru/Translate/LDD3/index.html?linux_device_drivers.html
(но только online)
в 2.6 перехват сисколов считается злом и sys_call_table не экспортируется... при большом желании можно нагуглить способы изменить её, но всё это грязные вещи... как всё это сделать без внедрения своего кода в ядро - не скажу...
Да, легальных способов перехвата нет.
А всё (!!!) трюкачество относительно ядер 2.6.Х которое я встречал - это хакерское бахвальство, которое переставало работать к следующей подверсии ядра.
Даже примеры 2010 года не работают на сегодня :P
4 есть ли литература которая затрагивала бы программирование ядра в целом и работу с файловой подсистемой ядра linux в частности? ну или про руткиты. на нашем, буржуйском, испанском или французском языках.
Посмотрите:
http://rus-linux.net/forum/viewtopic.php?f=3&t=1549
Может чем пригодится?
... и "на вашем" wink
код взятый из старых источников вроде "хакера"
мне кажется странным то, что "патч" которому уже лет 5, не работает с исходниками которым лет 15.
вы уверены, что что этот патч вообще работал когда-то?
1 для того что бы скрыть все каталоги с именем abcde нужно перехватить системный вызов.
простите, я не понял. Почему вы не хотите этот вызов попросту переделать? Встроить туда свой фильтр например? Что мешает? Места нету? Ну сломайте что-нить ненужное на целевой системе (которую вы ломаете).
А всё (!!!) трюкачество относительно ядер 2.6.Х которое я встречал - это хакерское бахвальство, которое переставало работать к следующей подверсии ядра.
естественно. А оно нужно? У нас задача - сломать целевую систему. Задачи написать вирус никто не ставил wink
Посмотрите:
сколько можно этот свой руслинукс и к месту и не к месту пиарить?
[quote=Olej]Посмотрите:
сколько можно этот свой руслинукс и к месту и не к месту пиарить?[/quote]
Потому, что это ответ на прямой вопрос.
К вам это не относится, так что можете не тревожиться по пустякам wink
В разборку вопроса писал, писал тест-модуль ... и написал wink
Про то, что в 2.6.х ядре из числа экспортируемых имён убрали таблицу системных вызовов sys_call_table - это только ленивый не знает...
Так вот модулёк, который "достаёт" sys_call_table, а затем и точку входа любого обработчика sys_*(). Так что дальше подменить его (для мониторинга, например) уже совсем проще простого.
Вот модуль:
#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>" );
А вот его результат (если без debug параметра запускать):
[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
...
Вот вам и "не экспортируется"!
месье знает толк в извращениях =)
всё куда проще:
#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" );
всё куда проще:
Fat-Zer, это здорово, если это работает wink , посмотрю...
Но мне кажется, что вы противоречите сами себе:
[quote=atropos]
1 для того что бы скрыть все каталоги с именем abcde нужно перехватить системный вызов. самым лучшим вызовом для перехвата является getdents64 или можно сделать проще?
в 2.6 перехват сисколов считается злом и sys_call_table не экспортируется... при большом желании можно нагуглить способы изменить её, но всё это грязные вещи... как всё это сделать без внедрения своего кода в ядро - не скажу...
[/quote]
Какие тогда это "грязные вещи", если вы использовали для этого легальный kernel API.
Да, я встречал описания, разные способы получения таблицы sys_call_table ... но все они изощрённые + перестают работать от версии к версии ядра. Но если это вызов API, то какой тогда смысл не экспортировать sys_call_table?
Но мне кажется, что вы противоречите сами себе:
заблуждался: получить адрес - реально, а вот использовать его - не хорошо... можно купить топор, но вот зарубить им на соседа всё равно не хорошо...
какой тогда смысл не экспортировать sys_call_table?
чтобы его не использовали, ибо тогда у обычных разработчиков появляется соблазн сотворить всякую фигню(типа подмены системных вызовов).
ЗЫ: не знаю, в какой версии появилась эта функция. в .2.6.39 - она есть
[quote=Olej]Но мне кажется, что вы противоречите сами себе:
заблуждался: получить адрес - реально, а вот использовать его - не хорошо... можно купить топор, но вот зарубить им на соседа всё равно не хорошо...
[/quote]
Всё равно как-то непоследовательно... убрать из экспорта, но сохранить доступ?
[quote=Olej]какой тогда смысл не экспортировать sys_call_table?
чтобы его не использовали, ибо тогда у обычных разработчиков появляется соблазн сотворить всякую фигню(типа подмены системных вызовов).
[/quote]
Совершенно не обязательно фигню, такой техникой делалось (и делается!) множество вещей в самых разных ОС, начиная с MS-DOS и ещё раньше: и мониторинг разный, и статистики, и отладочные цели...
А от использования "в фигню" здесь страхует, в гораздо большей степени, чем устранение из экспорта, необходимость для всех этих дел прав root.
ЗЫ: не знаю, в какой версии появилась эта функция. в .2.6.39 - она есть
[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
что делает 1-й из вызовов? символы из модулей?
kallsyms_lookup_name проверяет только символьные таблицы ядра. если ничего не нашёл, то он вызывает module_kallsyms_lookup_name, который проверяет модули. Последний не экспортируется.
[quote=Fat-Zer]ЗЫ: не знаю, в какой версии появилась эта функция. в .2.6.39 - она есть
[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
[/quote]
Но
[olej@notebook call_table]$ uname -r
2.6.32.9-70.fc12.i686.PAE
[olej@notebook call_table]$ make
make -C /lib/modules/2.6.32.9-70.fc12.i686.PAE/build M=/home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/call_table modules
...
WARNING: "kallsyms_lookup_name" [/home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/call_table/mod_kct.ko] undefined!
...
нуда... значит он не экспортируется.... из того, что у меня под рукой было:
alexander@goblin /tmp $ tar -xjf /usr/portage/distfiles/linux-2.6.32.tar.bz2
alexander@goblin /tmp $ cd linux-2.6.32/
alexander@goblin /tmp/linux-2.6.32 $ grep kallsyms_lookup_name kernel/kallsyms.c
unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name);
alexander@goblin /tmp/linux-2.6.32 $ grep kallsyms_lookup_name /usr/src/linux-2.6.39-gentoo-r3/kernel/kallsyms.c
unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name);
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
alexander@goblin /tmp/linux-2.6.32 $ grep kallsyms_lookup_name /usr/src/linux-3.0./kernel/kallsyms.c
linux-3.0.4/ linux-3.0.6-gentoo/
alexander@goblin /tmp/linux-2.6.32 $ grep kallsyms_lookup_name /usr/src/linux-3.0.6-gentoo/kernel/kallsyms.c
unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name);
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
alexander@goblin /tmp/linux-2.6.32 $ grep kallsyms_lookup_name /usr/src/linux-3.0.4/kernel/kallsyms.c
unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name);
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
alexander@goblin /tmp/linux-2.6.32 $ cd ..
alexander@goblin /tmp $ tar -xjf /usr/portage/distfiles/linux-2.6.36.tar.bz2
alexander@goblin /tmp $ grep kallsyms_lookup_name linux-2.6.36/kernel/kallsyms.c
unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name);
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
alexander@goblin /tmp $
можно обойти все символы через kallsyms_on_each_symbol.
всё разумней, чем читать файл из proc wink
нуда... значит он не экспортируется....
А вот
[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
[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
Всё ОК.
Так и запишем : wink ... начинает экспортироваться где-то между 2.6.32 и. 2.6.35
можно обойти все символы через kallsyms_on_each_symbol.
всё разумней, чем читать файл из proc wink
Посмотрю.
можно обойти все символы через kallsyms_on_each_symbol.
всё разумней, чем читать файл из proc wink
Мне в чтении /proc/kallsyms самым интересным было проверить как будет происходить последовательное чтение очень большого файла, без lseek().
Всё сложилось.