一、实验介绍
1.1 实验内容
木马程序会给普通用户带来很多危害,比如盗取QQ账号,游戏账号等。课程将用Python实现一个简易的木马程序,该程序会记录用户的键盘输入和屏幕截图并将数据发送到指定的服务器。通过分析键盘输入的数据,可以分析出root密码和其他账号的密码等等。
1.2 实验知识点
linux设备文件linux下Python多进程编程Python调用外部程序Python socket网络编程evdev库的使用Python实现键盘记录和
1.3 参考代码获取
你可以通过下面命令将代码下载到实验楼环境或者本地Linux环境中,作为参照对比进行学习。
二、实验原理
input子系统是linux kernel中与外部输入设备联系比较紧密的模块,例如我们的键盘设备会映射到/dev/input目录下的某个设备文件,由于键盘属于字符设备,所以我们可以将其当做普通的文件来操作(比如read、write)。通过不断的读取键盘设备文件,就可以完全获取到用户的键盘输入。注意该程序无法运行在windows和***cos系统下。
三、开发准备
首先打开xface, 安装实验所需要的第三方库evdev(linux下input输入子系统访问的api库)
然后安装命令行的截屏工具scrot
四、流程梳理
欢迎大家加入小编创建的Python行业交流群,有大牛答疑,有资源共享,有企业招人!是一个非常不错的交流基地!群号:683380553
4.1 记录键盘输入功能
键盘输入功能模块主要按照以下流程去设计与实现
找到/dev/input/目录下对应的键盘设备使用evdev库获取键盘记录的原始数据对原始数据进行解码处理加入到字符缓冲区在字符缓冲区冲处理Backspace、Left、Right等特殊按键操作将缓冲区中的内容通过socket套接字接口传输到远程服务器
由于运行在docker容器中的linux没有输入子系统,可以借助X11来记录键盘输入
详细文档可以参考。本文重点介绍基于Linux输入子系统的代码实现。
4.2 程序总体设计
程序主要分为两个大的功能:
键盘记录屏幕截图
可以看出这两个功能是完全不相关的,为了达到并行运行的效果,一半情况下采用
多线程技术,由于屏幕截图功能基于Python调用外部程序执行,运行期间会产生
一个子进程用来执行外部程序。所以我们直接采用多进程来实现。
五、实验步骤
5.1 屏幕截图
屏幕截图功能使用了Python调用外部程序技术,常用的库用subprocess、os.system,com***nds等,在这里我们使用了com***nds库,等多的用法可以参考 这篇博客。为了让大家对程序理解更深入,请根据注释中的提示完成相应的扩展功能作为练习。代码详情见screenshot.py,该代码可以直接执行。
5.2 键盘输入记录功能
主要按照4.1的流程来分析代码。
5.2.1 找到所有的键盘设备
/dev/input/目录下存在一些字符设备文件,通过对这些文件的读写和控制,
可以访问实际设备,更多资料可以参考这里。为了找到键盘设备,
需要了解linux的虚拟内存文件系统sysfs, 它挂在于/sys目录,它存储了系统内核和
设备驱动的实时信息,我们要找的键盘设备的信息可以在/sys/class/input目录
下找到,通过查看devices/name可以发现,该文件记录了设备的描述信息。更多关于设备文件和虚拟内存文件系统的知识可以参考这里。
在linux终端下执行下列命令(如linux运行在docker环境中无/dev/input目录,如发现/dev/input目录存在,请跳过此实验步骤或者在本地Linux环境下实验)
通过代码实现筛选键盘设备(代码详见keylogger/keyboard.py):
5.2.2 使用evdev获取键盘输入的数据
在这里我们使用evdev库来获取原始的键盘数据,在这里我们使用select库来**键盘的状态,若有输入时,readers返回键盘的文件描述符,evdev把键盘的输入转化为多个event对象。在这里只需要筛选类型为EV_KEY的键盘输入event对象即可。库的使用说明可以参考官方文档
5.2.3 解析evdev获取的原始数据
为了解析原始数据,使用了以下功能组件:
shift, caps按键的状态管理组件StatusManager扩展的event对象CurKeyEvent
在按键过程中,shift键和caps键会影响其他键效果(同时按下shift+’z’那么应该是’Z’),因此维护了一个StatusManager对象来管理shift和caps的状态,属性方法get_current_key可以根据当前的状态输出正确的字符结果。部分其他的按键,比如’,’如果同时按住shfit键那么按键的结果就是<,也是需要注意的地方,可参考get_current_key中的处理。
为了将原始数据对应到ascii码表的字符,我们需要建立一个映射字典:
为了简化程序,我们在这里不处理F1~12、Del等按不常用按键的处理,为此我们对按键进行分类,将这类按键划入到unvalidate。而一些特殊按键,比如f5等通过is_show进行过滤,用户可自行修改该方法过滤不需要的按键。
5.2.4 字符缓冲区处理Backspace, Left, Right特殊按键
当使用键盘输入时不可避免的会出错,那么我们会执行回退(Backspace)操作,当按下Backspace按键时上一次输入需要抹除掉,Left和Right操作会调到指定的位置进行输入。所以需要一个字符缓冲区来记录用户的输入以便处理上述情况。本程序中我们使用列表结构来作为缓冲区。这里一个要注意的地方就是hook_func参数,在Python中要改变传入的参数的值,那么需要传入列表或者是字典结构,这里使用列表来传值。该函数的作用是当程序终止记录键盘输入时,确保缓冲区的内容全部被发送出去。使用闭包来避免声明全局缓冲区变量。用户可根据注释里的提示完成扩展功能。
5.2.5 数据进行网络传输
根据前面的步骤我们已经获取我们所需要的屏幕截图和键盘输入的数据,接下来我们需要将这些数据发送到指定的服务器。在这里需要了解下Python的网络编程的相关知识。首先介绍服务端的编程的基本步骤:
建立一个socket套接字对象绑定这个套接字到服务器的ip和端口号设置最大链接数量接受客户端的链接与客户端进行通讯关闭相关资源
用Python实现的代码如下,这是一个最基本服务器的实现,该木马程序中的示例服务器也是基于这个模型进行的。
接下来的我们讨论客户端的实现,客户端的编程的基本模型比服务端要简单一些。只有两个步骤:
与服务器进行连接和服务器进行数据通讯
现在思考一下在这个木马程序中我们需要给服务器发送那些数据,很容易分析出我们需要传输<文件名,文件类型,文件的具体内容,结束标志>,为什么需要结束标志咧?因为客户端已经发送完数据了,需要通知服务器数据已经完成,可以断开连接了,这个时候客户端和服务器就能正常断开连接,将资源还给操作系统了。
现在我们开始思考如何实现客户端的功能,让我们再次梳理一下客户端的功能:
建立与服务器的连接发送文件名和文件类型(简称消息头部)发送文件的具体内容发送结束标志
在本程序中我们除了发送键盘输入数据外还有屏幕截图,因为这两个功能是并行执行的,所以这两类数据的发送不能共用同一个服务器连接(否则键盘数据和图像数据混合在一起就没法区分了)。本程序维护了一个服务器连接的类,
将每一次的数据发送抽象成一次网络任务,发送消息头部就相当于执行了一次网络任务。
5.2.6 运行程序
上述我们实现了键盘记录、截图功能、数据发送功能。根据4.2,在这里讲述下Python的多进程编程,将上述功能组合在一起实现并发运行。 Python下
的多进程编程常用的库是muptiprocessing,multiprocessing库提供了非常强大的功能,支持子进程、通讯和共享数据。 但因本程序限制在linux环境下,
所以使用更为轻量的os.fork来创建多进程程序。
接下来我们运行一下程序看一下实验效果。
开启键盘数据的服务
python server.py -p 8888
开启接收图片数据的服务
python server -p 8889
运行我们的主程序
python ***in.py
在程序运行期间,你可以在键盘上任意输入就可以进行记录了。运行效果如下,其中shot.png是服务器保存下来的屏幕截图,key.txt是键盘记录的数据。
def ***in(key_name, pic_name, key_type=’txt’, pic_type=’png’):
“””
因为捕捉键盘记录 和屏幕截图 是两个独立的任务,
所以在这里fork产生一个新的进程来执行屏幕截图
“””
f = os.fork()
if f == 0:
# 这里是子进程, 会调用外部程序
screen_shot(pic_name, pic_type)
else:
# 父进程
keylogger_func(key_name, key_type)
六 总结
基于Linux的设备管理相关知识和evdev库的使用,实现键盘记录,并详细介绍了缓冲区的处理方法和网络编程的相关知识。利用多进程编程实现
屏幕截图和键盘记录并发执行的效果。通过该项目的学习和实现,可以了解木马程序的基本结构和原理,加强对Linux的底层的了解,实践网络编程及相关应用。
本文来自水中明月投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/577087.html