2016-09-20 20 views
2

Информация:C# Получить список дескрипторов, AcessViolationException

  • .Net 4,5

Проверено на:

  • Win7 64 бит

  • Win10 64 бит (Virtual Box)

Я пытаюсь получить список дескрипторов внешнего процесса и вернуть их имена в виде строки, чтобы впоследствии я мог закрыть конкретный. Поэтому я написал эту функцию с помощью WIN32API, который будет проверять, если ручка ручка я хочу, чтобы закрыть: `

 const int CNST_SYSTEM_HANDLE_INFORMATION = 16; 
     const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; 

     public static string getObjectTypeName(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process) 
     { 
      IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id); 
      IntPtr ipHandle = IntPtr.Zero; 
      var objBasic = new Win32API.OBJECT_BASIC_INFORMATION(); 
      IntPtr ipBasic = IntPtr.Zero; 
      var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION(); 
      IntPtr ipObjectType = IntPtr.Zero; 
      IntPtr ipObjectName = IntPtr.Zero; 
      string strObjectTypeName = ""; 
      int nLength = 0; 
      int nReturn = 0; 
      IntPtr ipTemp = IntPtr.Zero; 


      if (!Win32API.DuplicateHandle(m_ipProcessHwnd, shHandle.Handle, 
              Win32API.GetCurrentProcess(), out ipHandle, 
              0, false, Win32API.DUPLICATE_SAME_ACCESS)) 
       return null; 



      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); 

      ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength); 
      nLength = objBasic.TypeInformationLength; 
      while ((uint)(nReturn = 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()); 
      if (Is64Bits()) 
      { 
       ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32); 
      } 
      else 
      { 
       ipTemp = objObjectType.Name.Buffer; 
      } 

     strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1); 


     Marshal.FreeHGlobal(ipObjectType); 
      Win32API.CloseHandle(ipHandle); 
      return strObjectTypeName; 
     }` 

Проблема однако в том, что этот код работает в Win7 64bit, а не в Win10! -> В Win 10 strObjectTypeName = Marshal.PtrToStringUni(); бросает AcessViolationException (Последние несколько строк в коде)

System.AccessViolationException Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Я пропустил что-то здесь о том, как доступ к неуправляемой памяти в win10?

ответ

0

Я только что столкнулся с той же проблемой. Я не пробовал Win7, но когда вы запускаете код на Win10 (x64) как 32-битный (например, установите «Предпочитаете 32-битный флаг» вашего приложения), он должен работать. Когда произойдет исключение, перетащите & в переменную «ipTemp» в «окно памяти» Visual Studio, если в ней отображаются только вопросительные знаки или сообщение об ошибке, у вас нет действительного указателя. Насколько я понял, в 64-битных версиях структур, используемых этим API, есть (более) байты заполнения: OBJECT_TYPE_INFORMATION содержит UNICODE_STRING, а UNICODE_STRING имеет 4 байта заполнения до поля Buffer в режиме 64 бит. Моего workaraound был таким:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct UNICODE_STRING 
{ 
    private IntPtr _dummy; // the two ushorts seem to be padded with 4 bytes in 64bit mode only 

    /// <summary> 
    /// The length, in bytes, of the string stored in Buffer. If the string is null-terminated, Length does not include the trailing null character. 
    /// </summary> 
    public ushort Length 
    { 
     get { return (ushort)Marshal.ReadInt16(this, 0); } 
    } 

    /// <summary> 
    /// The length, in bytes, of Buffer. 
    /// </summary> 
    public ushort MaximumLength 
    { 
     get { return (ushort)Marshal.ReadInt16(this, 2); } 
    } 

    public IntPtr Buffer; 
} 

В ходе моих исследований я нашел очень много вопросов по этой теме и в основном два вида образца кода , скопированных по всему Интернету, что я рассматриваю, чтобы создать с открытым исходным кодом библиотеки WinKernelObjectsDotNet.

Обновление: теперь доступна библиотека here. Он поддерживает поиск процесса, который блокирует файл или последовательный порт (COM) с помощью одной строки кода.