elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Guía actualizada para evitar que un ransomware ataque tu empresa


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  Snippet para obtener handle de procesos
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Snippet para obtener handle de procesos  (Leído 1,447 veces)
Lekim

Desconectado Desconectado

Mensajes: 268



Ver Perfil
Snippet para obtener handle de procesos
« en: 21 Noviembre 2015, 06:18 »

Hola

Iré al grano, utilizando la función Process.GetProcesses() puedo obtener información del los procesos del sistema así como el Handle o el MainWindowHandle de la ventana principal de un proceso.

El problema es que en algunos casos  MainWindowHandle  devuelve 0

Recordé un viejo código de VB que tenía por ahí. Y tras un buen rato probando lo conseguí pasar a VB.NET, ya que usa APIs y si no se usa bien devuelve error o valores nulos.

Se necesita el ID de un proceso para obtener el handle principal, y dado que la clase  Process no devuelve valor nulo con los IDs obtengo todos los Handles en la lista.


Ahí va el code  ;):

////OBTENER HANDLE PROCESO////

Código
  1. #Region "Obtener Handle Proceso"
  2. Public Module modProcessHandle
  3.    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
  4.    Private Function FindWindow(ByVal lpClassName As String, _
  5.    ByVal lpWindowName As String) As IntPtr
  6.    End Function
  7.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  8.    Public Function GetParent(ByVal hWnd As IntPtr) As IntPtr
  9.    End Function
  10.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  11.    Private Function GetWindow(ByVal hWnd As IntPtr, _
  12.    ByVal wCmd As Integer) As IntPtr
  13.    End Function
  14.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  15.    Private Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
  16.    ByRef lpdwProcessId As Integer) As IntPtr
  17.    End Function
  18.  
  19.  
  20.    Public Function GetProcessHandle(ByVal ProcessId As Integer) As IntPtr
  21.        Dim HwndTemporal As IntPtr
  22.        Dim idProc As Integer = 0
  23.        Dim HWND As IntPtr = IntPtr.Zero
  24.        Const GW_HWNDNEXT = 2
  25.        HwndTemporal = FindWindow(Nothing, Nothing)
  26.        ' Loop hasta que encuentra una coincidencia o no hay más identificadores de ventana:
  27.        Do Until HwndTemporal = IntPtr.Zero
  28.            ' Comprueba que no tenga ninguna ventana 'Parent'
  29.            If GetParent(HwndTemporal) = IntPtr.Zero Then
  30.                GetWindowThreadProcessId(HwndTemporal, idProc)
  31.                If ProcessId.Equals(idProc) Then
  32.                    HWND = HwndTemporal 'Devuelve el handle encontrado
  33.                    Return HWND
  34.                    Exit Do ' Salir de bucle
  35.                End If
  36.            End If
  37.            idProc = 0
  38.            'Siguiente identificador de ventana
  39.            HwndTemporal = GetWindow(HwndTemporal, GW_HWNDNEXT)
  40.        Loop
  41.        Return HWND
  42.    End Function
  43.  
  44. End Module
  45. #End Region


Aquí un ejemplo de como usarlo para obtener una lista con los procesos en ejecución sus handles y su Class Name.


Código
  1. Option Strict On
  2. Option Explicit On
  3. Imports System.Runtime.InteropServices
  4. Imports System.Text
  5.  
  6. Public Class Form1
  7.    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
  8.    Private Shared Function GetClassName(ByVal hWnd As IntPtr, _
  9.   ByVal lpClassName As System.Text.StringBuilder, _
  10.   ByVal nMaxCount As Integer) As Integer
  11.    End Function
  12.    Dim ClassName As StringBuilder = New StringBuilder(256)
  13.    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  14.        ListView1.Columns.Add("Name", 100)
  15.        ListView1.Columns.Add("MainHandle", 100)
  16.        ListView1.Columns.Add("ClassName", 200)
  17.        ListView1.Columns.Add("MainHandle", 100)
  18.        ListView1.Columns.Add("ClassName", 200)
  19.        ListView1.View = View.Details
  20.        ListView1.FullRowSelect = True
  21.        'Recorre los procesos y agrega la información al ListView
  22.        For Each Proceso In Process.GetProcesses()
  23.            Dim Handle As IntPtr = modProcessHandle.GetProcessHandle(Proceso.Id)
  24.            If Handle <> IntPtr.Zero Then
  25.                'Nombre Proceso
  26.                ListView1.Items.Add(Proceso.ProcessName)
  27.  
  28.                'MainWindowHandle
  29.                ListView1.Items(ListView1.Items.Count - 1).SubItems.Add _
  30.                    (Conversion.Hex(Proceso.MainWindowHandle.ToInt32))
  31.                'ClassName
  32.                ClassName.Clear()
  33.                GetClassName(CType(Proceso.MainWindowHandle.ToInt32, IntPtr), ClassName, ClassName.Capacity)
  34.                ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(ClassName.ToString)
  35.  
  36.                'MainWindowHandle
  37.                ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(Conversion.Hex(CInt(Handle)))
  38.                'ClassName
  39.                ClassName.Clear()
  40.                GetClassName(Handle, ClassName, ClassName.Capacity)
  41.                ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(ClassName.ToString)
  42.  
  43.            End If
  44.        Next
  45.    End Sub
  46.  
  47.    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  48.  
  49.    End Sub
  50. End Class
  51. #Region "Obtener Handle Proceso"
  52. Public Module modProcessHandle
  53.    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
  54.    Private Function FindWindow(ByVal lpClassName As String, _
  55.    ByVal lpWindowName As String) As IntPtr
  56.    End Function
  57.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  58.    Public Function GetParent(ByVal hWnd As IntPtr) As IntPtr
  59.    End Function
  60.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  61.    Private Function GetWindow(ByVal hWnd As IntPtr, _
  62.    ByVal wCmd As Integer) As IntPtr
  63.    End Function
  64.    <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
  65.    Private Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
  66.    ByRef lpdwProcessId As Integer) As IntPtr
  67.    End Function
  68.  
  69.  
  70.    Public Function GetProcessHandle(ByVal ProcessId As Integer) As IntPtr
  71.        Dim HwndTemporal As IntPtr
  72.        Dim idProc As Integer = 0
  73.        Dim HWND As IntPtr = IntPtr.Zero
  74.        Const GW_HWNDNEXT = 2
  75.        HwndTemporal = FindWindow(Nothing, Nothing)
  76.        ' Loop hasta que encuentra una coincidencia o no hay más identificadores de ventana:
  77.        Do Until HwndTemporal = IntPtr.Zero
  78.            ' Comprueba que no tenga ninguna ventana 'Parent'
  79.            If GetParent(HwndTemporal) = IntPtr.Zero Then
  80.                GetWindowThreadProcessId(HwndTemporal, idProc)
  81.                If ProcessId.Equals(idProc) Then
  82.                    HWND = HwndTemporal 'Devuelve el handle encontrado
  83.                    Return HWND
  84.                    Exit Do ' Salir de bucle
  85.                End If
  86.            End If
  87.            idProc = 0
  88.            'Siguiente identificador de ventana
  89.            HwndTemporal = GetWindow(HwndTemporal, GW_HWNDNEXT)
  90.        Loop
  91.        Return HWND
  92.    End Function
  93.  
  94. End Module
  95. #End Region


Como demostración he hecho que se muestre en una columna los handles obtenidos con la clase Process y otra columna con los handles obtenidos con el snippet. Se puede ver que con algunos procesos ocultos, es decir no son visibles, se devuelve valor 0, pero con el snippet se obtiene el handle sin problemas. Además se obtienen los nombres de clase (ClassName) que sin los Handles de las ventanas no es posible obtenerlos. Por lo menos que yo sepa.

La primera columna ClassName se obtiene con MainWindowHandle del Procces. La segunda columna ClassName se obtiene con los handles obtenidos con el snippet.


Si hay otra forma más sencilla, decídmelo  :-*


El código original VB6 está en el siguiente enlace:
CodeVB

Espero que os sirva...

Saludos


« Última modificación: 21 Noviembre 2015, 15:58 por Lekim » En línea

Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 9.709



Ver Perfil
Re: Snippet para obtener handle de procesos
« Respuesta #1 en: 25 Noviembre 2015, 16:03 »

Es útil, funciona muy bien hasta donde lo he testeado.

Yo uso la parte importante del código que has mostrado (función GetProcessHandle) para obtener el hwnd de la ventana principal de un proceso para cambiar la visibilidad de dicha ventana mediante la función Win32 ShowWindow.

saludos


« Última modificación: 25 Noviembre 2015, 16:11 por Eleкtro » En línea


Lekim

Desconectado Desconectado

Mensajes: 268



Ver Perfil
Re: Snippet para obtener handle de procesos
« Respuesta #2 en: 25 Noviembre 2015, 17:18 »

Es útil, funciona muy bien hasta donde lo he testeado.

Yo uso la parte importante del código que has mostrado (función GetProcessHandle) para obtener el hwnd de la ventana principal de un proceso para cambiar la visibilidad de dicha ventana mediante la función Win32 ShowWindow.

saludos

Hola
Si te soy sincero,  como conoces Net mucho más que yo pensé mostrarías una de tus perlas usando código Net para hacer lo mismo. Por eso dejé la coletilla:

Código:
Si hay otra forma más sencilla, decídmelo

Y si no tu otro/a. XD

Claro que no me refiero a reducir el código,  sino al uso de alguna otra clase distinta a Process, u otra función.

No entiendo porqué con la clase Process sólo se obtengan los handles de unos pero de otros no.

sl2s
« Última modificación: 25 Noviembre 2015, 17:25 por Lekim » En línea

Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 9.709



Ver Perfil
Re: Snippet para obtener handle de procesos
« Respuesta #3 en: 25 Noviembre 2015, 18:01 »

Si te soy sincero,  como conoces Net mucho más que yo pensé mostrarías una de tus perlas usando código Net para hacer lo mismo. Por eso dejé la coletilla:

Si hay otra forma más sencilla, decídmelo

Claro que no me refiero a reducir el código,  sino al uso de alguna otra clase distinta a Process, u otra función.

Hombre, con las classes de Windows UI Automation se puede reemplazar todo ese p/invoking de tu código para hacer practicamente cualquier tipo de Spy y automación en las ventanas, pero hay un gran problema, UI Automation descarta las ventanas ocultas así que la única manera posible que se me ocurre para obtener el hwnd de una ventana OCULTA sería mediante código no administrado, como ya has mostrado. Para todo lo demás puedes usar Windows UI Automation.

Edito:
Te muestro un ejemplo que simularia la función Process.GetProcessById para obtener una representación del proceso (o mejor dicho de la ventana) y así el hwnd de la ventana:

Código
  1. Dim p As New Process
  2.  
  3. p.StartInfo = New ProcessStartInfo() With {
  4.     .WindowStyle = ProcessWindowStyle.Normal,
  5.     .FileName = "notepad"
  6. }
  7.  
  8. p.Start()
  9. p.WaitForInputIdle()
  10.  
  11. Dim window As AutomationElement =
  12.    AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
  13.                                            New PropertyCondition(AutomationElement.ProcessIdProperty, p.Id))
  14.  
  15. Dim hwnd As IntPtr = New IntPtr(window.Current.NativeWindowHandle)

Yo según que cosas prefiero utilizar la API de Windows, ya que el manejo de UI Automation se puede volver demasiado tedioso.



No entiendo porqué con la clase Process sólo se obtengan los handles de unos pero de otros no.

Si vieras detenidamente el código fuente de la class process de .Net framework lo entenderías (la referencia online u offline del código fuente), simplemente se devuelve un handle nulo (IntPtr.Zero) a cualquier ventana que esté oculta, ahora, el "por qué" ...¿quien sabe?, probablemente serán cuestiones de diseño de Microsoft, al igual que UI Automation no trabaja con ventanas ocultas quien sabe por qué (cuando perfectamente podría, ya que la API de Windows puede), algún motivo tendrán, digo yo.

Saludos
« Última modificación: 25 Noviembre 2015, 18:51 por Eleкtro » En línea


Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines