proper linting & google formatting

This commit is contained in:
17ms 2024-01-06 13:53:18 +02:00
parent 2aa60ccc61
commit ef9b173c6e
10 changed files with 643 additions and 719 deletions

View File

@ -1,9 +1,12 @@
#include "generator.hpp" #include "generator.hpp"
#include <string>
#include <vector>
#include "../shared/crypto.hpp" #include "../shared/crypto.hpp"
#include "../shared/futils.hpp" #include "../shared/futils.hpp"
int main(int argc, char **argv) int main(int argc, char **argv) {
{
uint8_t flag = false; uint8_t flag = false;
std::string loaderPath, payloadPath, funcName, funcParameter, outputPath; std::string loaderPath, payloadPath, funcName, funcParameter, outputPath;
@ -20,10 +23,8 @@ int main(int argc, char **argv)
auto optionIndex = 0; auto optionIndex = 0;
int c; int c;
while ((c = getopt_long(argc, argv, "l:p:n:a:o:fh", longOptions, &optionIndex))) while ((c = getopt_long(argc, argv, "l:p:n:a:o:fh", longOptions, &optionIndex))) {
{ switch (c) {
switch (c)
{
case 'l': case 'l':
loaderPath = optarg; loaderPath = optarg;
break; break;
@ -51,8 +52,7 @@ int main(int argc, char **argv)
} }
} }
if (loaderPath.empty() || payloadPath.empty() || funcName.empty() || funcParameter.empty(), outputPath.empty()) if (loaderPath.empty() || payloadPath.empty() || funcName.empty() || funcParameter.empty(), outputPath.empty()) {
{
std::cout << "[!] Missing required arguments" << std::endl; std::cout << "[!] Missing required arguments" << std::endl;
PrintHelp(argv); PrintHelp(argv);
return 1; return 1;
@ -155,16 +155,14 @@ int main(int argc, char **argv)
bootstrap.push_back(0xc0); bootstrap.push_back(0xc0);
auto funcParameterOffset = (BOOTSTRAP_LEN - 5) + loaderContents.size() + payloadContents.size(); 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++) {
{
bootstrap.push_back(static_cast<BYTE>(funcParameterOffset >> (i * 8) & 0xff)); bootstrap.push_back(static_cast<BYTE>(funcParameterOffset >> (i * 8) & 0xff));
} }
// mov edx, <funcParameterHash> -> Copy the 2nd parameter, the hash of the function parameter, into edx // mov edx, <funcParameterHash> -> Copy the 2nd parameter, the hash of the function parameter, into edx
bootstrap.push_back(0xba); bootstrap.push_back(0xba);
for (size_t i = 0; i < sizeof(funcParameterHash); i++) for (size_t i = 0; i < sizeof(funcParameterHash); i++) {
{
bootstrap.push_back(static_cast<BYTE>(funcParameterHash >> (i * 8) & 0xff)); bootstrap.push_back(static_cast<BYTE>(funcParameterHash >> (i * 8) & 0xff));
} }
@ -174,8 +172,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0xc1); bootstrap.push_back(0xc1);
auto payloadOffset = (BOOTSTRAP_LEN - 5) + loaderContents.size(); 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++) {
{
bootstrap.push_back(static_cast<BYTE>(payloadOffset >> (i * 8) & 0xff)); bootstrap.push_back(static_cast<BYTE>(payloadOffset >> (i * 8) & 0xff));
} }
@ -187,8 +184,7 @@ int main(int argc, char **argv)
bootstrap.push_back(0xe8); bootstrap.push_back(0xe8);
auto reflectiveLoaderAddress = (BOOTSTRAP_LEN - 5) + loaderContents.size(); 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++) {
{
bootstrap.push_back(static_cast<BYTE>(reflectiveLoaderAddress >> (i * 8) & 0xff)); bootstrap.push_back(static_cast<BYTE>(reflectiveLoaderAddress >> (i * 8) & 0xff));
} }
@ -215,8 +211,7 @@ 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() != BOOTSTRAP_LEN) if (bootstrap.size() != BOOTSTRAP_LEN) {
{
std::cout << "[!] Bootstrap size mismatch: " << bootstrap.size() << " != " << BOOTSTRAP_LEN << std::endl; std::cout << "[!] Bootstrap size mismatch: " << bootstrap.size() << " != " << BOOTSTRAP_LEN << std::endl;
return 1; return 1;
} }
@ -239,7 +234,7 @@ int main(int argc, char **argv)
// XOR with a random content length key // XOR with a random content length key
std::cout << "[+] XOR'ing the shellcode..." << std::endl; std::cout << "[+] XOR'ing the shellcode..." << std::endl;
auto key = GenerateKey(bootstrap.size()); auto key = GenerateKey(bootstrap.size());
XorCipher(bootstrap, key); XorCipher(&bootstrap, key);
std::cout << "[+] Total XOR'd shellcode size: " << bootstrap.size() << std::endl; std::cout << "[+] Total XOR'd shellcode size: " << bootstrap.size() << std::endl;
@ -253,8 +248,7 @@ int main(int argc, char **argv)
return 0; return 0;
} }
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;
std::cout << "\nArguments:" << std::endl; std::cout << "\nArguments:" << std::endl;
std::cout << "\t-l, --loader Path to loader file" << std::endl; std::cout << "\t-l, --loader Path to loader file" << std::endl;

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <windows.h>
#include <getopt.h> #include <getopt.h>
#include <windows.h>
#include <iostream> #include <iostream>
constexpr auto BOOTSTRAP_LEN = 79; constexpr auto BOOTSTRAP_LEN = 79;

View File

@ -1,14 +1,14 @@
#include <windows.h> #include <windows.h>
#include <iostream> #include <iostream>
#include "../shared/futils.hpp"
#include "../shared/crypto.hpp" #include "../shared/crypto.hpp"
#include "../shared/futils.hpp"
#define VERBOSE 1 #define VERBOSE 1
int main(int argc, char **argv) int main(int argc, char **argv) {
{ if (argc != 3) {
if (argc != 3)
{
std::cout << "[?] Usage: " << argv[0] << " <shellcode-path> <xor-keyfile-path>" << std::endl; std::cout << "[?] Usage: " << argv[0] << " <shellcode-path> <xor-keyfile-path>" << std::endl;
return 1; return 1;
} }
@ -29,12 +29,11 @@ int main(int argc, char **argv)
std::cout << "[+] XOR'ing shellcode" << std::endl; std::cout << "[+] XOR'ing shellcode" << std::endl;
#endif #endif
XorCipher(shellcodeContents, key); XorCipher(&shellcodeContents, key);
auto baseAddress = VirtualAlloc(nullptr, shellcodeContents.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); auto baseAddress = VirtualAlloc(nullptr, shellcodeContents.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!baseAddress) if (!baseAddress) {
{
std::cout << "[!] Failed to allocate memory" << std::endl; std::cout << "[!] Failed to allocate memory" << std::endl;
return 1; return 1;
} }

View File

@ -8,18 +8,15 @@
#define DLL_EXPORT __declspec(dllimport) #define DLL_EXPORT __declspec(dllimport)
#endif #endif
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
{ if (dwReason == DLL_PROCESS_ATTACH) {
if (dwReason == DLL_PROCESS_ATTACH)
{
CreateProcessW(L"C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL); CreateProcessW(L"C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL);
} }
return TRUE; return TRUE;
} }
BOOL PrintMessage(LPVOID lpUserData, DWORD dwUserDataSize) BOOL PrintMessage(LPVOID lpUserData, DWORD dwUserDataSize) {
{
auto lpText = static_cast<LPCWSTR>(lpUserData); auto lpText = static_cast<LPCWSTR>(lpUserData);
MessageBoxW(NULL, lpText, L"Hello World!", MB_OK); MessageBoxW(NULL, lpText, L"Hello World!", MB_OK);

View File

@ -1,16 +1,19 @@
#include "loader.hpp" #include "loader.hpp"
#include <tuple>
#include <utility>
#include <vector>
#include "../shared/crypto.hpp" #include "../shared/crypto.hpp"
void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserDataLen, DWORD dwFlags) void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserDataLen, DWORD dwFlags) {
{
/* /*
1.) Locate the required functions and modules from exports with their hashed names 1.) Locate the required functions and modules from exports with their hashed names
*/ */
auto pbKernel32Dll = GetModuleAddressFromHash(KERNEL32_DLL_HASH); auto pbKernel32Dll = GetModuleAddressFromHash(KERNEL32_DLL_HASH);
if (pbKernel32Dll == nullptr) if (pbKernel32Dll == nullptr) {
{
return; return;
} }
@ -24,8 +27,7 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
auto pVirtualProtect = reinterpret_cast<VIRTUAL_PROTECT>(GetExportAddrFromHash(pbKernel32Dll, VIRTUAL_PROTECT_HASH, eng)); auto pVirtualProtect = reinterpret_cast<VIRTUAL_PROTECT>(GetExportAddrFromHash(pbKernel32Dll, VIRTUAL_PROTECT_HASH, eng));
auto pSleep = reinterpret_cast<SLEEP>(GetExportAddrFromHash(pbKernel32Dll, SLEEP_HASH, eng)); auto pSleep = reinterpret_cast<SLEEP>(GetExportAddrFromHash(pbKernel32Dll, SLEEP_HASH, eng));
if (pLoadLibraryW == nullptr || pGetProcAddress == nullptr || pVirtualAlloc == nullptr || pFlushInstructionCache == nullptr || pVirtualProtect == nullptr || pSleep == nullptr) if (pLoadLibraryW == nullptr || pGetProcAddress == nullptr || pVirtualAlloc == nullptr || pFlushInstructionCache == nullptr || pVirtualProtect == nullptr || pSleep == nullptr) {
{
return; return;
} }
@ -36,20 +38,13 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
auto pNtHeaders = GetNtHeaders(pImage); auto pNtHeaders = GetNtHeaders(pImage);
if (pNtHeaders == nullptr) if (pNtHeaders == nullptr) {
{
return; return;
} } else if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
else if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return; return;
} } else if (pNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
else if (pNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
{
return; return;
} } else if (pNtHeaders->OptionalHeader.SectionAlignment & 1) {
else if (pNtHeaders->OptionalHeader.SectionAlignment & 1)
{
return; return;
} }
@ -59,13 +54,11 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
// Try to allocate the image to the preferred base address // Try to allocate the image to the preferred base address
auto pNewImageBase = reinterpret_cast<ULONG_PTR>(pVirtualAlloc(reinterpret_cast<LPVOID>(ullPreferredImageBase), dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); auto pNewImageBase = reinterpret_cast<ULONG_PTR>(pVirtualAlloc(reinterpret_cast<LPVOID>(ullPreferredImageBase), dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (!pNewImageBase) if (!pNewImageBase) {
{
// Try to allocate the image to any available base address // Try to allocate the image to any available base address
pNewImageBase = reinterpret_cast<ULONG_PTR>(pVirtualAlloc(nullptr, dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); pNewImageBase = reinterpret_cast<ULONG_PTR>(pVirtualAlloc(nullptr, dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (!pNewImageBase) if (!pNewImageBase) {
{
return; return;
} }
} }
@ -79,8 +72,7 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
auto ulpDelta = pNewImageBase - pNtHeaders->OptionalHeader.ImageBase; auto ulpDelta = pNewImageBase - pNtHeaders->OptionalHeader.ImageBase;
auto pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; auto pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (!ProcessRelocations(pNewImageBase, pDataDir, ulpDelta)) if (!ProcessRelocations(pNewImageBase, pDataDir, ulpDelta)) {
{
return; return;
} }
@ -88,8 +80,7 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
4.) Resolve the imports by patching the Import Address Table (IAT) 4.) Resolve the imports by patching the Import Address Table (IAT)
*/ */
if (!PatchImportAddressTable(pNewImageBase, pDataDir, pLoadLibraryW, pGetProcAddress, pSleep, eng)) if (!PatchImportAddressTable(pNewImageBase, pDataDir, pLoadLibraryW, pGetProcAddress, pSleep, eng)) {
{
return; return;
} }
@ -103,15 +94,12 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
6.) Execute DllMain or user defined function depending on the flag passed into the shellcode by the generator 6.) Execute DllMain or user defined function depending on the flag passed into the shellcode by the generator
*/ */
if (dwFlags == 0) if (dwFlags == 0) {
{
// Execute DllMain with DLL_PROCESS_ATTACH // Execute DllMain with DLL_PROCESS_ATTACH
auto pDllMain = reinterpret_cast<DLL_MAIN>(pNewImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint); auto pDllMain = reinterpret_cast<DLL_MAIN>(pNewImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
// Optionally user data could also be passed to the DllMain instead of a separate function // Optionally user data could also be passed to the DllMain instead of a separate function
pDllMain(reinterpret_cast<HMODULE>(pNewImageBase), DLL_PROCESS_ATTACH, nullptr); pDllMain(reinterpret_cast<HMODULE>(pNewImageBase), DLL_PROCESS_ATTACH, nullptr);
} } else {
else
{
// Execute user defined function // Execute user defined function
auto pbNewImageBase = reinterpret_cast<PBYTE>(pNewImageBase); auto pbNewImageBase = reinterpret_cast<PBYTE>(pNewImageBase);
auto pUserFunction = reinterpret_cast<USER_FUNCTION>(GetExportAddrFromHash(pbNewImageBase, dwFunctionHash, eng)); auto pUserFunction = reinterpret_cast<USER_FUNCTION>(GetExportAddrFromHash(pbNewImageBase, dwFunctionHash, eng));
@ -119,15 +107,13 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData
} }
} }
void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache) void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache) {
{
auto pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); auto pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
DWORD dwOldProtect, dwNewProtect; DWORD dwOldProtect, dwNewProtect;
LPVOID lpAddress; LPVOID lpAddress;
for (auto i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) for (auto i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) {
{
dwNewProtect = 0; dwNewProtect = 0;
// Definitions for readability // Definitions for readability
@ -135,43 +121,35 @@ void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders
DWORD dwIsReadable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_READ) != 0; DWORD dwIsReadable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_READ) != 0;
DWORD dwIsWritable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; DWORD dwIsWritable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
if (!dwIsExecutable && !dwIsReadable && !dwIsWritable) if (!dwIsExecutable && !dwIsReadable && !dwIsWritable) {
{
dwNewProtect = PAGE_NOACCESS; dwNewProtect = PAGE_NOACCESS;
} }
if (dwIsWritable) if (dwIsWritable) {
{
dwNewProtect = PAGE_WRITECOPY; dwNewProtect = PAGE_WRITECOPY;
} }
if (dwIsReadable) if (dwIsReadable) {
{
dwNewProtect = PAGE_READONLY; dwNewProtect = PAGE_READONLY;
} }
if (dwIsWritable && dwIsReadable) if (dwIsWritable && dwIsReadable) {
{
dwNewProtect = PAGE_READWRITE; dwNewProtect = PAGE_READWRITE;
} }
if (dwIsExecutable) if (dwIsExecutable) {
{
dwNewProtect = PAGE_EXECUTE; dwNewProtect = PAGE_EXECUTE;
} }
if (dwIsExecutable && dwIsWritable) if (dwIsExecutable && dwIsWritable) {
{
dwNewProtect = PAGE_EXECUTE_WRITECOPY; dwNewProtect = PAGE_EXECUTE_WRITECOPY;
} }
if (dwIsExecutable && dwIsReadable) if (dwIsExecutable && dwIsReadable) {
{
dwNewProtect = PAGE_EXECUTE_READ; dwNewProtect = PAGE_EXECUTE_READ;
} }
if (dwIsExecutable && dwIsWritable && dwIsReadable) if (dwIsExecutable && dwIsWritable && dwIsReadable) {
{
dwNewProtect = PAGE_EXECUTE_READWRITE; dwNewProtect = PAGE_EXECUTE_READWRITE;
} }
@ -182,12 +160,10 @@ void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders
pFlushInstructionCache(INVALID_HANDLE_VALUE, nullptr, 0); pFlushInstructionCache(INVALID_HANDLE_VALUE, nullptr, 0);
} }
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, const std::mt19937 &eng) {
{
auto pImportDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(pNewImageBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); auto pImportDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(pNewImageBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (pImportDescriptor == nullptr) if (pImportDescriptor == nullptr) {
{
return FALSE; return FALSE;
} }
@ -201,8 +177,7 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
int importCount = 0; int importCount = 0;
auto pId = pImportDescriptor; auto pId = pImportDescriptor;
while (pId->Name) while (pId->Name) {
{
importCount++; importCount++;
pId++; pId++;
} }
@ -210,10 +185,8 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
std::vector<std::pair<int, DWORD>> sleepDurations; std::vector<std::pair<int, DWORD>> sleepDurations;
std::uniform_int_distribution<> sleepDist(1000, MAX_IMPORT_DELAY_MS); std::uniform_int_distribution<> sleepDist(1000, MAX_IMPORT_DELAY_MS);
if (importCount > 1 && OBFUSCATE_IMPORTS) if (importCount > 1 && OBFUSCATE_IMPORTS) {
{ for (auto i = 0; i < importCount - 1; i++) {
for (auto i = 0; i < importCount - 1; i++)
{
std::uniform_int_distribution<> distr(i, importCount - 1); std::uniform_int_distribution<> distr(i, importCount - 1);
int j = distr(eng); int j = distr(eng);
@ -232,16 +205,12 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
HMODULE hModule; HMODULE hModule;
PIMAGE_THUNK_DATA64 pThunkData, pThunkDataIat; PIMAGE_THUNK_DATA64 pThunkData, pThunkDataIat;
for (auto i = 0; pImportDescriptor->Name; pImportDescriptor++, i++) for (auto i = 0; pImportDescriptor->Name; pImportDescriptor++, i++) {
{
// Apply delay // Apply delay
if (OBFUSCATE_IMPORTS) if (OBFUSCATE_IMPORTS) {
{ auto it = std::find_if(sleepDurations.begin(), sleepDurations.end(), [i](const std::pair<int, DWORD> &pair) { return pair.first == i; });
auto it = std::find_if(sleepDurations.begin(), sleepDurations.end(), [i](const std::pair<int, DWORD> &pair)
{ return pair.first == i; });
if (it != sleepDurations.end()) if (it != sleepDurations.end()) {
{
pSleep(it->second); pSleep(it->second);
} }
} }
@ -249,8 +218,7 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
pwszModuleName = reinterpret_cast<LPCWSTR>(pNewImageBase + pImportDescriptor->Name); pwszModuleName = reinterpret_cast<LPCWSTR>(pNewImageBase + pImportDescriptor->Name);
hModule = pLoadLibraryW(pwszModuleName); hModule = pLoadLibraryW(pwszModuleName);
if (hModule == nullptr) if (hModule == nullptr) {
{
return FALSE; return FALSE;
} }
@ -260,15 +228,11 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
LPCSTR lpProcName; LPCSTR lpProcName;
PIMAGE_IMPORT_BY_NAME pImportByName; PIMAGE_IMPORT_BY_NAME pImportByName;
for (auto j = 0; pThunkData->u1.Function; pThunkData++, pThunkDataIat++, j++) for (auto j = 0; pThunkData->u1.Function; pThunkData++, pThunkDataIat++, j++) {
{ if (pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG64) {
if (pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
{
// High bits masked out to get the ordinal number // High bits masked out to get the ordinal number
lpProcName = reinterpret_cast<LPCSTR>(pThunkData->u1.Ordinal & 0xFFFF); lpProcName = reinterpret_cast<LPCSTR>(pThunkData->u1.Ordinal & 0xFFFF);
} } else {
else
{
// The address of the imported function is stored in the IMAGE_IMPORT_BY_NAME structure // The address of the imported function is stored in the IMAGE_IMPORT_BY_NAME structure
pImportByName = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(pNewImageBase + pThunkData->u1.AddressOfData); pImportByName = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(pNewImageBase + pThunkData->u1.AddressOfData);
lpProcName = pImportByName->Name; lpProcName = pImportByName->Name;
@ -281,12 +245,10 @@ BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDat
return TRUE; return TRUE;
} }
BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta) BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta) {
{
auto pRelocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(pNewImageBase + pDataDirectory->VirtualAddress); auto pRelocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(pNewImageBase + pDataDirectory->VirtualAddress);
if (pRelocation == nullptr || pDataDirectory->Size == 0) if (pRelocation == nullptr || pDataDirectory->Size == 0) {
{
return FALSE; return FALSE;
} }
@ -294,17 +256,14 @@ BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDire
auto dwRelocationEnd = pDataDirectory->VirtualAddress + pDataDirectory->Size; auto dwRelocationEnd = pDataDirectory->VirtualAddress + pDataDirectory->Size;
PIMAGE_RELOC pRelocationList; PIMAGE_RELOC pRelocationList;
while (pRelocation->VirtualAddress && pRelocation->VirtualAddress <= dwRelocationEnd && pRelocation->SizeOfBlock) while (pRelocation->VirtualAddress && pRelocation->VirtualAddress <= dwRelocationEnd && pRelocation->SizeOfBlock) {
{
pRelocationList = reinterpret_cast<PIMAGE_RELOC>(pRelocation + 1); pRelocationList = reinterpret_cast<PIMAGE_RELOC>(pRelocation + 1);
while (reinterpret_cast<PBYTE>(pRelocationList) < reinterpret_cast<PBYTE>(pRelocation) + pRelocation->SizeOfBlock) while (reinterpret_cast<PBYTE>(pRelocationList) < reinterpret_cast<PBYTE>(pRelocation) + pRelocation->SizeOfBlock) {
{
auto pPatchAddress = reinterpret_cast<PBYTE>(pNewImageBase + pRelocation->VirtualAddress + pRelocationList->offset); auto pPatchAddress = reinterpret_cast<PBYTE>(pNewImageBase + pRelocation->VirtualAddress + pRelocationList->offset);
// Note -- Types adjusted from PULONG_PTR to PDWORD and PWORD // Note -- Types adjusted from PULONG_PTR to PDWORD and PWORD
switch (pRelocationList->type) switch (pRelocationList->type) {
{
case IMAGE_REL_BASED_DIR64: case IMAGE_REL_BASED_DIR64:
*reinterpret_cast<PULONG_PTR>(pPatchAddress) += ulpDelta; *reinterpret_cast<PULONG_PTR>(pPatchAddress) += ulpDelta;
break; break;
@ -330,8 +289,7 @@ BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDire
return TRUE; return TRUE;
} }
void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders) void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HEADERS64 pNtHeaders) {
{
// Copy headers // Copy headers
auto pbDst = reinterpret_cast<PBYTE>(pNewImageBase); auto pbDst = reinterpret_cast<PBYTE>(pNewImageBase);
std::copy(pbImage, pbImage + pNtHeaders->OptionalHeader.SizeOfHeaders, pbDst); std::copy(pbImage, pbImage + pNtHeaders->OptionalHeader.SizeOfHeaders, pbDst);
@ -342,15 +300,13 @@ void CopyHeadersAndSections(ULONG_PTR pNewImageBase, PBYTE pbImage, PIMAGE_NT_HE
PBYTE pbSrc; PBYTE pbSrc;
for (auto i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) for (auto i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) {
{
pbSrc = reinterpret_cast<PBYTE>(pbImage + pSectionHeader->PointerToRawData); pbSrc = reinterpret_cast<PBYTE>(pbImage + pSectionHeader->PointerToRawData);
std::copy(pbSrc, pbSrc + pSectionHeader->SizeOfRawData, pbDst); std::copy(pbSrc, pbSrc + pSectionHeader->SizeOfRawData, pbDst);
} }
} }
PBYTE GetModuleAddressFromHash(DWORD dwHash) PBYTE GetModuleAddressFromHash(DWORD dwHash) {
{
// https://en.wikipedia.org/wiki/Win32_Thread_Information_Block // https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
#if defined(_WIN64) #if defined(_WIN64)
// PEB is at GS:[0x60] // PEB is at GS:[0x60]
@ -363,10 +319,8 @@ PBYTE GetModuleAddressFromHash(DWORD dwHash)
auto pLdr = reinterpret_cast<PMY_PEB_LDR_DATA>(pPEB->Ldr); auto pLdr = reinterpret_cast<PMY_PEB_LDR_DATA>(pPEB->Ldr);
auto pEntry = reinterpret_cast<PMY_LDR_DATA_TABLE_ENTRY>(pLdr->InLoadOrderModuleList.Flink); auto pEntry = reinterpret_cast<PMY_LDR_DATA_TABLE_ENTRY>(pLdr->InLoadOrderModuleList.Flink);
while (pEntry->DllBase != NULL) while (pEntry->DllBase != NULL) {
{ if (CalculateHash(pEntry->BaseDllName) == dwHash && pEntry->DllBase != nullptr) {
if (CalculateHash(pEntry->BaseDllName) == dwHash && pEntry->DllBase != nullptr)
{
return reinterpret_cast<PBYTE>(pEntry->DllBase); return reinterpret_cast<PBYTE>(pEntry->DllBase);
} }
@ -376,12 +330,10 @@ PBYTE GetModuleAddressFromHash(DWORD dwHash)
return nullptr; return nullptr;
} }
HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng) HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, const std::mt19937 &eng) {
{
auto pNtHeaders = GetNtHeaders(pbModule); auto pNtHeaders = GetNtHeaders(pbModule);
if (pNtHeaders == nullptr) if (pNtHeaders == nullptr) {
{
return nullptr; return nullptr;
} }
@ -397,8 +349,7 @@ HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng)
DWORD dwNameRva; DWORD dwNameRva;
std::vector<std::tuple<DWORD, size_t>> vNameRvas; std::vector<std::tuple<DWORD, size_t>> vNameRvas;
for (DWORD i = 0; i < pExport->NumberOfNames; i++) for (DWORD i = 0; i < pExport->NumberOfNames; i++) {
{
dwNameRva = (reinterpret_cast<DWORD *>(pbModule + pExport->AddressOfNames))[i]; dwNameRva = (reinterpret_cast<DWORD *>(pbModule + pExport->AddressOfNames))[i];
vNameRvas.push_back(std::make_tuple(dwNameRva, i)); vNameRvas.push_back(std::make_tuple(dwNameRva, i));
} }
@ -409,13 +360,11 @@ HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng)
UNICODE_STRING *strFunctionNameBase; UNICODE_STRING *strFunctionNameBase;
WORD wOrdinal; WORD wOrdinal;
for (auto dwNRva : vNameRvas) for (auto dwNRva : vNameRvas) {
{
strFunctionNameBase = reinterpret_cast<UNICODE_STRING *>(pbModule + std::get<0>(dwNRva)); strFunctionNameBase = reinterpret_cast<UNICODE_STRING *>(pbModule + std::get<0>(dwNRva));
dwNameHash = CalculateHash(*strFunctionNameBase); dwNameHash = CalculateHash(*strFunctionNameBase);
if (dwNameHash == dwHash) if (dwNameHash == dwHash) {
{
wOrdinal = (reinterpret_cast<WORD *>(pbModule + pExport->AddressOfNameOrdinals))[std::get<1>(dwNRva)]; wOrdinal = (reinterpret_cast<WORD *>(pbModule + pExport->AddressOfNameOrdinals))[std::get<1>(dwNRva)];
dwFunctionRva = (reinterpret_cast<DWORD *>(pbModule + pExport->AddressOfFunctions))[wOrdinal]; dwFunctionRva = (reinterpret_cast<DWORD *>(pbModule + pExport->AddressOfFunctions))[wOrdinal];
@ -426,19 +375,16 @@ HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng)
return nullptr; return nullptr;
} }
PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage) PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage) {
{
auto pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(pbImage); auto pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(pbImage);
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
{
return nullptr; return nullptr;
} }
auto pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS64>(pbImage + pDosHeader->e_lfanew); auto pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS64>(pbImage + pDosHeader->e_lfanew);
if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
{
return nullptr; return nullptr;
} }

View File

@ -2,6 +2,7 @@
#include <windows.h> #include <windows.h>
#include <winternl.h> #include <winternl.h>
#include <algorithm> #include <algorithm>
#include <random> #include <random>
@ -29,8 +30,7 @@ using DLL_MAIN = BOOL(WINAPI *)(HMODULE, DWORD, LPVOID);
using USER_FUNCTION = BOOL(WINAPI *)(LPVOID, DWORD); using USER_FUNCTION = BOOL(WINAPI *)(LPVOID, DWORD);
// Complete WinAPI PEB structs // Complete WinAPI PEB structs
struct _MY_PEB_LDR_DATA struct _MY_PEB_LDR_DATA {
{
ULONG Length; ULONG Length;
BOOL Initialized; BOOL Initialized;
PVOID SsHandle; PVOID SsHandle;
@ -41,8 +41,7 @@ struct _MY_PEB_LDR_DATA
using MY_PEB_LDR_DATA = _MY_PEB_LDR_DATA; using MY_PEB_LDR_DATA = _MY_PEB_LDR_DATA;
using PMY_PEB_LDR_DATA = _MY_PEB_LDR_DATA *; using PMY_PEB_LDR_DATA = _MY_PEB_LDR_DATA *;
struct _MY_LDR_DATA_TABLE_ENTRY struct _MY_LDR_DATA_TABLE_ENTRY {
{
LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks; LIST_ENTRY InInitializationOrderLinks;
@ -55,8 +54,7 @@ struct _MY_LDR_DATA_TABLE_ENTRY
using MY_LDR_DATA_TABLE_ENTRY = _MY_LDR_DATA_TABLE_ENTRY; using MY_LDR_DATA_TABLE_ENTRY = _MY_LDR_DATA_TABLE_ENTRY;
using PMY_LDR_DATA_TABLE_ENTRY = _MY_LDR_DATA_TABLE_ENTRY *; using PMY_LDR_DATA_TABLE_ENTRY = _MY_LDR_DATA_TABLE_ENTRY *;
struct _IMAGE_RELOC struct _IMAGE_RELOC {
{
WORD offset : 12; WORD offset : 12;
WORD type : 4; WORD type : 4;
}; };
@ -64,10 +62,10 @@ using IMAGE_RELOC = _IMAGE_RELOC;
using PIMAGE_RELOC = _IMAGE_RELOC *; using PIMAGE_RELOC = _IMAGE_RELOC *;
PBYTE GetModuleAddressFromHash(DWORD dwHash); PBYTE GetModuleAddressFromHash(DWORD dwHash);
HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, std::mt19937 &eng); HMODULE GetExportAddrFromHash(PBYTE pbModule, DWORD dwHash, const std::mt19937 &eng);
PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage); PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pbImage);
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, const std::mt19937 &eng);
void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache); void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache);

View File

@ -1,41 +1,33 @@
#include "crypto.hpp" #include "crypto.hpp"
std::vector<BYTE> GenerateKey(size_t keysize) std::vector<BYTE> GenerateKey(size_t keysize) {
{
std::vector<BYTE> key(keysize, 0); std::vector<BYTE> key(keysize, 0);
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 255); std::uniform_int_distribution<> dis(0, 255);
for (size_t i = 0; i < key.size(); ++i) for (size_t i = 0; i < key.size(); ++i) {
{
key[i] = static_cast<BYTE>(dis(gen)); key[i] = static_cast<BYTE>(dis(gen));
} }
return key; return key;
} }
void XorCipher(std::vector<BYTE> &data, const std::vector<BYTE> &key) void XorCipher(std::vector<BYTE> *data, const std::vector<BYTE> &key) {
{ for (size_t i = 0; i < data->size(); i++) {
for (size_t i = 0; i < data.size(); i++) (*data)[i] = (*data)[i] ^ key[i % key.size()];
{
data[i] = data[i] ^ key[i % key.size()];
} }
} }
DWORD CalculateHash(const std::string &source) DWORD CalculateHash(const std::string &source) {
{
auto dwHash = HASH_KEY; auto dwHash = HASH_KEY;
for (char ch : source) for (char ch : source) {
{ if (ch == '\0') {
if (ch == '\0')
{
continue; continue;
} }
if (ch >= 'a' && ch <= 'z') if (ch >= 'a' && ch <= 'z') {
{
ch -= 0x20; ch -= 0x20;
} }
@ -46,24 +38,20 @@ DWORD CalculateHash(const std::string &source)
return dwHash; return dwHash;
} }
DWORD CalculateHash(const UNICODE_STRING &baseDllName) DWORD CalculateHash(const UNICODE_STRING &baseDllName) {
{
auto pwszBaseDllName = baseDllName.Buffer; auto pwszBaseDllName = baseDllName.Buffer;
auto dwHash = HASH_KEY; auto dwHash = HASH_KEY;
char ch; char ch;
for (auto i = 0; i < baseDllName.MaximumLength; i++) for (auto i = 0; i < baseDllName.MaximumLength; i++) {
{
ch = pwszBaseDllName[i]; ch = pwszBaseDllName[i];
if (ch == '\0') if (ch == '\0') {
{
continue; continue;
} }
if (ch >= 'a' && ch <= 'z') if (ch >= 'a' && ch <= 'z') {
{
ch -= 0x20; ch -= 0x20;
} }

View File

@ -2,12 +2,14 @@
#include <windows.h> #include <windows.h>
#include <winternl.h> #include <winternl.h>
#include <string>
#include <random> #include <random>
#include <string>
#include <vector>
constexpr auto HASH_KEY = 5381; constexpr auto HASH_KEY = 5381;
std::vector<BYTE> GenerateKey(size_t keysize); std::vector<BYTE> GenerateKey(size_t keysize);
void XorCipher(std::vector<BYTE> &data, const std::vector<BYTE> &key); 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);

View File

@ -1,7 +1,6 @@
#include "futils.hpp" #include "futils.hpp"
std::vector<BYTE> ReadFromFile(const std::string &filename) std::vector<BYTE> ReadFromFile(const std::string &filename) {
{
std::ifstream file(filename, std::ios::binary); std::ifstream file(filename, std::ios::binary);
std::vector<BYTE> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); std::vector<BYTE> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close(); file.close();
@ -9,8 +8,7 @@ std::vector<BYTE> ReadFromFile(const std::string &filename)
return data; return data;
} }
void WriteToFile(const std::string &filename, const std::vector<BYTE> &data) void WriteToFile(const std::string &filename, const std::vector<BYTE> &data) {
{
std::ofstream file(filename, std::ios::binary); std::ofstream file(filename, std::ios::binary);
file.write(reinterpret_cast<const char *>(data.data()), data.size()); file.write(reinterpret_cast<const char *>(data.data()), data.size());
file.close(); file.close();

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fstream>
std::vector<BYTE> ReadFromFile(const std::string &filename); std::vector<BYTE> ReadFromFile(const std::string &filename);
void WriteToFile(const std::string &filename, const std::vector<BYTE> &data); void WriteToFile(const std::string &filename, const std::vector<BYTE> &data);