java - jvm_bind - ¿Por qué se lanza conhost.exe?
java.net.bindexception address already in use jvm_bind netbeans (9)
Actualización: supongo que puedes encontrar el razonamiento en el viejo tema . Probablemente se agregó para restaurar algunas funciones (como arrastrar y soltar) que se eliminaron de Windows Vista por razones de seguridad.
Antes de la actualización: conhost parece iniciarse en cualquier apertura de cmd.exe. Probablemente sea algo nuevo e indocumentado en Windows 7.
Estoy lanzando un proceso de Java ("java.exe") desde .Net. utilizando Process.Start () . Además del proceso de Java, otro proceso llamado conhost.exe se inicia de alguna manera. Estoy redirigiendo la salida del proceso de Java al proceso .Net.
- ¿Por qué se lanza conhost.exe?
- ¿Cómo puedo rastrearlo desde .Net? Quiero rastrear esta instancia específica, y como no la estoy creando directamente (sino el proceso Java.exe), no tengo su PID.
En las versiones anteriores de Windows, las ventanas de la consola se alojaban en CSRSS, que es un proceso de gran importancia para el sistema, confiable y de alto nivel de privilegios. En Win7, parece que las ventanas de la consola ahora están alojadas en conhost.exe, que tiene menos derechos. Probablemente esto se hizo por razones de seguridad y confiabilidad: un problema de seguridad en el sistema de la consola no comprometerá todo el cuadro, y un bloqueo en el código de la consola no mostrará en pantalla azul el sistema.
Es un proceso que aloja la ventana de la consola. Se introdujo en Windows 7 (iirc), en versiones anteriores, la funcionalidad se ejecutó en el contexto del proceso csrss.exe.
Esto plantea una pregunta relacionada: ¿quieres una ventana de consola para la aplicación Java generada por la aplicación .NET?Si no, puede ejecutar el javaw
comando en lugar de java
. No he experimentado con él en Vista, pero puede eliminar el conhost.exe
proceso.
Para ser descarado, no sé nada sobre Java, así que no puedo ayudarte con el # 1. Sin embargo, puedo ayudarte con el # 2.
Para rastrearlo con .NET, puede usar System.Diagnostics.
En primer lugar, debe obtener cada uno de los procesos con el nombre "conhost.exe", iniciar Java, luego obtener todos los procesos nuevamente y comparar.
Para obtener las instancias específicas, use la ID del proceso :
foreach (Process singleProcess in Process.GetProcessesByName("conhost"))
{
//Store the following in some kind of array
somePidArray[yourindex] = singleProcess.Id;
}
Luego, cuando desee eliminar los procesos, ejecute exactamente el mismo bucle y, si la ID del proceso no se almacenó en el ciclo inicial, llame a singleProcess.Kill (); en eso. Luego, mantendrá vivos todos los procesos iniciales conhost.exe y solo eliminará los creados entre el momento en que ejecute Java en su programa y el momento en que finalice su proceso Java.
Lo siento, por necroear un hilo tan viejo, pero pensé que la pregunta es interesante y vale la pena una respuesta.
¿Por qué se lanza conhost.exe? Como se explicó en otras publicaciones, esta es ahora una forma predeterminada de alojar aplicaciones de consola. Se pueden encontrar más detalles en el artículo vinculado en otra respuesta aquí: ¿Qué es conhost.exe y por qué se está ejecutando?
¿Cómo puedo rastrearlo desde .Net? Quiero rastrear esta instancia específica, y como no la estoy creando directamente (sino el proceso Java.exe), no tengo su PID.
Como otros han notado, debería haber pocas razones para "rastrear" el proceso conhost. Habiendo dicho eso, hay una forma de obtener el id del proceso conhost desde su Id del proceso java.exe. Todo lo que tiene que hacer es enumerar todos los identificadores de proceso que tiene cada proceso conhost en el sistema, y si uno de estos identificadores apunta a un proceso con el mismo Id que su jawa.exe, este será el manejador conhost.exe que usted está después. Cubrirlo con ID de proceso y obtendrá el PID para conhost.exe
Entonces esto es teoría. ¿Cómo lograr esto en la práctica? Hay un excelente artículo que muestra algún código que está haciendo algo muy similar. He modificado este código un poco para adaptarlo a nuestra tarea. Al final, Utility.GetConhostIdByProcessId
la función estática Utility.GetConhostIdByProcessId
y pase el PID de su java.exe, y le devolverá el PID del conhost.exe correspondiente. Se puede encontrar una llamada de prueba a este método en la función Main en el siguiente ejemplo .
Y ahora el código:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SO1313195
{
class Program
{
static void Main()
{
const int processId = 6980;
int? result = Utility.GetConhostIdByProcessId(processId);
if (result.HasValue)
{
Console.WriteLine("Process {0} has conhost {1}", processId, result.Value);
}
else
{
Console.WriteLine("Unable to find conhost for process {0}", processId);
}
Console.ReadLine();
}
}
public class Win32Api
{
[DllImportAttribute("kernel32.dll", EntryPoint = "GetProcessId")]
public static extern uint GetProcessId([In]IntPtr process);
[DllImport("ntdll.dll")]
public static extern int NtQueryObject(IntPtr objectHandle, int
objectInformationClass, IntPtr objectInformation, int objectInformationLength,
ref int returnLength);
[DllImport("ntdll.dll")]
public static extern uint NtQuerySystemInformation(int
systemInformationClass, IntPtr systemInformation, int systemInformationLength,
ref int returnLength);
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(byte[] destination, IntPtr source, uint length);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
public enum ObjectInformationClass
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
ObjectAllTypesInformation = 3,
ObjectHandleInformation = 4
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VmOperation = 0x00000008,
VmRead = 0x00000010,
VmWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_BASIC_INFORMATION
{
public int Attributes;
public int GrantedAccess;
public int HandleCount;
public int PointerCount;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int NameInformationLength;
public int TypeInformationLength;
public int SecurityDescriptorLength;
public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_TYPE_INFORMATION
{
public UNICODE_STRING Name;
public int ObjectCount;
public int HandleCount;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public int PeakObjectCount;
public int PeakHandleCount;
public int Reserved5;
public int Reserved6;
public int Reserved7;
public int Reserved8;
public int InvalidAttributes;
public GENERIC_MAPPING GenericMapping;
public int ValidAccess;
public byte Unknown;
public byte MaintainHandleDatabase;
public int PoolType;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct GENERIC_MAPPING
{
public int GenericRead;
public int GenericWrite;
public int GenericExecute;
public int GenericAll;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_HANDLE_INFORMATION
{
public int ProcessID;
public byte ObjectTypeNumber;
public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
public ushort Handle;
public int Object_Pointer;
public UInt32 GrantedAccess;
}
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2;
}
class Utility
{
public static int? GetConhostIdByProcessId(int processId)
{
foreach (Process process in Process.GetProcessesByName("conhost"))
{
IntPtr processHwnd = Win32Api.OpenProcess(Win32Api.ProcessAccessFlags.DupHandle, false, process.Id);
List<Win32Api.SYSTEM_HANDLE_INFORMATION> lstHandles = GetHandles(process);
foreach (Win32Api.SYSTEM_HANDLE_INFORMATION handle in lstHandles)
{
int? id = GetFileDetails(processHwnd, handle);
if (id == processId)
{
return process.Id;
}
}
}
return null;
}
private static int? GetFileDetails(IntPtr processHwnd, Win32Api.SYSTEM_HANDLE_INFORMATION systemHandleInformation)
{
IntPtr ipHandle;
Win32Api.OBJECT_BASIC_INFORMATION objBasic = new Win32Api.OBJECT_BASIC_INFORMATION();
Win32Api.OBJECT_TYPE_INFORMATION objObjectType = new Win32Api.OBJECT_TYPE_INFORMATION();
int nLength = 0;
if (!Win32Api.DuplicateHandle(processHwnd, systemHandleInformation.Handle, Win32Api.GetCurrentProcess(), out ipHandle, 0, false, Win32Api.DUPLICATE_SAME_ACCESS)) return null;
IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
Win32Api.NtQueryObject(ipHandle, (int)Win32Api.ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength);
objBasic = (Win32Api.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
Marshal.FreeHGlobal(ipBasic);
IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
nLength = objBasic.TypeInformationLength;
while ((uint)(Win32Api.NtQueryObject(ipHandle, (int)Win32Api.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32Api.STATUS_INFO_LENGTH_MISMATCH)
{
Marshal.FreeHGlobal(ipObjectType);
ipObjectType = Marshal.AllocHGlobal(nLength);
}
objObjectType = (Win32Api.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
IntPtr ipTemp = Is64Bits() ? new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32) : objObjectType.Name.Buffer;
string strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
Marshal.FreeHGlobal(ipObjectType);
if (strObjectTypeName != "Process") return null;
return (int)Win32Api.GetProcessId(ipHandle);
}
private static List<Win32Api.SYSTEM_HANDLE_INFORMATION> GetHandles(Process process)
{
const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004;
int nHandleInfoSize = 0x10000;
IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
int nLength = 0;
IntPtr ipHandle;
while ((Win32Api.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];
Win32Api.CopyMemory(baTemp, ipHandlePointer, (uint)nLength);
long lHandleCount;
if (Is64Bits())
{
lHandleCount = Marshal.ReadInt64(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
}
else
{
lHandleCount = Marshal.ReadInt32(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
}
Win32Api.SYSTEM_HANDLE_INFORMATION shHandle;
List<Win32Api.SYSTEM_HANDLE_INFORMATION> lstHandles = new List<Win32Api.SYSTEM_HANDLE_INFORMATION>();
for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
{
shHandle = new Win32Api.SYSTEM_HANDLE_INFORMATION();
if (Is64Bits())
{
shHandle = (Win32Api.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 = (Win32Api.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
}
if (shHandle.ProcessID != process.Id) continue;
lstHandles.Add(shHandle);
}
return lstHandles;
}
static bool Is64Bits()
{
return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false;
}
}
}
Tenga en cuenta que solo probé este código en x64 Windows 7 con la opción de compilación x86 y x64. Lo compilé con VS2010 para .NET 4. Este código es menos legible y no puedo garantizar que funcione en todas las plataformas y arquitecturas relevantes. Sin embargo, funciona aquí (tm) y es útil para esta tarea esotérica.
Cuando uno inicia un proceso usando ''Process.Start ()'', tiene la opción de crear el proceso directamente, o de ejecutar ''cmd.exe'' y dejar que ''cmd.exe'' maneje los detalles. El indicador ''UseShellExecute'' controla esto. Si elige dejar los detalles en ''cmd.exe'', que es común en situaciones donde desea invocar un archivo y dejar que el shell ejecute el programa apropiado para manejarlo, por ejemplo, al "ejecutar" un archivo ''.txt'', luego en Win7 esto realmente ejecutará ''cmd'', que a su vez ejecuta ''conhost''. Si, por otro lado, no usa ''ShellExecute'', ''Start ()'' no ejecutará ''cmd'' y no lanzará indirectamente ''conhost''.
Acabo de escribir un artículo que intenta explicar el propósito del proceso. Está dirigido a personas normales, pero hay muchas capturas de pantalla para ilustrar.
¿Qué es conhost.exe y por qué se está ejecutando?
La conclusión es que conhost.exe se encuentra entre el proceso CSRSS y cmd.exe, por lo que puede usar arrastrar y soltar de nuevo.
Basado en la respuesta de zespri , escribí métodos actualizados.
Este código es capaz de manejar identificadores de proceso de más de 16 bits.
También se corrigió un error de lógica y algunas pérdidas de memoria y control. Se agregó alguna falla de seguridad.
Agregué un método para el caso cuando conhost.exe tiene múltiples procesos asociados. Esto puede suceder cuando se está ejecutando un programa de consola y tiene cmd.exe como su proceso principal, pero también en otros casos, donde los procesos asociados ni siquiera están en la relación padre hijo.
Muchas gracias por zespri por el código original, ¡hay mucho que aprender de él!
Más explicación para las actualizaciones de métodos:
Para WinXP +, es mejor utilizar SYSTEM_EXTENDED_HANDLE_INFORMATION, ya que SYSTEM_HANDLE_INFORMATION solo devuelve id-s de proceso largos de 16 bits. Si el sistema está muy cargado con identificadores, los id-s de proceso tienden a comenzar a tener valores superiores a 65 k, por ejemplo, 8 dígitos decimales. La llamada al sistema que utiliza el código anterior simplemente enmascararía los bits altos de los id-s del proceso. Puede encontrar SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX y su uso en el código fuente de Process Hacker.
void Main()
{
//System.Diagnostics.Process.EnterDebugMode(); //TODO: is this necessary?
int? ConsoleHost_PId = NativeMethods.GetConhostIdByProcessId(14412376);
ConsoleHost_PId.Dump();
int pid = 4484;
int? apid = NativeMethods.GetFirstConhostAssociatedProcessId(pid);
apid.Dump();
var apids = NativeMethods.GetConhostAssociatedProcessIds(pid);
apids.Dump();
}
public static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImportAttribute("kernel32.dll", SetLastError = true)]
public static extern uint GetProcessId([In]IntPtr process);
[DllImport("ntdll.dll")]
public static extern uint NtQueryObject(IntPtr objectHandle,
int objectInformationClass, IntPtr objectInformation, int objectInformationLength,
ref int returnLength);
[DllImport("ntdll.dll")]
public static extern uint NtQuerySystemInformation(int
systemInformationClass, IntPtr systemInformation, int systemInformationLength,
ref int returnLength);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
public enum ObjectInformationClass
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
ObjectAllTypesInformation = 3,
ObjectHandleInformation = 4
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VmOperation = 0x00000008,
VmRead = 0x00000010,
VmWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_BASIC_INFORMATION
{
public int Attributes;
public int GrantedAccess;
public int HandleCount;
public int PointerCount;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int NameInformationLength;
public int TypeInformationLength;
public int SecurityDescriptorLength;
public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_TYPE_INFORMATION
{
public UNICODE_STRING Name;
public int ObjectCount;
public int HandleCount;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public int PeakObjectCount;
public int PeakHandleCount;
public int Reserved5;
public int Reserved6;
public int Reserved7;
public int Reserved8;
public int InvalidAttributes;
public GENERIC_MAPPING GenericMapping;
public int ValidAccess;
public byte Unknown;
public byte MaintainHandleDatabase;
public int PoolType;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
}
[StructLayout(LayoutKind.Sequential)] //, Pack = 1)] //NB! no packing!
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct GENERIC_MAPPING
{
public int GenericRead;
public int GenericWrite;
public int GenericExecute;
public int GenericAll;
}
[StructLayout(LayoutKind.Sequential)] //, Pack = 1)] //NB! no packing!
public struct SYSTEM_HANDLE_INFORMATION
{
public ushort UniqueProcessId;
public ushort CreatorBackTraceIndex;
public byte ObjectTypeIndex;
public byte HandleAttributes; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
public ushort HandleValue;
public UIntPtr Object;
public uint GrantedAccess;
}
//adapted from ProcessExplorer ntexapi.h
[StructLayout(LayoutKind.Sequential)] //, Pack = 1)] //NB! no packing!
public struct SYSTEM_HANDLE_INFORMATION_EX
{
public UIntPtr Object;
public UIntPtr UniqueProcessId; //changed ulong to IntPtr
public UIntPtr HandleValue; //changed ulong to IntPtr
public uint GrantedAccess;
public ushort CreatorBackTraceIndex;
public ushort ObjectTypeIndex;
public uint HandleAttributes;
public uint Reserved;
}
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2;
// ############################################################################
/// <summary>
/// Some console host processes have multiple associated processes!
/// </summary>
public static List<int> GetConhostAssociatedProcessIds(int pid)
{
List<int> result = new List<int>();
IntPtr currentProcess = GetCurrentProcess();
IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid);
try
{
List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = GetHandles(pid);
foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles)
{
int? id = GetFileDetails(processHandle, handleInformation, currentProcess);
if (id.HasValue)
result.Add(id.Value);
}
return result;
}
finally
{
CloseHandle(processHandle);
}
}
public static int? GetFirstConhostAssociatedProcessId(int pid)
{
IntPtr currentProcess = GetCurrentProcess();
IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid);
try
{
List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = GetHandles(pid);
foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles)
{
int? id = GetFileDetails(processHandle, handleInformation, currentProcess);
if (id.HasValue)
return id;
}
return null;
}
finally
{
CloseHandle(processHandle);
}
}
public static int? GetConhostIdByProcessId(int processId)
{
IntPtr currentProcess = GetCurrentProcess();
var processes = Process.GetProcessesByName("conhost");
try
{
foreach (Process process in processes) //TODO: check that this process is really system''s console host
{
IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, process.Id);
try
{
List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = GetHandles(process.Id);
foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles)
{
int? id = GetFileDetails(processHandle, handleInformation, currentProcess);
if (id == processId)
{
return process.Id;
}
}
}
finally
{
CloseHandle(processHandle);
}
} //foreach (Process process in Process.GetProcessesByName("conhost"))
return null;
}
finally
{
foreach (Process process in processes)
process.Dispose();
}
} //public static int? GetConhostIdByProcessId(int processId)
//TODO see this for possible hang under XP 32-bit:
//http://forum.sysinternals.com/handle-name-help-ntqueryobject_topic14435.html
//and https://.com/questions/16127948/hang-on-ntquerysysteminformation-in-winxpx32-but-works-fine-in-win7x64
private static int? GetFileDetails(IntPtr processHandle, SYSTEM_HANDLE_INFORMATION_EX systemHandleInformation,
IntPtr currentProcess)
{
IntPtr ipHandle;
OBJECT_BASIC_INFORMATION objBasic = new OBJECT_BASIC_INFORMATION();
OBJECT_TYPE_INFORMATION objObjectType = new OBJECT_TYPE_INFORMATION();
int nLength = 0;
if (Is64Bits())
{
if (!DuplicateHandle(processHandle, new IntPtr(unchecked((long)systemHandleInformation.HandleValue)), currentProcess,
out ipHandle, 0, false, DUPLICATE_SAME_ACCESS))
{
return null;
}
}
else
{
//failsafety
if ((systemHandleInformation.HandleValue.ToUInt64() >> 32) != 0)
return null;
if (!DuplicateHandle(processHandle, new IntPtr(unchecked((int)systemHandleInformation.HandleValue)), currentProcess,
out ipHandle, 0, false, DUPLICATE_SAME_ACCESS))
{
return null;
}
}
try
{
IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
try
{
NtQueryObject(ipHandle, (int)ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength);
objBasic = (OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
}
finally
{
Marshal.FreeHGlobal(ipBasic);
}
IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
try
{
nLength = objBasic.TypeInformationLength;
while (NtQueryObject(ipHandle, (int)ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
{
Marshal.FreeHGlobal(ipObjectType);
ipObjectType = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails
ipObjectType = Marshal.AllocHGlobal(nLength);
}
objObjectType = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
//IntPtr ipTemp = Is64Bits() ? new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32) : objObjectType.Name.Buffer;
//string strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, objObjectType.Name.Length >> 1);
if (strObjectTypeName != "Process")
return null;
}
finally
{
Marshal.FreeHGlobal(ipObjectType);
}
return (int)GetProcessId(ipHandle);
}
finally
{
CloseHandle(ipHandle);
}
} //private static int? GetFileDetails(IntPtr processHandle, SYSTEM_HANDLE_INFORMATION systemHandleInformation, IntPtr currentProcess)
const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
const int CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION = 64; //from ProcessHacker ntexapi.h
//http://hintdesk.com/c-get-all-handles-of-a-given-process-in-64-bits/
private static List<SYSTEM_HANDLE_INFORMATION_EX> GetHandles(int pid)
{
List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = new List<SYSTEM_HANDLE_INFORMATION_EX>();
int nHandleInfoSize = 0x10000;
IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
int nLength = 0;
IntPtr ipHandle;
if (IsWinXP) //from ProcessHacker. This works under Win XP+
{
try
{
//the structure array may get larger any number of times during our query
while (
(
NtQuerySystemInformation(CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION, ipHandlePointer,
nHandleInfoSize, ref nLength)
)
== STATUS_INFO_LENGTH_MISMATCH
)
{
//TODO: stop loop if buffer size gets large
nHandleInfoSize = nLength;
Marshal.FreeHGlobal(ipHandlePointer);
ipHandlePointer = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails
ipHandlePointer = Marshal.AllocHGlobal(nLength);
}
long lHandleCount;
if (Is64Bits())
{
lHandleCount = Marshal.ReadInt64(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 16);
}
else
{
lHandleCount = Marshal.ReadInt32(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 8); //changed to 8, tested OK
}
SYSTEM_HANDLE_INFORMATION_EX shHandle_ex;
for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
{
shHandle_ex = new SYSTEM_HANDLE_INFORMATION_EX();
if (Is64Bits())
{
shHandle_ex = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(ipHandle, shHandle_ex.GetType());
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle_ex));
}
else
{
shHandle_ex = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(ipHandle, shHandle_ex.GetType());
ipHandle = new IntPtr(ipHandle.ToInt32() + Marshal.SizeOf(shHandle_ex));
}
//failsafety
if (shHandle_ex.UniqueProcessId.ToUInt64() > (ulong)int.MaxValue) //TODO: start using ulong pids?
continue;
if ((int)shHandle_ex.UniqueProcessId.ToUInt32() != pid)
continue;
lstHandles.Add(shHandle_ex);
}
}
finally
{
Marshal.FreeHGlobal(ipHandlePointer);
}
return lstHandles;
}
else //if (IsWinXP)
{
try
{
//the structure array may get larger any number of times during our query
while (
(
NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer,
nHandleInfoSize, ref nLength)
)
== STATUS_INFO_LENGTH_MISMATCH
)
{
//TODO: stop loop if buffer size gets large
nHandleInfoSize = nLength;
Marshal.FreeHGlobal(ipHandlePointer);
ipHandlePointer = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails
ipHandlePointer = Marshal.AllocHGlobal(nLength);
}
long lHandleCount;
if (Is64Bits())
{
lHandleCount = Marshal.ReadInt64(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
}
else
{
lHandleCount = Marshal.ReadInt32(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
}
SYSTEM_HANDLE_INFORMATION shHandle;
for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
{
shHandle = new SYSTEM_HANDLE_INFORMATION();
if (Is64Bits())
{
shHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 4);
}
else
{
shHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
ipHandle = new IntPtr(ipHandle.ToInt32() + Marshal.SizeOf(shHandle));
}
if (shHandle.UniqueProcessId != pid)
continue;
SYSTEM_HANDLE_INFORMATION_EX shHandle_ex = new SYSTEM_HANDLE_INFORMATION_EX();
shHandle_ex.Object = shHandle.Object;
shHandle_ex.UniqueProcessId = new UIntPtr(shHandle.UniqueProcessId);
shHandle_ex.HandleValue = new UIntPtr(shHandle.HandleValue);
shHandle_ex.GrantedAccess = shHandle.GrantedAccess;
shHandle_ex.CreatorBackTraceIndex = shHandle.CreatorBackTraceIndex;
shHandle_ex.ObjectTypeIndex = shHandle.ObjectTypeIndex;
shHandle_ex.HandleAttributes = shHandle.HandleAttributes;
lstHandles.Add(shHandle_ex);
}
}
finally
{
Marshal.FreeHGlobal(ipHandlePointer);
}
return lstHandles;
} //if (IsWinXP)
} //private static List<SYSTEM_HANDLE_INFORMATION> GetHandles(int pid)
private static bool Is64Bits()
{
return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false;
}
public static bool IsWinXP
{
get
{
return (
false
|| (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) //WinXP
|| Environment.OSVersion.Version.Major >= 6 //Vista or 7
);
}
}
}
ACTUALIZAR:
Agregué correcciones de errores importantes para el código de 64 bits el 27.06.2014.
El empaque de la estructura UNICODE_STRING era incorrecto y el código intentó compensarlo de alguna manera complicada. Aunque no se manifestó en Win7, se colgó muy bien en Win8.
El embalaje de las otras estructuras con Pack = 1 también fue incorrecto, pero accidentalmente no modificó su diseño calculado.
Las partes importantes cambiadas fueron:
[StructLayout(LayoutKind.Sequential)] //, Pack = 1)] //NB! no packing!
public struct UNICODE_STRING
//IntPtr ipTemp = Is64Bits() ? new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32) : objObjectType.Name.Buffer;
//string strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, objObjectType.Name.Length >> 1);