hang on NtQuerySystemInformation in WinXPx32 but works fine in Win7x64
Asked Answered
A

1

1

I have a class that will let me close process handles in a given process. I have the fundamentals down, and it works flawlessly in Win7 x64, but when I run it in WinXP x86, it hangs and I can't understand why. I feel like I am missing something fairly obvious, here.

    public static List<handleFinder.SYSTEM_HANDLE_INFORMATION>
    GetHandles(Process process = null, string IN_strObjectTypeName = null, string IN_strObjectName = null)
    {
        int nLength = 0;
        int nHandleInfoSize = 0x10000;
        IntPtr ipHandle = IntPtr.Zero;
        IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
        uint nStatus;

        while ((nStatus = handleFinder.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer,nHandleInfoSize, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH)
        {
            nHandleInfoSize = nLength;
            Marshal.FreeHGlobal(ipHandlePointer);
            ipHandlePointer = Marshal.AllocHGlobal(nLength);
        }

        byte[] baTemp = new byte[nLength];
        Marshal.Copy(ipHandlePointer, baTemp, 0, nLength);

        long lHandleCount = 0;
        if (Is64Bits())
        {
            lHandleCount = Marshal.ReadInt64(ipHandlePointer);
            ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
        }
        else
        {
            lHandleCount = Marshal.ReadInt32(ipHandlePointer);
            ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
        }

        handleFinder.SYSTEM_HANDLE_INFORMATION shHandle;
        List<handleFinder.SYSTEM_HANDLE_INFORMATION> lstHandles = new List<handleFinder.SYSTEM_HANDLE_INFORMATION>();

        for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
        {
            shHandle = new handleFinder.SYSTEM_HANDLE_INFORMATION();
            if (Is64Bits())
            {
                shHandle = (handleFinder.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
                ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8);
            }
            else
            {
                ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle));
                shHandle = (handleFinder.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
            }
            if (process != null)
            {
                if (shHandle.ProcessID != process.Id) continue;
            }

            string strObjectTypeName = "";
            if (IN_strObjectTypeName != null)
            {
                strObjectTypeName = getObjectTypeName(shHandle, Process.GetProcessById(shHandle.ProcessID));
                if (strObjectTypeName != IN_strObjectTypeName) continue;
            }

            string strObjectName = "";
            if (IN_strObjectName != null)
            {
                strObjectName = getObjectName(shHandle, Process.GetProcessById(shHandle.ProcessID));
                if (strObjectName != IN_strObjectName) continue;
            }
            lstHandles.Add(shHandle);

            string strObjectTypeName2 = getObjectTypeName(shHandle, Process.GetProcessById(shHandle.ProcessID));
            string strObjectName2 = getObjectName(shHandle, Process.GetProcessById(shHandle.ProcessID));
            Console.WriteLine("{0}   {1}   {2}", shHandle.ProcessID, strObjectTypeName2, strObjectName2);

        }
        return lstHandles;
    }

    public static bool Is64Bits()
    {
        return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false;
    }
}

public class HandleKiller
{
    public static void doMurderHandle()
    {
        String ProcessName = "xboxstat";

        try
        {
            Process process = Process.GetProcessesByName(ProcessName)[0];
            var handles = Win32Processes.GetHandles(process, "File");
            if (handles.Count == 0) throw new System.ArgumentException("No handles found");
            foreach (var handle in handles)
            {
                IntPtr ipHandle = IntPtr.Zero;
                if (!handleFinder.DuplicateHandle(Process.GetProcessById(handle.ProcessID).Handle, handle.Handle, handleFinder.GetCurrentProcess(), out ipHandle, 0, false, handleFinder.DUPLICATE_CLOSE_SOURCE))
                    Console.WriteLine("DuplicateHandle() failed, error = {0}", Marshal.GetLastWin32Error());

                Console.WriteLine("Handle Killed!");
            }
        }
        catch (IndexOutOfRangeException)
        {
            Console.WriteLine("The process name '{0}' is not currently running", ProcessName);
        }
        catch (ArgumentException)
        {
            Console.WriteLine("The Handle '{0}' was not found in the process '{1}'", "", ProcessName);
        }
        Console.ReadLine();
    }
}
}
Aviate answered 21/4, 2013 at 4:22 Comment(5)
Are you sure it's NtQuerySystemInformation that's hanging, and not something else like NtQueryObject?Ornamented
Is all of that code necessary to produce the hang? Can you cut it down to just the essentials?Hispanic
Thanks for the tip about removing the extra code, I am having a hard time figuring out whether it is the NtQueryObject or the NtQuerySystemInformation. When I step through it after a breakpoint, the loops go fine in WinXP, but if I try to step through it too quickly I get an error "Can not perform action because process is running."Aviate
@user2303420: The one thing I know is that if you try to call NtQueryObject to e.g. get the name of the "wrong" object (typically, certain named pipes in the system), the entire system can hang. There is no way to avoid this deadlock (and only this deadlock) without using kernel-mode code. I've never heard of NtQuerySystemInformation hanging though. See this for more info: forum.sysinternals.com/…Ornamented
I have looked at that thread because that was my first thought... but because it pulls back everything just fine in Win7, I am inclined to lean towards something else as the root cause. NtQueryObject is just fine there. I will try to continue debugging.Aviate
E
4

To avoid the deadlock when encountering a synchronous named pipe with a pending wait operation, call CreateFileMapping() on the duplicated handle.

If GetLastError() returns 193 (ERROR_BAD_EXE_FORMAT) then the handle is not a file handle and you should skip the query for the filename.

Unlike every other type of call to test for a named pipe, CreateFileMapping() doesn't deadlock in the kernel.

ERROR_BAD_EXE_FORMAT -- ZwCreateSection probably returns STATUS_INVALID_FILE_FOR_SECTION which maps to that user error code.

see http://msdn.microsoft.com/en-us/library/windows/hardware/ff566428(v=vs.85).aspx also http://support.microsoft.com/kb/113996

Expansive answered 5/9, 2013 at 21:16 Comment(2)
Old post, but I was having the same issue with registry keys and your answer helped me to fix it. I used RegNotifyChangeKeyValue with a dummy eventIloilo
The Microsoft Support link is dead. Here is an alternative link: betaarchive.com/wiki/index.php/Microsoft_KB_Archive/113996Pigeontoed

© 2022 - 2024 — McMap. All rights reserved.