[APORTE] Hook global de teclado (sin DLL) VB .NET

Iniciado por kub0x, 26 Marzo 2012, 22:52 PM

0 Miembros y 1 Visitante están viendo este tema.

kub0x

Buenas .NET(adictos),

he observado que por este foro circulan peticiones de usuarios que desean introducirse en el mundo del hooking en Windows y he decidido codear una breve aplicación, comentada al detalle para su buen entendimiento y poder comprender las nociones básicas del Hooking.

La verdad que aprendí hace unos 2 días, me puse en C a codearlo pero .NET me tira más, ya después de leer la documentación de MSDN (abajo os dejo el link) y utilizar un poquito (la Web) Pinvoke para declarar las funciones del API ya pude completar el programa.

El programa simplemente establece un Hook de tipo LowLevelKeyBoard, captura las teclas interceptadas por el hook y finalmente las guarda una a una en un fichero de la carpeta actual.

Link Documentacion Hooks-> http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx

Como no, comparto con vosotros el Source del programa. Está codeado bajo el Framework 4.0 y desarrollado en Visual Basic .NET (VS 2010)

Link de descarga -> http://www.mediafire.com/?4fbdmx5obwu5k10

Source:

Código (VB.NET) [Seleccionar]

Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Threading
Imports System.Windows.Forms
Public Class Form1
   Enum Constantes As Integer
       WH_KEYBOARD_LL = 13
       HC_ACTION = 0
       WM_KEYDOWN = &H100
       WM_KEYUP = &H101
       WM_SYSKEYDOWN = &H104
       WM_SYSKEYUP = &H105
   End Enum '-> Constantes utilizadas en el Hook Global
   <StructLayout(LayoutKind.Sequential)> _
   Public Class KBDLLHOOKSTRUCT
       Public vkCode As UInt32
       Public scanCode As UInt32
       Public flags As UInt32
       Public time As UInt32
       Public dwExtraInfo As UIntPtr
   End Class '-> Estructura que contiene los mensajes interceptados por el Hook
#Region "Declaraciones_API"
   <DllImport("user32.dll")> _
   Friend Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As Integer
   End Function

   <DllImport("user32.dll")> _
   Friend Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As KBDLLHOOKSTRUCT) As Integer
   End Function
   <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
   Public Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr
   End Function
   <DllImport("user32.dll", SetLastError:=True)> _
   Public Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
   End Function
#End Region '-> Declaraciones de APIs para el uso de Hooks (SetWindowsHookEx...)
   Enum HookType As Integer
       WH_JOURNALRECORD = 0
       WH_JOURNALPLAYBACK = 1
       WH_KEYBOARD = 2
       WH_GETMESSAGE = 3
       WH_CALLWNDPROC = 4
       WH_CBT = 5
       WH_SYSMSGFILTER = 6
       WH_MOUSE = 7
       WH_HARDWARE = 8
       WH_DEBUG = 9
       WH_SHELL = 10
       WH_FOREGROUNDIDLE = 11
       WH_CALLWNDPROCRET = 12
       WH_KEYBOARD_LL = 13
       WH_MOUSE_LL = 14
   End Enum '-> Tipos de Hooks para monitorizar mensajes
   'Declaramos un delegado y le asignamos sus respectivos argumentos
   Delegate Function HookProc(ByVal code As Integer, ByVal wParam As IntPtr, ByVal lParam As KBDLLHOOKSTRUCT) As Integer
   Private CallbackDelegate As HookProc = Nothing
   'Declaramos la variable Hook. Será la encargada de almacenar la direccion de memoria del Hook
   Dim hook As IntPtr = IntPtr.Zero
   'Procedimiento asociado al puntero AddressOf(CallBackDelegate)
   Private Function HookprocHandler(ByVal code As Integer, ByVal wParam As IntPtr, ByVal lParam As KBDLLHOOKSTRUCT) As Integer
       Try
           'Code es la variable encargada de decir si existe un mensaje. Si code !=0 no habra nada.
           If (code < 0) Then
               'Damos paso al siguiente Hook y procedemos con el continuamiento del Sistema
               Return CallNextHookEx(IntPtr.Zero, code, wParam, lParam)
           Else
               Dim sr As New StreamWriter(CurDir() & "\log.txt", True)
               'Segun el código devuelto a la pulsación de la tecla (257,258)
               Select Case wParam
                   Case Constantes.WM_KEYDOWN, Constantes.WM_SYSKEYDOWN
                       Dim key As Char = ChrW(lParam.vkCode) 'Imprimimos el caracter ASCII en pantalla
                       sr.Write(key)
               End Select
               sr.Close()
               Return CallNextHookEx(IntPtr.Zero, code, wParam, lParam)
           End If
       Catch ex As Exception
       End Try
       Return 1
   End Function
   Private Sub Iniciar_Hook()
       Try
           'Asociamos a dicho procedimiento un puntero hacia el controlador del Hook (HookProcHandler)
           CallbackDelegate = New HookProc(AddressOf HookprocHandler)
           If hook <> 0 Then
               'Desinstalamos el Hook
               UnhookWindowsHookEx(hook)
               hook = IntPtr.Zero
               btn_hook.Text = "Hookear Teclado"
           Else
               'Instalamos un Hook Global (LowLevelKeyBoard) y llamamos a la funcion HookProcHandler
               'Los ultimos dos parametros indican el HINSTANCE y PID, se utilizarian en caso de Hook local _
               'empleados en juegos y demás.
               hook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, CallbackDelegate, 0, 0)
               btn_hook.Text = "Desinstalar Hook"
               FileSystem.Kill(CurDir() & "\log.txt")
           End If
       Catch ex As Exception
       End Try

   End Sub
   Private Sub btn_hook_Click(sender As System.Object, e As System.EventArgs) Handles btn_hook.Click
       Iniciar_Hook()
   End Sub
End Class


Espero que os haya gustado el aporte. Cualquier duda que pueda surgir con el tema posteadla aquí, no olvideis que esto es lo más básico, los hooks tienen muchísimo juego.

Un Saludo ;)
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


Maurice_Lupin

Buen aporte, no hay muchos ejemplos del uso de la API en vb.net, esa web de pinvoke a mi tambien me ha ayudado mucho, pero lo malo es que la mayoria de ejemplos estan en C#, lo bueno es que el sharpdevelop convierte proyectos de C# a vb  ;D

Saludos.
Un error se comete al equivocarse.

kub0x

#2
Cita de: Maurice_Lupin en 11 Abril 2012, 14:52 PM
Buen aporte, no hay muchos ejemplos del uso de la API en vb.net, esa web de pinvoke a mi tambien me ha ayudado mucho, pero lo malo es que la mayoria de ejemplos estan en C#, lo bueno es que el sharpdevelop convierte proyectos de C# a vb  ;D

Saludos.

Gracias por tu comentario :) La verdad es que encontré bastantes ejemplos para .NET pero no tenía ni papa (entonces) sobre APIs :D Por cierto, lo probé junto a un par de módulos más en XP y no funciona.. También por lo que he leído sobre Hooks a bajo nivel de teclado, éstos no son recomendables emplearlos en Win7 (me funciona de maravilla).

Recomiendan el uso de Raw Input, cada uno verá como rinde su app junto con los hooks. Sobre todo porque no funciona en XP, pues ni idea, quizá deba implementarlo de diferente manera.

Saludos.
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate