2012-04-03 14 views
5

Sono richiesto per una determinata attività per enumerare tutti gli handle nel sistema. L'approccio migliore che ho trovato finora è l'uso di documenti non documentati NtQuerySystemInformation con il flag SystemHandleInformation per il parametro di classe.Approccio preferito per la compilazione condizionale per versioni di tipi a 32 bit contro 64 bit

Fin qui tutto bene. Tuttavia, l'esecuzione in modalità a 32 bit a 64 bit di Windows, la struttura richiesta è la seguente:

// 32-bit version 
[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct SYSTEM_HANDLE_INFORMATION 
{ 
    public uint ProcessID;    
    public byte ObjectTypeNumber;  
    public byte Flags;     
    public ushort Handle;    
    public uint Object_Pointer;  
    public UInt32 GrantedAccess;   
} 

E per Windows a 64 bit (x64, non ho la prova Itanium, che spero non sia diverso. ..), la struttura è la seguente:

// 64-bit version 
[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct SYSTEM_HANDLE_INFORMATION 
{ 
    public int Reserved;   // unknown, no documentation found 
    public uint ProcessID;    
    public byte ObjectTypeNumber;  
    public byte Flags;     
    public ushort Handle;    
    public long Object_Pointer;  
    public UInt32 GrantedAccess;   
} 

Ora, dovrei cambiare il Object_Pointer a un IntPtr. Speravo per un momento che potessi fare lo stesso con ProcessId, c'era un riferimento che diceva che in realtà era un HANDLE che in realtà è un valore a 64 bit. Tuttavia, Reserved è sempre zero, quindi non posso unirlo in uno IntPtr allo stesso modo.

Questo probabilmente non è l'unico scenario in cui ciò accade. Sto cercando un modo migliore pratica di trattare con tali differenze:

  • Usando una costante come #if WIN32 (utilizzato internamente nella fonte di riferimento di IntPtr) non avrebbe funzionato qui a meno che voglio mantenere separati i binari.
  • Posso scrivere due diverse funzioni e due diverse strutture, creare un wrapper e utilizzare if IntPtr.Size ==4 nel codice. Funziona per funzioni esterne, ma non funziona bene con i tipi.
  • Posso sovraccaricare GetType ma non sono sicuro di dove porta (potrebbe essere d'aiuto con Marshalling?).
  • C'è altro?

Nessuno di questi sembra l'ideale, ma finora, l'unico modo infallibile sembra essere quella di strutto mio sistema con if IsWin64() dichiarazioni. Mi piacerebbe sentire approcci migliori dei miei.

+3

Questo tipo di codice è come il sesso adolescenziale, un errore e ti sostenere per il resto della tua vita. Utilizzare la classe Process per eseguire l'utilità Handle.exe di SysInternals, almeno è possibile ottenere qualcun altro per supportarlo. –

+0

@HansPassant: LOL! Sì, ho preso in considerazione l'utilizzo di qualcuno dei programmi di utilità di SysInternal, ma no, non si adatta al mio scenario. Grazie per il puntatore però. – Abel

risposta

2

data dimensione di IntPtr è diverso, perché non provare il seguente:

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct SYSTEM_HANDLE_INFORMATION 
{ 
    public IntPtr ProcessID;    // mask with 0xffffffff 
    public byte ObjectTypeNumber;  
    public byte Flags;     
    public ushort Handle;    
    public IntPtr Object_Pointer;   // again good for 32/64bit 
    public UInt32 GrantedAccess;   
} 

Questo dovrebbe funzionare sia per 32 e 64 bit inalterato.

+0

Sì, l'ho provato un paio di volte, ma restituisce l'ID processo errato. Forse è una buona idea, dovrei quindi espandere la struct con un metodo 'GetProcessId()' che esegue lo smascheramento e contrassegna ProcessID private. – Abel

+0

@Abel: a 64 bit, quindi righthift a 32 bit.Non ero sicuro dei problemi di endian :) – leppie

+0

Ottiene l'ID di processo 4 (sistema) come '0x0000000400000000', che è' 17179869184', dalla sequenza di byte '00 00 00 00 04 00 00 00'. Quindi sì, l'endianità è un problema (nel senso che i principali zero riservati sono nel modo). '0x0000000400000000 >> 32' funziona in casi a 64 bit. – Abel

3

Questo è il problema: le strutture di SystemHandleInformation forniscono solo PID a 16 bit. È possibile utilizzare SystemExtendedHandleInformation su XP e versioni successive.

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
    public class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX 
    { 
    public IntPtr Object; 
    public IntPtr UniqueProcessId; 
    public IntPtr HandleValue; 
    public uint GrantedAccess; 
    public ushort CreatorBackTraceIndex; 
    public ushort ObjectTypeIndex; 
    public uint HandleAttributes; 
    public uint Reserved; 
    } 

    internal enum SYSTEM_INFORMATION_CLASS 
    { 
    SystemBasicInformation = 0, 
    SystemPerformanceInformation = 2, 
    SystemTimeOfDayInformation = 3, 
    SystemProcessInformation = 5, 
    SystemProcessorPerformanceInformation = 8, 
    SystemHandleInformation = 16, 
    SystemInterruptInformation = 23, 
    SystemExceptionInformation = 33, 
    SystemRegistryQuotaInformation = 37, 
    SystemLookasideInformation = 45, 
    SystemExtendedHandleInformation = 64, 
    } 


[DllImport("ntdll.dll", CharSet=CharSet.Auto)] 
private static extern int NtQuerySystemInformation(int InfoType, IntPtr lpStructure, int StructSize, out int returnLength); 



    public static void Main(string[] args) 
    { 
    Console.WriteLine(Environment.Is64BitProcess ? "x64" : "x32"); 
    Console.WriteLine(); 

    var infoSize = Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); 

    Console.WriteLine("sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): {0}", infoSize); 
    int allSize = 1000 * infoSize; 
    var buffer = Marshal.AllocHGlobal(allSize); 
    var status = NtQuerySystemInformation((int)SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, buffer, allSize, out allSize); 
    Console.WriteLine("status: {0:x}, return len: {1}", status, allSize); 

    if (status != 0) 
    { 
     allSize += 40 * infoSize; 
     Marshal.FreeHGlobal(buffer); 
     buffer = Marshal.AllocHGlobal(allSize); 
     status = NtQuerySystemInformation((int)SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, buffer, allSize, out allSize); 
     Console.WriteLine("status: {0:x}, return len: {1}", status, allSize); 
    } 

    Console.WriteLine(); 
    var info = new SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(); 
    //for (var i = 0; i < allSize; i += infoSize) 
    for (var i = 0; i < Math.Min(allSize, 20 * infoSize); i+= infoSize) // for testing purpose only 20 
    { 
     Marshal.PtrToStructure(IntPtr.Add(buffer, i), info); 
     Console.WriteLine("{0,16:x}, {1,16:x}, {2,16:x}, {3,6:x}, {4,8:x}", info.Object.ToInt64(), info.UniqueProcessId.ToInt64(), info.HandleValue.ToInt64(), info.GrantedAccess, info.HandleAttributes); 
    } 
    Marshal.FreeHGlobal(buffer); 
    } 

uscita:

x32 

sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): 28 
status: c0000004, return len: 1850052 
status: 0, return len: 1850052 

      10219,    0,   6729b30,  4, 1fffff 
       0,    0,    dfa0,  4, 2001f 
       0,    0,    8eb0,  4, f000f 
       0,    0,    fca0,  4,  0 
       0,    0,   225b0,  4, 20019 
       0,    0,   98210,  4, f003f 
       0,    0,   6758e60,  4, 1f0001 
       0,    0,   98040,  4, 2001f 
       0,    0,   67534e0,  4, 1f0001 
       0,    0,   9c560,  4, 2001f 
       0,    0,   6834620,  4, 1fffff 
       0,    0,   99250,  4, f003f 
       0,    0,   9a7c0,  4, f003f 
       0,    0,   95380,  4, f003f 
       0,    0,   62d80,  4, f003f 
       0,    0,   15e580,  4, 20019 
       0,    0,   6f3b940,  4,  2a 
       0,    0,   20da30,  4,  e 
       0,    0,   7b07a0,  4,  10 
       0,    0,   9af83a0,  4, 20019 

x64 

sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): 40 
status: c0000004, return len: 2647576 
status: 0, return len: 2647856 

      10294,    0, fffffa8006729b30,  4,  4 
    70000001fffff,    0, fffff8a00000dfa0,  4,  8 
    2300000002001f,    0, fffff8a000008eb0,  4,  c 
    30000000f000f,    0, fffff8a00000fca0,  4,  10 
    23000000000000,    0, fffff8a0000225b0,  4,  14 
    23000000020019,    0, fffff8a000098210,  4,  18 
    230000000f003f,    0, fffffa8006758e60,  4,  1c 
    240000001f0001,    0, fffff8a000098040,  4,  20 
    2300000002001f,    0, fffffa80067534e0,  4,  24 
    240000001f0001,    0, fffff8a00009c560,  4,  28 
    2300000002001f,    0, fffffa8006834620,  4,  2c 
    80000001fffff,    0, fffff8a000099250,  4,  30 
    230000000f003f,    0, fffff8a00009a7c0,  4,  34 
    230000000f003f,    0, fffff8a000095380,  4,  38 
    230000000f003f,    0, fffff8a000062d80,  4,  3c 
    230000000f003f,    0, fffff8a00015e580,  4,  40 
    23000000020019,    0, fffffa8006f3b940,  4,  44 
    700000000002a,    0, fffff8a00020da30,  4,  48 
    500000000000e,    0, fffff8a0007b07a0,  4,  4c 
    23000000000010,    0, fffff8a009af83a0,  4,  50 
+1

Questo è semplicemente eccellente. Stavo chiedendo un approccio generalmente migliore per trattare con i testimoni, ma ricevo risposte alla mia domanda più specifica. Non ero a conoscenza della versione estesa, grazie! – Abel