private void CloseMutex(WS.SYSTEM_HANDLE_INFORMATION handle) { IntPtr targetHandle; // DUPLICATE_CLOSE_SOURCE = 0x1 // GetCurrentProcess(), out targetHandle ======> Set target process to null for success if (!DuplicateHandle(Process.GetProcessById(handle.ProcessID).Handle, handle.Handle, IntPtr.Zero, out targetHandle, 0, false, 0x1)) { MessageBox.Show("Failed to close mutex: " + Marshal.GetLastWin32Error(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } Console.WriteLine("Mutex was killed"); }
// Closes all needed mutant handles in given process private void CloseProcessHandles(Process growtopia) // We need to remove handlers from the last process { Console.WriteLine("Starting handle magic..."); statusMessage.Text = "Querying system handle information..."; int nLength = 0; IntPtr handlePointer = IntPtr.Zero; int sysInfoLength = 0x10000; // How much to allocate to returned data IntPtr infoPointer = Marshal.AllocHGlobal(sysInfoLength); // 0x10 = SystemHandleInformation, an undocumented SystemInformationClass uint result; // NtQuerySystemInformation won't give us the correct buffer size, so we guess it // Assign result of NtQuerySystemInformation to this variable and check if the buffer size is correct // If it's incorrect, it returns STATUS_INFO_LENGTH_MISMATCH (0xc0000004) while ((result = NtQuerySystemInformation(0x10, infoPointer, sysInfoLength, ref nLength)) == 0xc0000004) { sysInfoLength = nLength; Marshal.FreeHGlobal(infoPointer); infoPointer = Marshal.AllocHGlobal(nLength); } byte[] baTemp = new byte[nLength]; // Copy the data from unmanaged memory to managed 1-byte uint array Marshal.Copy(infoPointer, baTemp, 0, nLength); // Do we even need the two statements above??? Look into this later. long sysHandleCount = 0; // How many handles there are total if (Is64Bits()) { sysHandleCount = Marshal.ReadInt64(infoPointer); handlePointer = new IntPtr(infoPointer.ToInt64() + 8); // Points in bits at the start of a handle } else { sysHandleCount = Marshal.ReadInt32(infoPointer); handlePointer = new IntPtr(infoPointer.ToInt32() + 4); // Ignores 4 first bits instead of 8 } statusMessage.Text = "Query received, processing the " + sysHandleCount + " results."; WS.SYSTEM_HANDLE_INFORMATION handleInfoStruct; // The struct to hold info about a single handler List <WS.SYSTEM_HANDLE_INFORMATION> handles = new List <WS.SYSTEM_HANDLE_INFORMATION>(); for (long i = 0; i < sysHandleCount; i++) // Iterate over handle structs in the handle struct list { handleInfoStruct = new WS.SYSTEM_HANDLE_INFORMATION(); if (Is64Bits()) { handleInfoStruct = (WS.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(handlePointer, handleInfoStruct.GetType()); // Convert to struct handlePointer = new IntPtr(handlePointer.ToInt64() + Marshal.SizeOf(handleInfoStruct) + 8); // point 8 bits forward to the next handle } else { handleInfoStruct = (WS.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(handlePointer, handleInfoStruct.GetType()); handlePointer = new IntPtr(handlePointer.ToInt64() + Marshal.SizeOf(handleInfoStruct)); } if (handleInfoStruct.ProcessID != growtopia.Id) // Check if current handler is from Growtopia { continue; // If it's not from Growtopia, just skip it } string handleName = ViewHandleName(handleInfoStruct, growtopia); // TODO: Looks like the mutant session number is different for different PCs // Maybe just check if the string contains basenamedobjects/growtopia and starts with sessions? if (handleName != null && handleName.StartsWith(@"\Sessions\") && handleName.EndsWith(@"\BaseNamedObjects\Growtopia")) { handles.Add(handleInfoStruct); Console.WriteLine("PID {0,7} Pointer {1,12} Type {2,4} Name {3}", handleInfoStruct.ProcessID.ToString(), handleInfoStruct.Object_Pointer.ToString(), handleInfoStruct.ObjectTypeNumber.ToString(), handleName); } else { continue; // This is not a handle we're looking for } } Console.WriteLine("Closing mutexes?"); foreach (WS.SYSTEM_HANDLE_INFORMATION handle in handles) { CloseMutex(handle); } statusMessage.Text = "Query finished, " + sysHandleCount + " results processed."; Console.WriteLine("Handle closed."); }
private static string ViewHandleName(WS.SYSTEM_HANDLE_INFORMATION shHandle, Process process) { // handleInfoStruct is the struct that contains data about our handle // targetProcess is the process where the handle resides // DUP_HANDLE (0x40) might also work IntPtr sourceProcessHandle = OpenProcess(0x1F0FFF, false, process.Id); IntPtr targetHandle = IntPtr.Zero; // We create a duplicate of the handle so that we can query more information about it if (!DuplicateHandle(sourceProcessHandle, shHandle.Handle, GetCurrentProcess(), out targetHandle, 0, false, 0x2)) { return(null); } // Buffers that the query results get sent to IntPtr basicQueryData = IntPtr.Zero; // Query result structs WS.OBJECT_BASIC_INFORMATION basicInformationStruct = new WS.OBJECT_BASIC_INFORMATION(); WS.OBJECT_NAME_INFORMATION nameInformationStruct = new WS.OBJECT_NAME_INFORMATION(); basicQueryData = Marshal.AllocHGlobal(Marshal.SizeOf(basicInformationStruct)); int nameInfoLength = 0; // Size of information returned to us NtQueryObject(targetHandle, 0, basicQueryData, Marshal.SizeOf(basicInformationStruct), ref nameInfoLength); // Insert buffer data into a struct and free the buffer basicInformationStruct = (WS.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(basicQueryData, basicInformationStruct.GetType()); Marshal.FreeHGlobal(basicQueryData); // The basicInformationStruct contains data about the name's length // TODO: We could probably skip querying for OBJECT_BASIC_INFORMATION nameInfoLength = basicInformationStruct.NameInformationLength; // Allocate buffer for the name now that we know its size IntPtr nameQueryData = Marshal.AllocHGlobal(nameInfoLength); // Object information class: 1 // If it's incorrect, it returns STATUS_INFO_LENGTH_MISMATCH (0xc0000004) int result; while ((uint)(result = NtQueryObject(targetHandle, 1, nameQueryData, nameInfoLength, ref nameInfoLength)) == 0xc0000004) { Marshal.FreeHGlobal(nameQueryData); nameQueryData = Marshal.AllocHGlobal(nameInfoLength); } nameInformationStruct = (WS.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(nameQueryData, nameInformationStruct.GetType()); IntPtr handlerName; if (Is64Bits()) { handlerName = new IntPtr(Convert.ToInt64(nameInformationStruct.Name.Buffer.ToString(), 10) >> 32); } else { handlerName = nameInformationStruct.Name.Buffer; } if (handlerName != IntPtr.Zero) { byte[] baTemp2 = new byte[nameInfoLength]; try { Marshal.Copy(handlerName, baTemp2, 0, nameInfoLength); return(Marshal.PtrToStringUni(Is64Bits() ? new IntPtr(handlerName.ToInt64()) : new IntPtr(handlerName.ToInt32()))); } catch (AccessViolationException) { return(null); } finally { Marshal.FreeHGlobal(nameQueryData); CloseHandle(targetHandle); } } return(null); }