Olej писал(а):
Задача оказалась не так проста, как кажется ... там есть несколько приятных нюансов
Вот свеженький пример подмены всё того же системного вызова sys_wrte, который отвечает за wrte(2) и, в конечном итоге, за вывод на терминал printf(3):
Код: Выделить всё
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include "./find.c"
#include "./CR0.c"
#define ERR(...) printk( KERN_ERR "! "__VA_ARGS__ )
asmlinkage long (*old_sys_write) ( unsigned int fd, const char __user *buf, size_t count );
asmlinkage long new_sys_write ( unsigned int fd, const char __user *buf, size_t count ) {
if( 1 == fd ) {
static char msg[ 160 ];
int n = count < sizeof( msg ) ? count : sizeof( msg ) - 1,
r = copy_from_user( msg, (void*)buf, n );
if( '!' == msg[ 0 ] ) goto rec;
msg[ n ] = '\0';
if( '\n' == msg[ n - 1 ] ) msg[ n - 1 ] = '\0';
if( strchr( msg, '!' ) != NULL ) goto rec; // to prevent recursion
printk( "! {%04d} %s\n", count, msg );
}
rec:
return old_sys_write( fd, buf, count );
};
EXPORT_SYMBOL( new_sys_write );
static void **taddr; // address of sys_call_table
static int __init wrchg_init( void ) {
void *waddr;
if( NULL == ( taddr = find_sym( "sys_call_table" ) ) ) {
ERR( "sys_call_table not found\n" ); return -EINVAL;
}
old_sys_write = (void*)taddr[ __NR_write ];
if( NULL == ( waddr = find_sym( "sys_write" ) ) ) {
ERR( "sys_write not found\n" ); return -EINVAL;
}
if( old_sys_write != waddr ) {
ERR( "Oooops! : addresses not equal\n" ); return -EINVAL;
}
printk( "! set new sys_write syscall [%p]\n", &new_sys_write );
show_cr0();
rw_enable();
taddr[ __NR_write ] = new_sys_write;
show_cr0();
rw_disable();
show_cr0();
return 0;
}
static void __exit wrchg_exit( void ) {
rw_enable();
taddr[ __NR_write ] = old_sys_write;
rw_disable();
printk( "! restore old sys_write syscall [%p]\n", (void*)taddr[ __NR_write ] );
return;
}
module_init( wrchg_init );
module_exit( wrchg_exit );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" );
Теперь всё, что выводится на терминал, параллельно пишется printk() в журнал ядра.
Шпионит...
Самое удивительное здесь место, что нужно избежать бесконечной (почти
) рекурсии, поскольку printk() каким-то образом тоже использует write() ... что и стоило ожидать, но разбираться глубже я не стал.
Но интересно то, что это делалось как практический пример для проверки возможности (корректности) перехвата и подмены системных вызовов не только в реальной инсталляции на железе, но и в виртуальной машине в VirtualBox ... а также в облачной виртуальной машине созданной средствами такого инстумента как Cisco Maestro.
Так вот, я вас поздравляю
: в VirtualBox это всё происходит так же, как на реальном железе.
Это очень хорошая новость ... потому как подобные рисковые штучки можно тренировать в VirtualBox.
Вот это - VirtualBox:
Код: Выделить всё
olej@ubuntu:~/WORK_2015/FWall/drivers/wrlog$ dmesg | tail -n13
[ 6103.858156] ! set new sys_write syscall [e1a03030]
[ 6103.858775] ! CR0 = 8005003b
[ 6103.859252] ! CR0 = 8004003b
[ 6103.859345] ! CR0 = 8005003b
[ 6103.871976] ! {0041} /home/olej/WORK_2015/FWall/drivers/wrlog
[ 6103.875946] ! {0094} \x1b]0;olej@ubuntu: ~/WORK_2015/FWall/drivers/wrlog\x07olej@ubuntu:~/WORK_2015/FWall/drivers/wrlog$
[ 6104.523854] ! {0020} sudo insmod wrlog.ko
[ 6105.028481] ! {0027} \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08make\x1b[K
[ 6107.230753] ! {0021} \x08\x08\x08\x08dmesg | tail -n33
[ 6108.470280] ! {0004} \x08\x0813
[ 6109.211730] ! {0036} \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08sudo rmmod wrlog.ko
[ 6111.618226] ! {0002}
[ 6111.705243] ! restore old sys_write syscall [c1144d20]
Что за такие всякие удивительные штучки как \x08 ?
Я тоже на это в недоумении смотрел
... А это те "стрелка вверх" которыми я прокручивал на терминале предыдущие команды в поисках rmmod...
А вот это - реальное железо:
Код: Выделить всё
olej@nvidia ~ $ lsb_release -ircd
Distributor ID: LinuxMint
Description: Linux Mint 17.1 Rebecca
Release: 17.1
Codename: rebecca
Код: Выделить всё
olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ sudo insmod wrlog.ko
olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ sudo rmmod wrlog
olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ dmesg | tail -n25
[ 1220.476585] device eth0 entered promiscuous mode
[ 7850.815396] ! set new sys_write syscall [f8bff000]
[ 7850.815399] ! CR0 = 8005003b
[ 7850.815401] ! CR0 = 8004003b
[ 7850.815402] ! CR0 = 8005003b
[ 7850.817121] ! {0049} /home/olej/2015_WORK/in.WORK/FWall/drivers/wrlog
[ 7850.817483] ! {0075} \x1b[01;32molej@nvidia\x1b[01;34m ~/2015_WORK/in.WORK/FWall/drivers/wrlog $\x1b[00m
[ 7853.997031] ! {0001} s
[ 7854.301131] ! {0001} u
[ 7854.541040] ! {0001} d
[ 7854.901050] ! {0001} o
[ 7857.934642] ! {0001}
[ 7858.317047] ! {0001} r
[ 7859.061051] ! {0001} m
[ 7859.284676] ! {0001} m
[ 7860.268919] ! {0001} o
[ 7860.884974] ! {0001} d
[ 7862.149085] ! {0001}
[ 7863.748656] ! {0001} w
[ 7864.005039] ! {0001} r
[ 7865.141581] ! {0001} l
[ 7865.453121] ! {0001} o
[ 7865.925047] ! {0001} g
[ 7866.910978] ! {0002}
[ 7866.917365] ! restore old sys_write syscall [c1179f70]
А вот здесь команда rmmod набиралась на терминале посимвольно.
NB Ещё раз повторю: экспериментировать с таким кодом можно только если вы хорошо понимаете что делаете на каждом щагу. Разнести при похожих действиях свою операционную систему - элементарно. ... Но вы предупреждены, значит вооружены!