From a58033df45777dfef31e2b4242004be038163789 Mon Sep 17 00:00:00 2001 From: wj32 Date: Thu, 25 Jun 2009 08:54:11 +0000 Subject: [PATCH] NPH file object name hack! git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1465 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/CHANGELOG.txt | 1 + trunk/NProcessHacker/NProcessHacker.vcproj | 8 + .../NProcessHacker/Release/NProcessHacker.dll | Bin 16384 -> 17920 bytes trunk/NProcessHacker/nativedefs.h | 25 +++ trunk/NProcessHacker/nph.c | 7 + trunk/NProcessHacker/nph.h | 1 + trunk/NProcessHacker/obj.c | 151 ++++++++++++++++++ trunk/NProcessHacker/obj.h | 45 ++++++ trunk/ProcessHacker.Native/Api/Extensions.cs | 122 +++++++++----- .../NProcessHacker.cs | 34 ++-- .../ProcessHacker.Native.csproj | 1 + .../Components/ProcessTree/ProcessNode.cs | 1 + trunk/ProcessHacker/ProcessHacker.csproj | 1 - 13 files changed, 341 insertions(+), 56 deletions(-) create mode 100644 trunk/NProcessHacker/obj.c create mode 100644 trunk/NProcessHacker/obj.h rename trunk/{ProcessHacker/Program => ProcessHacker.Native}/NProcessHacker.cs (67%) diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 491af158a..5465225fb 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -12,6 +12,7 @@ Process Hacker * Terminator test: TP1a (TP1, alternative method) * Terminator test: TT1a (TT1, alternative method) * Thread wait analysis now detects NtQueryObject hangs + * Better file object names without KProcessHacker * Small performance improvements * FIXED: * Broken system thread start addresses due to sign-extending diff --git a/trunk/NProcessHacker/NProcessHacker.vcproj b/trunk/NProcessHacker/NProcessHacker.vcproj index 53ba1dc9d..c46ce8d8f 100644 --- a/trunk/NProcessHacker/NProcessHacker.vcproj +++ b/trunk/NProcessHacker/NProcessHacker.vcproj @@ -184,6 +184,10 @@ RelativePath=".\nph.c" > + + @@ -218,6 +222,10 @@ RelativePath=".\nph.h" > + + diff --git a/trunk/NProcessHacker/Release/NProcessHacker.dll b/trunk/NProcessHacker/Release/NProcessHacker.dll index 9317cd04c1ddfc51b3ea16dedf4fd4785f794d98..a3b590f0f0fafa02169411e1f402d5c469e175dd 100644 GIT binary patch delta 5635 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 F{|7B}nbH6N diff --git a/trunk/NProcessHacker/nativedefs.h b/trunk/NProcessHacker/nativedefs.h index e5a8eee10..af754046d 100644 --- a/trunk/NProcessHacker/nativedefs.h +++ b/trunk/NProcessHacker/nativedefs.h @@ -3,6 +3,15 @@ #include "nph.h" +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, + ObjectAllInformation, + ObjectDataInformation +} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; + typedef struct _UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; typedef struct _CLIENT_ID @@ -38,6 +47,11 @@ typedef struct _UNICODE_STRING PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + #define NTDEVICEIOCONTROLFILE_ARGS \ HANDLE FileHandle, \ HANDLE Event, \ @@ -101,6 +115,17 @@ typedef NTSTATUS (NTAPI *_NtOpenThread)( NTOPENTHREAD_ARGS ); +#define NTQUERYOBJECT_ARGS \ + HANDLE Handle, \ + OBJECT_INFORMATION_CLASS ObjectInformationClass, \ + PVOID ObjectInformation, \ + ULONG Length, \ + PULONG ReturnLength + +typedef NTSTATUS (NTAPI *_NtQueryObject)( + NTQUERYOBJECT_ARGS + ); + #define NTREADVIRTUALMEMORY_ARGS \ HANDLE ProcessHandle, \ PVOID BaseAddress, \ diff --git a/trunk/NProcessHacker/nph.c b/trunk/NProcessHacker/nph.c index 220d55008..0d376d8b0 100644 --- a/trunk/NProcessHacker/nph.c +++ b/trunk/NProcessHacker/nph.c @@ -54,6 +54,11 @@ PVOID PhGetProcAddress(PWSTR LibraryName, PSTR ProcName) return GetProcAddress(GetModuleHandle(LibraryName), ProcName); } +VOID PhVoid() +{ + return; +} + BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, @@ -65,6 +70,8 @@ BOOL WINAPI DllMain( case DLL_PROCESS_ATTACH: if (!NT_SUCCESS(PhvInit())) return FALSE; + if (!NT_SUCCESS(PhObjInit())) + return FALSE; if (!NT_SUCCESS(KphInit())) return FALSE; diff --git a/trunk/NProcessHacker/nph.h b/trunk/NProcessHacker/nph.h index 0126f580b..c28aab5ac 100644 --- a/trunk/NProcessHacker/nph.h +++ b/trunk/NProcessHacker/nph.h @@ -63,5 +63,6 @@ NPHAPI PVOID PhAlloc(SIZE_T Size); NPHAPI PVOID PhRealloc(PVOID Memory, SIZE_T Size); NPHAPI VOID PhFree(PVOID Memory); PVOID PhGetProcAddress(PWSTR LibraryName, PSTR ProcName); +NPHAPI VOID PhVoid(); #endif diff --git a/trunk/NProcessHacker/obj.c b/trunk/NProcessHacker/obj.c new file mode 100644 index 000000000..7914ba46f --- /dev/null +++ b/trunk/NProcessHacker/obj.c @@ -0,0 +1,151 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "obj.h" + +ULONG PhpQueryFileObjectThreadStart( + PVOID Parameter + ); + +_NtQueryObject NtQueryObject = NULL; + +HANDLE QueryFileObjectThreadHandle = NULL; +PVOID QueryFileObjectFiber = NULL; +CRITICAL_SECTION QueryFileObjectCs; +HANDLE QueryFileObjectStartEvent = NULL; +HANDLE QueryFileObjectCompletedEvent = NULL; +HANDLE QueryFileObjectFileHandle; +PH_QUERY_FILE_OBJECT_BUFFER QueryFileObjectBuffer; + +NTSTATUS PhObjInit() +{ + if (!(NtQueryObject = (_NtQueryObject) + PhGetProcAddress(L"ntdll.dll", "NtQueryObject"))) + return STATUS_PROCEDURE_NOT_FOUND; + + InitializeCriticalSection(&QueryFileObjectCs); + + return STATUS_SUCCESS; +} + +NTSTATUS PhQueryNameFileObject( + HANDLE FileHandle, + POBJECT_NAME_INFORMATION FileObjectNameInformation, + ULONG FileObjectNameInformationLength, + PULONG ReturnLength + ) +{ + ULONG waitResult; + + EnterCriticalSection(&QueryFileObjectCs); + + /* Create a query thread if we don't have one. */ + if (!QueryFileObjectThreadHandle) + { + ULONG threadId; + + QueryFileObjectThreadHandle = CreateThread( + NULL, 0, (LPTHREAD_START_ROUTINE)PhpQueryFileObjectThreadStart, NULL, 0, NULL); + + if (!QueryFileObjectThreadHandle) + { + LeaveCriticalSection(&QueryFileObjectCs); + return STATUS_UNSUCCESSFUL; + } + } + + /* Create the events if they don't exist. */ + if (!QueryFileObjectStartEvent) + if (!(QueryFileObjectStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) + return STATUS_UNSUCCESSFUL; + if (!QueryFileObjectCompletedEvent) + if (!(QueryFileObjectCompletedEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) + return STATUS_UNSUCCESSFUL; + + /* Initialize the work context. */ + QueryFileObjectFileHandle = FileHandle; + QueryFileObjectBuffer.Length = FileObjectNameInformationLength; + QueryFileObjectBuffer.Name = FileObjectNameInformation; + /* Allow the worker thread to start. */ + SetEvent(QueryFileObjectStartEvent); + /* Wait for the work to complete, with a timeout of 1 second. */ + waitResult = WaitForSingleObject(QueryFileObjectCompletedEvent, 1000); + + /* Return normally if the work was completed. */ + if (waitResult == WAIT_OBJECT_0) + { + NTSTATUS status; + ULONG returnLength; + + /* Copy the status information before we leave the critical section. */ + status = QueryFileObjectBuffer.Status; + returnLength = QueryFileObjectBuffer.ReturnLength; + LeaveCriticalSection(&QueryFileObjectCs); + + if (ReturnLength) + *ReturnLength = returnLength; + + return status; + } + /* Kill the worker thread if it took too long. */ + else if (waitResult == WAIT_TIMEOUT) + { + /* Kill the thread. */ + if (TerminateThread(QueryFileObjectThreadHandle, 1)) + { + QueryFileObjectThreadHandle = NULL; + + /* Delete the fiber (and free the thread stack). */ + DeleteFiber(QueryFileObjectFiber); + QueryFileObjectFiber = NULL; + } + + LeaveCriticalSection(&QueryFileObjectCs); + return STATUS_UNSUCCESSFUL; + } +} + +ULONG PhpQueryFileObjectThreadStart( + PVOID Parameter + ) +{ + QueryFileObjectFiber = ConvertThreadToFiber(Parameter); + + while (TRUE) + { + /* Wait for work. */ + if (WaitForSingleObject(QueryFileObjectStartEvent, INFINITE) != WAIT_OBJECT_0) + continue; + + QueryFileObjectBuffer.Status = NtQueryObject( + QueryFileObjectFileHandle, + ObjectNameInformation, + QueryFileObjectBuffer.Name, + QueryFileObjectBuffer.Length, + &QueryFileObjectBuffer.ReturnLength + ); + + /* Work done. */ + SetEvent(QueryFileObjectCompletedEvent); + } + + return 0; +} diff --git a/trunk/NProcessHacker/obj.h b/trunk/NProcessHacker/obj.h new file mode 100644 index 000000000..49a26c473 --- /dev/null +++ b/trunk/NProcessHacker/obj.h @@ -0,0 +1,45 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _OBJ_H +#define _OBJ_H + +#include "nph.h" +#include "nativedefs.h" + +typedef struct _PH_QUERY_FILE_OBJECT_BUFFER +{ + NTSTATUS Status; + ULONG Length; + ULONG ReturnLength; + POBJECT_NAME_INFORMATION Name; +} PH_QUERY_FILE_OBJECT_BUFFER, *PPH_QUERY_FILE_OBJECT_BUFFER; + +NTSTATUS PhObjInit(); + +NPHAPI NTSTATUS PhQueryNameFileObject( + HANDLE FileHandle, + POBJECT_NAME_INFORMATION FileObjectNameInformation, + ULONG FileObjectNameInformationLength, + PULONG ReturnLength + ); + +#endif diff --git a/trunk/ProcessHacker.Native/Api/Extensions.cs b/trunk/ProcessHacker.Native/Api/Extensions.cs index c6e7aea9d..c2dd19390 100644 --- a/trunk/ProcessHacker.Native/Api/Extensions.cs +++ b/trunk/ProcessHacker.Native/Api/Extensions.cs @@ -61,6 +61,52 @@ namespace ProcessHacker.Native.Api } } + private static string GetObjectNameNt(ProcessHandle process, IntPtr handle, GenericHandle dupHandle) + { + int retLength; + int baseAddress = 0; + + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, + IntPtr.Zero, 0, out retLength, out baseAddress); + } + else + { + Win32.NtQueryObject(dupHandle, ObjectInformationClass.ObjectNameInformation, + IntPtr.Zero, 0, out retLength); + } + + if (retLength > 0) + { + using (MemoryAlloc oniMem = new MemoryAlloc(retLength)) + { + if (KProcessHacker.Instance != null) + { + if (KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, + oniMem, oniMem.Size, out retLength, out baseAddress) >= NtStatus.Error) + throw new Exception("ZwQueryObject failed."); + } + else + { + if (Win32.NtQueryObject(dupHandle, ObjectInformationClass.ObjectNameInformation, + oniMem, oniMem.Size, out retLength) >= NtStatus.Error) + throw new Exception("NtQueryObject failed."); + } + + var oni = oniMem.ReadStruct(); + var str = oni.Name; + + if (KProcessHacker.Instance != null) + str.Buffer = str.Buffer.Increment(-baseAddress + oniMem); + + return str.Read(); + } + } + + throw new Exception("NtQueryObject failed."); + } + public static ObjectInformation GetHandleInfo(this SystemHandleInformation thisHandle) { using (ProcessHandle process = new ProcessHandle(thisHandle.ProcessId, @@ -147,77 +193,65 @@ namespace ProcessHacker.Native.Api } } - if (KProcessHacker.Instance != null && info.TypeName == "File") + // Get the object's name. If the object is a file we must take special + // precautions so that we don't hang. + if (info.TypeName == "File") { - // use KProcessHacker for files - info.OrigName = KProcessHacker.Instance.GetFileObjectName(thisHandle); - } - else if (info.TypeName == "File" && (int)thisHandle.GrantedAccess == 0x0012019f) - { - // KProcessHacker not available, fall back to using hack (i.e. not querying the name at all) - } - else - { - int baseAddress = 0; - if (KProcessHacker.Instance != null) { - KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, - IntPtr.Zero, 0, out retLength, out baseAddress); + // Use KProcessHacker for files to avoid hangs. + info.OrigName = KProcessHacker.Instance.GetFileObjectName(thisHandle); } else { - Win32.NtQueryObject(objectHandle, ObjectInformationClass.ObjectNameInformation, - IntPtr.Zero, 0, out retLength); - } - - if (retLength > 0) - { - using (MemoryAlloc oniMem = new MemoryAlloc(retLength)) + try { - if (KProcessHacker.Instance != null) + // Use NProcessHacker. + using (MemoryAlloc oniMem = new MemoryAlloc(0x4000)) { - if (KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, - oniMem, oniMem.Size, out retLength, out baseAddress) >= NtStatus.Error) - throw new Exception("ZwQueryObject failed."); + if (NProcessHacker.PhQueryNameFileObject( + objectHandle, oniMem, oniMem.Size, out retLength) >= NtStatus.Error) + throw new Exception("PhQueryNameFileObject failed."); + + var oni = oniMem.ReadStruct(); + + info.OrigName = oni.Name.Read(); } - else - { - if (Win32.NtQueryObject(objectHandle, ObjectInformationClass.ObjectNameInformation, - oniMem, oniMem.Size, out retLength) >= NtStatus.Error) - throw new Exception("NtQueryObject failed."); - } - - var oni = oniMem.ReadStruct(); - var str = oni.Name; - - if (KProcessHacker.Instance != null) - str.Buffer = str.Buffer.Increment(-baseAddress + oniMem); - - info.OrigName = str.Read(); + } + catch (DllNotFoundException) + { + // KProcessHacker and NProcessHacker not available. Fall back to using hack + // (i.e. not querying the name at all if the access is 0x0012019f) + if ((int)thisHandle.GrantedAccess != 0x0012019f) + info.OrigName = GetObjectNameNt(process, handle, objectHandle); } } } + else + { + // Not a file. Query the object normally. + info.OrigName = GetObjectNameNt(process, handle, objectHandle); + } - // get a better name for the handle + // Get a better name for the handle. try { switch (info.TypeName) { case "File": - // resolves \Device\Harddisk1 into C:, for example + // Resolves \Device\Harddisk1 into C:, for example. info.BestName = FileUtils.DeviceFileNameToDos(info.OrigName); break; case "Key": - string hklmString = "\\registry\\machine"; - string hkcrString = "\\registry\\machine\\software\\classes"; + const string hklmString = "\\registry\\machine"; + const string hkcrString = "\\registry\\machine\\software\\classes"; string hkcuString = "\\registry\\user\\" + System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString().ToLower(); string hkcucrString = "\\registry\\user\\" + System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString().ToLower() + "_classes"; - string hkuString = "\\registry\\user"; + const string hkuString = "\\registry\\user"; if (info.OrigName.ToLower().StartsWith(hkcrString)) info.BestName = "HKCR" + info.OrigName.Substring(hkcrString.Length); diff --git a/trunk/ProcessHacker/Program/NProcessHacker.cs b/trunk/ProcessHacker.Native/NProcessHacker.cs similarity index 67% rename from trunk/ProcessHacker/Program/NProcessHacker.cs rename to trunk/ProcessHacker.Native/NProcessHacker.cs index 0c8f85e6d..144663b7d 100644 --- a/trunk/ProcessHacker/Program/NProcessHacker.cs +++ b/trunk/ProcessHacker.Native/NProcessHacker.cs @@ -24,8 +24,9 @@ using System.Runtime.InteropServices; using System.Windows.Forms; using ProcessHacker.Native; using ProcessHacker.Native.Api; +using System; -namespace ProcessHacker +namespace ProcessHacker.Native { public class NProcessHacker { @@ -55,22 +56,33 @@ namespace ProcessHacker [DllImport("nprocesshacker.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] public static extern NtStatus PhpQueryProcessWs( - int ProcessHandle, - WS_INFORMATION_CLASS WsInformationClass, - out int WsInformation, - int WsInformationLength, - out int ReturnLength + [In] IntPtr ProcessHandle, + [In] WS_INFORMATION_CLASS WsInformationClass, + [Out] out int WsInformation, + [In] int WsInformationLength, + [Out] out int ReturnLength ); [DllImport("nprocesshacker.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] public static extern NtStatus PhpQueryProcessWs( - int ProcessHandle, - WS_INFORMATION_CLASS WsInformationClass, - out WS_ALL_COUNTS WsInformation, - int WsInformationLength, - out int ReturnLength + [In] IntPtr ProcessHandle, + [In] WS_INFORMATION_CLASS WsInformationClass, + [Out] out WS_ALL_COUNTS WsInformation, + [In] int WsInformationLength, + [Out] out int ReturnLength ); + [DllImport("nprocesshacker.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + public static extern NtStatus PhQueryNameFileObject( + [In] IntPtr FileHandle, + [In] IntPtr FileObjectNameInformation, + [In] int FileObjectNameInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("nprocesshacker.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void PhVoid(); + [DllImport("nprocesshacker.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern VerifyResult PhvVerifyFile(string FileName); } diff --git a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj index 447dc3acb..22056976b 100644 --- a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj +++ b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj @@ -59,6 +59,7 @@ + diff --git a/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs b/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs index f768a82c1..3c3f5ba60 100644 --- a/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs +++ b/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.Drawing; using Aga.Controls.Tree; using ProcessHacker.Common; +using ProcessHacker.Native; using ProcessHacker.Native.Api; using ProcessHacker.Native.Objects; using ProcessHacker.Native.Security; diff --git a/trunk/ProcessHacker/ProcessHacker.csproj b/trunk/ProcessHacker/ProcessHacker.csproj index 627f7f613..96813b1a1 100644 --- a/trunk/ProcessHacker/ProcessHacker.csproj +++ b/trunk/ProcessHacker/ProcessHacker.csproj @@ -705,7 +705,6 @@ -