Files
mirror-processhacker/1.x/trunk/ProcessHacker.Native/Api/Extensions.cs
T
dmex e0579b0393 PH1.x: Code Cleanup/Fixes, Initial KPH2 support
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4785 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2011-10-30 10:35:02 +00:00

471 lines
18 KiB
C#

/*
* Process Hacker -
* windows API structure extension functions
*
* 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 <http://www.gnu.org/licenses/>.
*/
using System;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Objects;
using ProcessHacker.Native.Security;
namespace ProcessHacker.Native
{
public static class NativeExtensions
{
private static bool NphNotAvailable;
public static ObjectBasicInformation GetBasicInfo(this SystemHandleEntry thisHandle)
{
using (ProcessHandle process = new ProcessHandle(thisHandle.ProcessId, ProcessAccess.DupHandle))
{
return thisHandle.GetBasicInfo(process);
}
}
public static ObjectBasicInformation GetBasicInfo(this SystemHandleEntry thisHandle, ProcessHandle process)
{
IntPtr handle = new IntPtr(thisHandle.Handle);
IntPtr objectHandleI;
GenericHandle objectHandle = null;
int retLength;
Win32.NtDuplicateObject(
process,
handle,
ProcessHandle.Current,
out objectHandleI,
0,
0,
0
).ThrowIf();
try
{
objectHandle = new GenericHandle(objectHandleI);
using (MemoryAlloc data = new MemoryAlloc(ObjectBasicInformation.SizeOf))
{
Win32.NtQueryObject(
objectHandle,
ObjectInformationClass.ObjectBasicInformation,
data,
data.Size,
out retLength
).ThrowIf();
return data.ReadStruct<ObjectBasicInformation>();
}
}
finally
{
if (objectHandle != null)
objectHandle.Dispose();
}
}
public static string GetName(this ClientId clientId)
{
return clientId.GetName(true);
}
public static string GetName(this ClientId clientId, bool includeThread)
{
string processName = Windows.GetProcessName(clientId.ProcessId);
if (includeThread)
{
if (!string.IsNullOrEmpty(processName))
return processName + " (" + clientId.ProcessId.ToString() + "): " + clientId.ThreadId.ToString();
return "Non-existent process (" + clientId.ProcessId.ToString() + "): " + clientId.ThreadId.ToString();
}
if (!string.IsNullOrEmpty(processName))
return processName + " (" + clientId.ProcessId.ToString() + ")";
return "Non-existent process (" + clientId.ProcessId.ToString() + ")";
}
private static string GetObjectNameNt(ProcessHandle process, IntPtr handle, GenericHandle dupHandle)
{
int retLength;
Win32.NtQueryObject(
dupHandle,
ObjectInformationClass.ObjectNameInformation,
IntPtr.Zero,
0,
out retLength
);
if (retLength > 0)
{
using (MemoryAlloc oniMem = new MemoryAlloc(retLength))
{
Win32.NtQueryObject(
dupHandle,
ObjectInformationClass.ObjectNameInformation,
oniMem,
oniMem.Size,
out retLength
).ThrowIf();
ObjectNameInformation oni = oniMem.ReadStruct<ObjectNameInformation>();
UnicodeString str = oni.Name;
//if (KProcessHacker.Instance != null)
//str.Buffer = str.Buffer.Increment(oniMem.Memory.Decrement(baseAddress));
return str.Text;
}
}
throw new Exception("NtQueryObject failed.");
}
public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle)
{
return thisHandle.GetHandleInfo(true);
}
public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, bool getName)
{
using (ProcessHandle process = new ProcessHandle(thisHandle.ProcessId, ProcessAccess.DupHandle))
{
return thisHandle.GetHandleInfo(process, getName);
}
}
public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, ProcessHandle process)
{
return thisHandle.GetHandleInfo(process, true);
}
public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, ProcessHandle process, bool getName)
{
IntPtr handle = new IntPtr(thisHandle.Handle);
IntPtr objectHandleI;
int retLength;
GenericHandle objectHandle = null;
if (thisHandle.Handle == 0 || thisHandle.Handle == -1 || thisHandle.Handle == -2)
throw new WindowsException(NtStatus.InvalidHandle);
// Duplicate the handle if we're not using KPH
//if (KProcessHacker.Instance == null)
{
Win32.NtDuplicateObject(
process,
handle,
ProcessHandle.Current,
out objectHandleI,
0,
0,
0
).ThrowIf();
objectHandle = new GenericHandle(objectHandleI);
}
ObjectInformation info = new ObjectInformation();
// If the cache contains the object type's name, use it. Otherwise, query the type
// for its name.
Windows.ObjectTypesLock.AcquireShared();
try
{
if (Windows.ObjectTypes.ContainsKey(thisHandle.ObjectTypeNumber))
{
info.TypeName = Windows.ObjectTypes[thisHandle.ObjectTypeNumber];
}
}
finally
{
Windows.ObjectTypesLock.ReleaseShared();
}
if (string.IsNullOrEmpty(info.TypeName))
{
Win32.NtQueryObject(
objectHandle,
ObjectInformationClass.ObjectTypeInformation,
IntPtr.Zero,
0,
out retLength
);
if (retLength > 0)
{
using (MemoryAlloc otiMem = new MemoryAlloc(retLength))
{
Win32.NtQueryObject(
objectHandle,
ObjectInformationClass.ObjectTypeInformation,
otiMem,
otiMem.Size,
out retLength
).ThrowIf();
ObjectTypeInformation oti = otiMem.ReadStruct<ObjectTypeInformation>();
UnicodeString str = oti.Name;
//if (KProcessHacker.Instance != null)
//str.Buffer = str.Buffer.Increment(otiMem.Memory.Decrement(baseAddress));
info.TypeName = str.Text;
Windows.ObjectTypesLock.AcquireExclusive();
try
{
if (!Windows.ObjectTypes.ContainsKey(thisHandle.ObjectTypeNumber))
Windows.ObjectTypes.Add(thisHandle.ObjectTypeNumber, info.TypeName);
}
finally
{
Windows.ObjectTypesLock.ReleaseExclusive();
}
}
}
}
if (!getName)
return info;
// Get the object's name. If the object is a file we must take special
// precautions so that we don't hang.
if (string.Equals(info.TypeName, "File", StringComparison.OrdinalIgnoreCase))
{
//if (KProcessHacker.Instance != null)
//{
// // Use KProcessHacker for files to avoid hangs.
// info.OrigName = KProcessHacker.Instance.GetHandleObjectName(process, handle);
//}
//else
{
// 0: No hack, query the thing normally.
// 1: No hack, use NProcessHacker.
// 2: Hack.
int hackLevel = 1;
// If we already tried to use NPH but it wasn't present,
// skip to level 2.
if (NphNotAvailable)
hackLevel = 2;
// Can't use NPH because XP had a bug where a thread hanging
// on NtQueryObject couldn't be terminated.
if (OSVersion.IsBelowOrEqual(WindowsVersion.XP))
hackLevel = 2;
// On Windows 7 and above the hanging bug appears to have
// been fixed. Query the object normally.
// UPDATE: Not so. It still happens.
//if (OSVersion.IsAboveOrEqual(WindowsVersion.Seven))
// hackLevel = 0;
if (hackLevel == 1)
{
try
{
// Use NProcessHacker.
using (MemoryAlloc oniMem = new MemoryAlloc(0x4000))
{
NProcessHacker.PhQueryNameFileObject(
objectHandle,
oniMem,
oniMem.Size,
out retLength
).ThrowIf();
var oni = oniMem.ReadStruct<ObjectNameInformation>();
info.OrigName = oni.Name.Text;
}
}
catch (DllNotFoundException)
{
hackLevel = 2;
NphNotAvailable = true;
}
}
if (hackLevel == 0)
{
info.OrigName = GetObjectNameNt(process, handle, objectHandle);
}
else if (hackLevel == 2)
{
// KProcessHacker and NProcessHacker not available. Fall back to using hack
// (i.e. not querying the name at all if the access is 0x0012019f).
if (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.
try
{
switch (info.TypeName)
{
case "File":
// Resolves \Device\HarddiskVolume1 into C:, for example.
if (!string.IsNullOrEmpty(info.OrigName))
info.BestName = FileUtils.GetFileName(info.OrigName);
break;
case "Key":
info.BestName = NativeUtils.FormatNativeKeyName(info.OrigName);
break;
case "Process":
{
int processId;
using (NativeHandle<ProcessAccess> processHandle = new NativeHandle<ProcessAccess>(process, handle, OSVersion.MinProcessQueryInfoAccess))
{
if ((processId = Win32.GetProcessId(processHandle)) == 0)
Win32.Throw();
}
info.BestName = (new ClientId(processId, 0)).GetName(false);
}
break;
case "Thread":
{
int processId;
int threadId;
using (var threadHandle = new NativeHandle<ThreadAccess>(process, handle, OSVersion.MinThreadQueryInfoAccess))
{
var basicInfo = ThreadHandle.FromHandle(threadHandle).GetBasicInformation();
threadId = basicInfo.ClientId.ThreadId;
processId = basicInfo.ClientId.ProcessId;
}
info.BestName = (new ClientId(processId, threadId)).GetName(true);
}
break;
case "TmEn":
{
using (NativeHandle<EnlistmentAccess> enHandleDup = new NativeHandle<EnlistmentAccess>(process, handle, EnlistmentAccess.QueryInformation))
using (EnlistmentHandle enHandle = EnlistmentHandle.FromHandle(enHandleDup))
{
info.BestName = enHandle.BasicInformation.EnlistmentId.ToString("B");
}
}
break;
case "TmRm":
{
using (var rmHandleDup = new NativeHandle<ResourceManagerAccess>(process, handle, ResourceManagerAccess.QueryInformation))
{
var rmHandle = ResourceManagerHandle.FromHandle(rmHandleDup);
info.BestName = rmHandle.Description;
if (string.IsNullOrEmpty(info.BestName))
info.BestName = rmHandle.Guid.ToString("B");
}
}
break;
case "TmTm":
{
using (NativeHandle<TmAccess> tmHandleDup = new NativeHandle<TmAccess>(process, handle, TmAccess.QueryInformation))
using (TmHandle tmHandle = TmHandle.FromHandle(tmHandleDup))
{
info.BestName = FileUtils.GetFileName(FileUtils.GetFileName(tmHandle.LogFileName));
if (string.IsNullOrEmpty(info.BestName))
info.BestName = tmHandle.BasicInformation.TmIdentity.ToString("B");
}
}
break;
case "TmTx":
{
using (var transactionHandleDup = new NativeHandle<TransactionAccess>(process, handle, TransactionAccess.QueryInformation))
{
TransactionHandle transactionHandle = TransactionHandle.FromHandle(transactionHandleDup);
info.BestName = transactionHandle.Description;
if (string.IsNullOrEmpty(info.BestName))
info.BestName = transactionHandle.BasicInformation.TransactionId.ToString("B");
}
}
break;
case "Token":
{
using (var tokenHandleDup = new NativeHandle<TokenAccess>(process, handle, TokenAccess.Query))
using (TokenHandle tokenHandle = TokenHandle.FromHandle(tokenHandleDup))
using (tokenHandle.User)
{
info.BestName = tokenHandle.User.GetFullName(true) + ": 0x" + tokenHandle.Statistics.AuthenticationId;
}
}
break;
default:
if (!string.IsNullOrEmpty(info.OrigName))
{
info.BestName = info.OrigName;
}
else
{
info.BestName = null;
}
break;
}
}
catch
{
if (!string.IsNullOrEmpty(info.OrigName))
{
info.BestName = info.OrigName;
}
else
{
info.BestName = null;
}
}
if (objectHandle != null)
objectHandle.Dispose();
return info;
}
}
}