Captura Teclas / Keylogger en C# independiente del foco de la aplicación


Este es un capturador de teclas independiente de si la aplicación tiene el foco o no. Trabaja en modo consola, pero puede adaptarse a diversas necesidades.

using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace atrapateclas
{
    class Program
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        static void Main(string[] args)
        {
            _hookID = SetHook(_proc);
            Application.Run();
            UnhookWindowsHookEx(_hookID);
        }

        private static 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 static IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
            //if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                //if (Keys.C == (Keys)vkCode && Keys.Control == Control.ModifierKeys)
                //verifico que se presione CTRL + F1:
                if (Keys.F1 == (Keys)vkCode && Keys.Control == Control.ModifierKeys)
                    Console.WriteLine((Keys)vkCode);
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

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

 

regsvr32 on a 64 bit platform


Resulta que tengo una aplicación desarrollada en C# para un dispositivo de lectura de huellas dactilares FP200 de Wison Tecnologies. Este dispositivo viene con una librería (DLL) COM precompilada que es necesario registrar en el sistema operativo huésped a fin de poder acceder al dispositivo.

En plataformas de 32 bits, este registro lo realizaba siempre con el viejo y no tan querido regsvr32. En las nuevas plataformas de 64 bits, no me fué tan bien.

En principio hay que aclarar: en los sistemas operativos Microsoft (w7) de 64 bits hay dos versiones del regsvr32, una en \windows\system32 y otra en \windows\sysWOM64. La de system32 es para 64 bits y la de sysWOM64 es para 32 bits.

Debemos tratar de registrar nuestra librería con la aplicación y en el directorio correcto a fin de que funcione, de otra manera tendremos grandes dolores de cabeza.

Por otro lado, habiendo registrado la librería en alguno de los dos directorios mencionados, en mi caso, tuve que recompilar los ejecutables, indicando plataforma destino “x86” en vez de “Any CPU” ó “x64”.

Ojo al abrir la ventana de DOS “cmd.exe” que debe abrirse con permisos de administrador, sinó no podremos registrar la DLL.

Espero que esto sea de utilidad a los que se encuentren con este problema.

Redirigir la salida estandard en C#


Como hacemos para redirigir la salida estandard de un programa en C# generada por el comando Console.Writeln ?

Acá va:

//stringwriter para manejo de mensajes/salida console.writeln
private System.IO.StringWriter sw = new System.IO.StringWriter();
private void btnPrueba_Click(object sender, EventArgs e){
    Console.SetOut(sw);
    Console.WriteLine("Esto es una prueba");
    MessageBox.Show("el resultado esta almacenado en la variable sw = " + this.sw.ToString());
}

C# tcp listener multithreading / multiple connections


Hace un tiempo “el negro” me había pedido el tcp listener modo consola… ahora necesitaba una mejora para que acepte multiples conecciones, dado que el anterior, solo aceptaba una.
No pude encontrar nada concreto que funcionara en la web, asi que me tuve que poner a hacer el trabajo pesado: un rejunte de código para obtener un tcp listener multithreading.
El resultado es este:

Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace tcplistener_console
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.Write(“tcplistener by hvivani – 20110225 – para el negro: \r\n”);
            if (args.Length == 0)
            {
                System.Console.WriteLine(“Parametros: Puerto IP   \r\n”);
                System.Console.WriteLine(“Ejemplo: tcplistener 2525 127.0.0.1  \r\n”);
                System.Console.WriteLine(“si tenes mas de una interfaz de red, usa la ip de dicha interfaz.  \r\n”);
                return 1;
            }
            else
            {
                multicnnNew.iniciar(args[0], args[1]);
                return 0;
            }

        } 
    }
}


multicnnNew.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace tcplistener_console
{
    public class multicnnNew
    {
        // Thread signal.
        public static ManualResetEvent clientConnected = new ManualResetEvent(false);

        public static void iniciar(string puerto, string addr)
        {
            IPAddress localAddr = IPAddress.Parse(addr);
            TcpListener server = new TcpListener(localAddr, int.Parse(puerto));
            server.Start();

            server.BeginAcceptTcpClient(AcceptCallback, server);
            clientConnected.WaitOne();
        }

        private static void AcceptCallback(IAsyncResult ar)
        {
            TcpListener server = (TcpListener)ar.AsyncState;
            ClientState state = new ClientState();

            // Once the accept operation completes, this callback will
            // be called.  In it, you can create a new TcpClient in much
            // the same way you did it in the synchronous code you had:

            state.client = server.EndAcceptTcpClient(ar);

            // We’re going to start reading from the client’s stream, and
            // we need a buffer for that:

            state.buffer = new byte[4096];

            // Note that the TcpClient and the byte[] are both put into
            // this “ClientState” object.  We’re going to need an easy
            // way to get at those values in the callback for the read
            // operation.

            // Next, start a new accept operation so that we can process
            // another client connection:

            server.BeginAcceptTcpClient(AcceptCallback, server);

            // Finally, start a read operation on the client we just
            // accepted.  Note that you could do this before starting the
            // accept operation; the order isn’t really important.

            state.client.GetStream().BeginRead(state.buffer, 0, state.buffer.Length, ReadCallback, state);
        }

        private static void ReadCallback(IAsyncResult ar)
        {
            ClientState state = (ClientState)ar.AsyncState;
            int cbRead = state.client.GetStream().EndRead(ar);

            if (cbRead == 0)
            {
                // The client has closed the connection
                return;
            }
            //else
            //{
                //Console.WriteLine(“hay datos”);
            //}

            // Your data is in state.buffer, and there are cbRead
            // bytes to process in the buffer.  This number may be
            // anywhere from 1 up to the length of the buffer.
            // The i/o completes when there is _any_ data to be read,
            // not necessarily when the buffer is full.

            // So, for example:

            string strData = Encoding.ASCII.GetString(state.buffer, 0, cbRead);
            Console.WriteLine(strData);

            // For ASCII you won’t have to worry about partial characters
            // but for pretty much any other common encoding you’ll have to
            // deal with that possibility, as there’s no guarantee that an
            // entire character will be transmitted in one piece.

            // Of course, even with ASCII, you need to watch your string
            // terminations.  You’ll have to either check the read buffer
            // directly for a null terminator, or have some other means
            // of detecting the actual end of a string.  By the time the
            // string goes through the decoding process, you’ll have lost
            // that information.

            // As with the accept operation, we need to start a new read
            // operation on this client, so that we can process the next
            // bit of data that’s sent:

            state.client.GetStream().BeginRead(state.buffer, 0, state.buffer.Length, ReadCallback, state);
        }
    }
}

ClientState.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace tcplistener_console
{
    public class ClientState
    {
        public TcpClient client;
        public byte[] buffer;
    }
}

Estas son las clases necesarias para crear un proyecto en modo consola.
y, como diría “el negro”: 
SALUTE !

C# tcp listener modo consola


Acá va un ejemplo sencillo de un tcplistener  en C# modo consola a pedido de Matias – el negro 🙂

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace tcplistener_console
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.Write(“tcplistener by hvivani – 20110225 – para el negro: \r\n”);
            if (args.Length == 0)
            {
                System.Console.WriteLine(“Parametros: Puerto IP   \r\n”);
                System.Console.WriteLine(“Ejemplo: tcplistener 2525 127.0.0.1  \r\n”);
                System.Console.WriteLine(“si tenes mas de una interfaz de red, usa la ip de dicha interfaz.  \r\n”);
                return 1;
            }

            TcpListener server = null;
            // Set the TcpListener on port.
            Int32 port = int.Parse(args[0]);
            IPAddress localAddr = IPAddress.Parse(args[1]);

            // TcpListener server = new TcpListener(port);
            server = new TcpListener(localAddr, port);

            // Start listening for client requests.
            server.Start();

            // Buffer for reading data
            Byte[] bytes = new Byte[256];
            String data = null;

            // Enter the listening loop.
            while (true)
            {
                Console.Write(“Waiting for a connection… “);

                // Perform a blocking call to accept requests.
                // You could also user server.AcceptSocket() here.
                TcpClient client = server.AcceptTcpClient();
                Console.WriteLine(“Connected!”);

                data = null;

                // Get a stream object for reading and writing
                NetworkStream stream = client.GetStream();

                int i;

                // Loop to receive all the data sent by the client.
                while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    // Translate data bytes to a ASCII string.
                    data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                    Console.WriteLine(“Received: {0}”, data);

                    // Process the data sent by the client.
                    data = data.ToUpper();

                    byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);

                    // Send back a response.
                    //stream.Write(msg, 0, msg.Length);
                    //Console.WriteLine(“Sent: {0}”, data);
                }

                // Shutdown and end connection
                client.Close();
                }

        } 
    }
}