Key Stroke Logger
|
#define _WIN32_WINNT 0x0400
#include <windows.h>
MSG m;HINSTANCE h;HHOOK k;char aa[100];KBDLLHOOKSTRUCT o;int i,key;
__declspec(dllexport) __w64 __stdcall zzz(int code,unsigned int w,long l)
{
KBDLLHOOKSTRUCT *o1;
o = *((KBDLLHOOKSTRUCT*)l);
key = o.scanCode << 16;
key += o.flags << 24;
GetKeyNameText(key,aa,100);
printf("%s Code=%d w=%x ScanCode=%d Flags=%d vkCode=%d Time=%d \n",aa,code,w,o.scanCode,o.flags,o.vkCode,o.time);
return CallNextHookEx(k,code,w,l);
}
int main()
{
h = GetModuleHandle(0);
printf("%x\n",h);
k = SetWindowsHookEx (WH_KEYBOARD_LL,zzz,h,0); //WH_KEYBOARD_LL=13
while (GetMessage(&m,0,0,0))
DispatchMessage( &m );
}
We are writing a program called a keystroke logger. This
program will log every keystroke that you press in any application under
windows. We first start with a function GetModuleHandle. This function returns
a value of 400000. Each time you load a program under Windows, it is loaded at
a virtual address of 0x40000.
As an experiment write a program using WinMain and not
main. The first parameter to the function WinMain is a number that tells you
where your program is loaded in memory and is always 0x400000. This number is a
handle to your application and it is here that windows loads your exe file or
dll.
The first two bytes will be M and Z. Normally we pass the
name of the module but if we pass 0 as in our case, it means the program
actually running.
The function SetWindowsHookEx is the most important
function in the above code. This is the
function that windows gives us so that we can hook different type of
activities. The first parameter is the type of
hook we are interested in.
There are 15 types of hooks we can capture ranging from
mouse to keyboard or shell etc. The macro WH_KEYBOARD is to be used for older
windows versions. The macro WH_KEYBOARD_LL is for Windows Nt upwards and
captures all low level keyboard messages.
The second parameter is the address of the function to be
called each time there is in our case a key pressed on the keyboard in our case
function zzz. The third parameter is the handle of the dll that contain the
function zzz. This function zzz normally resides in a dll.
We would have used the function LoadLibrary to load the
dll in memory and passed the return value of that function as this parameter.
The last parameter would be 0 as this is the thread id of the thread that we
want to hook ourselves to. By specifying 0 we are saying hook keyboard events
for all threads.
At the end of this function call, anytime anyone presses
a key, the function zzz will get called.
The function GetMessage waits for a message and till it
does not get one it sleeps on the job and lets windows do other work for other
applications. When it receives message it stores it in the MSG structure m and
returns non zero.
A message would be a key stroke, a mouse movement, a
window wanting to be repainted. Any activity in the windows world is a message.
As an aside when the function GetMessage
receives a WM_QUIT message it will return 0. The DispatchMessage
actually send the message to a windows procedure that we registered when we
created the window.
In our case there is no window created by the function
CreateWindow. When we press ctrl-C we will quit out of the while loop and the
program. Normally we would at the end of program use a function
UnhookWindowsHookEx function.
Let us now move to the function that does gets called
each time we press a key under windows. This function zzz takes three
parameters. The first parameter is normally 0, the second parameter is normally
0x100 which means a key is pressed or 0x101 when a key is released.
This function zzz gets called twice, once for a key press and once for a key release. When we keep a key pressed, the value is 0x100 or WM_KEYDOWN. The last parameter is a pointer to a structure KBDLLHOOKSTRUCT.
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
This structure has a member scanCode that contains the
scan code of each key pressed. This scan code is different from the ASCII
value. The scan code depends upon the physical layout of the key on the
keyboard. Thus the key a has a scan
code of 30, s 31 and d 32.
The flag member is to read as individual bits. The first
bit tells us whether it is a extended key like the insert or home key. The bits
1-3 are reserved. The 5 bit tells us if the ALT key was pressed and the 7th or
last bit the transition state 0 if pressed, 1 if released.
Thus we press the A key, the flags are 0, when we release
the 7th is 1, hence flags are 128. When we press the Insert key, bit 0 is 0n
and hence the values are 1 and 129. When we press the ALT key, the value of the
flags is 32.
The vkCode member is defined in the header file
winuser.h. Normally it is the ascii value of the key pressed. For the special
keys we have a large number of hash defines like
#define VK_HOME 0x24
The last member time is the time in milliseconds when we
pressed a key. We would to display the key pressed not as a number but as a
character. Thus the backspace key we want displayed as backspace.
We have been given a function GetKeyNameText that takes
an array as the second parameter, the length as the third. The array gets
filled up with a textual representation of the name. The first parameter is a
little complex to understand. We have to pass it the scan code in bits 16 to
23, in bit 24 the extended flags bit.
In bit 25, the do not care bit which lets us distinguish
between keys like left and right shift which appear twice on the keyword. Thus
we take the scan code and shift it 16 bits to the left to occupy bits 16 to 23.
We then take the flags bit and left shift it 24 bits to the left.
We then display all the variables and call the
CallNextHookEx function passing it our hook id, and the three parameters code,
w and l. If we do not do this other
hooks will not get the key. If we return 1, we are telling the system not to
pass this key to the other applications.
Thus we have the option of seeing to it that the
application that should have received the key does not. A value of 0 means pass
it on. We are also not allowed to modify the key as it goes over to the final
application.