基于Python实现主机远程控制
目录
- 1.概要设计
- 2.详细设计
- 2.调试分析
- 3.测试结果
前言:
本文为 HITwh 网络空间安全专业网络空间安全设计与实践 I 的选题之一,主要实现了远程监控局域网内的主机桌面与网络情况、简单键鼠控制、远程断网(ARP 攻击)、数据加密传输等功能。由于本文是由 Word 直接复制到 Typora 中生成的,尽管经过了简单的修改,但仍不能保证所有格式都正确,且很多图片模糊不清,暂时没有办法解决。如果有需要,请在文章末尾请我喝杯奶茶后发邮件告知我,我将把原 Word 文档以邮件形式发给您;或者您也可以直接加我的微信。
1.概要设计
本次设计为远程控制主机,我选择的远程主机为 windows 10 虚拟机(运行在 VMWare Workstation Pro 16 中)。系统环境为 Windows 10,使用语言为 python,版本 3.9,编程软件为 VS Code。
主要功能包括:图形化界面,视频监控,鼠标键盘远程控制,记录监控时长,监控硬件资源使用,监控网络活动,中断网络访问等。为了更好的性能,还需要使用多线程模型。
功能结构图如图 1 所示:
图形化界面由 pyqt5
实现,程序运行后,会启动主界面(图形界面一),然后阻塞,等待用户操作。在该界面上,用户可以输入目标主机 IP,然后开启视频监控线程、硬件资源使用监控线程和监控时长记录线程,其中前两个线程都需要使用 socket 通信。视频监控线程需要不断接收目的主机发来的数据包,将数据包的内容转换成相应的图片,然后显示在主界面上;硬件资源使用监控线程需要在另一个 socket 上接收目标主机发来的 CPU 使用率、内存使用率以及总内存等硬件资源信息,然后将其格式化后显示在主界面;监控时长记录线程需要记录当前视频监控的时长,格式化后将其显示在主界面。键鼠控制我放在了主线程,当用户在视频界面点击某个位置时,将记录点击坐标,并根据缩放比例转换成目标主机桌面的坐标,然后将相应的键鼠操作用整数表示,和坐标一起发送给目标主机,目标主机接收后将进行相对应的操作。同时,表示键鼠操作的整数将被加密,加密方法为 RSA。视频监控随时可以结束,也可以截取当前的屏幕截图并保存。
在视频监控的同时,用户可以选择性地开启网络活动监控线程。如果用户需要开启,则需要先在设置界面(图形界面二)进行过滤设置,选择需要捕获的数据包,可以从网络接口、协议类型、源主机、目的主机几个方面进行设置。开启该线程后,本机将开始抓包,并将抓到的包进行处理后显示在主界面。抓包过程中,随时可以暂停或终止,终止后可以将抓到的数据包保存为 pacp 格式,以供后续使用 wireshark 详细查看。用户也可以选择中断目标主机的网络访问,原理即为 ARP 攻击,该选项将会开启一个线程,持续向目标主机发送 ARP 包。
当因为用户使用不当而导致错误时,都会弹出错误窗口(图形界面三),该窗口将提示具体是哪个地方出错了。
2.详细设计
Python 对于多线程的支持对用户非常友好,使用 Threading
库,可以非常方便的创建一个新线程并使其运行,也可以通过 Event()函数来协调多线程之间的运行与阻塞。图形化界面也可以通过 pyqt5 非常方便的编写。
视频监控的主要原理为目标主机截取当前桌面截图并通过 socket 发送给本机,本机接收后将图片改变为需要的格式并显示在主界面。但是有一个主要问题就是,每次目标主机每次截取的图片大小基本都在 500KB 以上,有些甚至达到了 1MB,如果每秒截取十张,并且全部发送,那么需要的网络带宽为 5M/s 到 10M/s,网络负担明显过大。因此,可以采取差异化传输。同样为每秒截取十张图片,即每 100 毫秒截取一张,目标主机与本机刚建立连接时,截取的第一张图片将完整发送,之后,目标主机截取每一张图片后都将与上一张比较,若没有变化,则不发送,100 毫秒再截取下一张;如果有变化,则将两张图片做减法,找到有差异的部分,仅发送差异化的部分。比如,当前截取的图片与上一张图片仅有一个光标的差别,那么就会只发送该光标。为了继续优化,将再次比较差异化部分与当前截图的大小,哪一个小就发送哪一个。为了方便本机确定接收到的图片是完整图片还是差异化图片,将在数据包设置一个标志位,1 表示完整图片,0 表示差异化图片。目标主机差异化发送图片的伪代码如图 2 所示,本机的图片传输流程图分别如图 3 所示。
键鼠控制同样通过 socket 实现。目标主机的分辨率为 1920*1080,为了能够在画面中全部显示目标主机的监控画面,我将图片缩小到了原来的 0.6 倍,然后在主界面显示。显示图片的部件为重写后的 QLabel,我在其中重写了鼠标事件和键盘事件,即附录源程序中的 MyQLabel 类。当用户在 QLabel(即显示的监控画面)上进行鼠标操作时,重写后的鼠标事件将会立即获得当前坐标、用户的操作(鼠标按下或鼠标释放),并得知操作的左键还是右键,然后调用发送函数,将鼠标按键、鼠标操作以及坐标(除以 0.6)一起打包发送给目标主机。目标主机接收到这些信息后,将会把鼠标移动到相应的坐标,执行相应的操作。键盘操作和鼠标操作类似,但由于使用的 keyboard 库与 pyqt5 的键盘事件返回的键盘码不太兼容,因此目前只能确保英文字母输入正常,且不支持组合键。本机键鼠控制的流程图如图 4 所示,目标主机端键鼠控制的流程图以及伪代码因为非常简单,不再给出,可参考附录源程序。
目标主机硬件资源的监控也是通过 socket 实现的。目标主机每两秒发送一次 CPU 使用率、内存使用率和总内存,本机循环接收,接收到后即进行格式转换与单位转换,然后填充到主界面对应的位置。本机对应的流程图如图 5 所示,目标主机发送硬件资源信息的流程图非常简单,不再给出。
监控时长的记录主要是通过 python
的 time 库实现的。当开始监控一台主机时,就会获取当前时间,并开启一个新的线程用来记录时间,每秒更新一次。伪代码如图 6 所示。
截图功能可以截取当前目标主机的桌面,这个十分容易实现,因为在把图片显示到主界面之前,一定需要用一个变量 img 来存储它,只要在按下截图按键时,立即获得当前的 img,然后保存为 png 文件即可。
在监控过程中,随时可以结束视频监控,由于视频监控而开启的各个线程也将会随之阻塞或退出。这些线程都是通过一个定义为 event_monitor 的线程事件来调度的。当 event_monitor 被设置时(event_monitor.set()函数调用),所有线程都将开启,并正常运行,各个线程通过 event_monitor.is_set()函数来检测对应的进程事件是否被设置;当用户选择结束线程时,将会调用 event_monitor.clear()函数,清除该事件的设置,并断开 socket 连接,相应的进程也就会阻塞(如监控时间记录线程)或退出(图片接收线程、硬件使用信息接收线程)。结束视频监控的流程图如图 7 所示。
至此,关于主机控制模块的基本功能都已经介绍完毕。下面给将开始介绍网络活动监控模块。
网络活动监控模块最主要的功能就是抓包,使用 python 的 scapy 库中的 sniff 函数可以实现抓取特定网卡上的数据包。但是,sniff 函数抓取的数据包只能解析到 TCP/UDP 层,再往下就无法解析了,统一标记为 RAW。这个可以通过端口号来解决,后面会进行说明。在开始抓包之前,我们还希望能对抓到的包进行简单的过滤。为了满足这一要求,用户可以点击设置按键,进入到设置界面,进行抓包选项设置:网络接口,协议类型,主机,源主机以及目的主机。因为我是在自己的虚拟机上进行的,虚拟机使用的是 NAT 模式,因此网络接口默认为” VMware Network Adapter VMnet8”。协议类型可以从一个下拉框中选择:Any, TCP, UDP, IP, HTTP, HTTPS, SMTP 等。主机则默认为当前正在进行视频监控的主机 IP,源主机和目的主机用户可以指定。在设置这些选项的过程中,实际上就是构造了一条 filter 语句,这个语句将作为参数传入 sniff 函数。构造 filter 语句的伪代码如图 8 所示。
过滤语句构造好后,就可以开始抓包了,流程图如图 9 所示。首先设置以下按键,比如在抓包的时候将保存键设置为不可用。然后调用 sniff 函数进行抓包,每抓到一个包,就开始逐层解析。
首先是以太网帧,在这里协议类型可能有 IPv4, ARP, IPv6 等,使用 packet[Ether].type 可以获得一个 2 字节的十六进制数,这个数字对应了协议类型。比如,0x0800 表示 IPv4。可以使用一个字典类型的数据结构来保存十六进制数与对应的协议类型。然后解析 IP 层数据报,同样也可以使用 packet[IP].proto 获得一个整数,然后这个整数对应了某种协议类型,比如,4 对应了 IP。这种对应关系依然可以用字典来保存。要获取源主机 IP 和目的主机 IP,可以使用 packet[IP].src 和 packet[IP].dst 分别获得。接下来的 TCP/UDP 层报文段类似,也可以通过 packet[TCP/UDP].sport 和 packet[TCP/UDP].dport 来获取端口号。然后根据端口号来确定更具体的协议类型,如 Http(tcp port 80), Https(tcp port 443), SMTP(tcp port 25), Telnet(tcp port 23), SNMP(udp port 161)等。这些协议类型和端口号的映射关系也要用字典保存。当确定具体的协议类型、源地址、目的地址、端口、报文长度、报文内容等信息后,就可以将其显示在主界面了。
在抓包过程中,随时可以暂停,此时将会把变量 flag_pause 设置为 Ture(初始为 False),这时抓包进程仍在继续,但不会进行数据包的解析与展示。再次点击开始按键,如果 flag_pause 为 True,那么将把该变量设置为 True,抓到包后会继续解析并展示。同时,按下暂停键后,开始按键将被设置为可用,暂停键本身被设置为不可用。过程十分简单,不再展示流程图。
如果想要终止抓包进程,那么可以按下终止按键,此时将进行以下操作:调用函数 event_stop_capture.set()
,即抓包进程将会阻塞;设置相应的按键是否可用,比如,这时候保存按键就可以使用了;清空数据包列表,因为所有抓到的数据包都保存在一个列表中,清空后,下次点击开始按键就会重新开始抓包。过程很简单,也不再展示流程图或伪代码。
不管是我们试图攻击目标主机,还是在目标主机遭受攻击时希望保护它,都可能需要强制中断目标主机的网络访问。该功能可以通过 ARP 攻击来实现。流程图如上页图 10 所示。首先需要知道目标主机的 IP 和网关 IP,然后使用 Scapy 库的 getmacbyip()函数和 get_if_hwaddr()函数可以分别获得目标主机的 MAC 地址和网关的 MAC 地址,然后构造 ARP 数据包:ARP(hwsrc=网关 MAC 地址, psrc=网关 IP, hwdst=目标主机 MAC 地址, pdst=目标主机 IP)。该 ARP 包的源地址为网关 IP 和网关 MAC 地址,目的地址为目标主机的 IP 和 MAC 地址。然后构造以太网帧:Ether(src=网关 MAC 地址, dst=目标主机 MAC 地址)。构造完成后,每隔一秒向目标主机发送一次,这样目标主机将无法正常进行网络访问。同样,该功能也需要开启一个新线程,通过 event_cutoff 这个线程事件来协调。
当用户想要允许目标主机的网络访问时,只需要点击恢复网络按键,这样 event_cutoff 这个事件将会被清空,相应线程将会停止发送 ARP 数据包,目标主机的网络访问也会随之恢复正常。
到此为止,远程控制主机的两个主要模块已经叙述完毕,其他的还有加密功能和错误提示功能。
为了防止远程控制模块的鼠标键盘操作被他人窃取,我将键鼠操作进行了加密。在本机的键鼠操作都是通过 socket 发往目标主机的,发送的是四个数字:左键或右键或键盘某个按键对应的整数,按键按下或释放对应的整数,横坐标,纵坐标。我将第一个整数,即左键或右键或某个键盘按键对应的整数进行了加密,加密方式为 RSA。首先使用 Python 的 RSA 模块生成密钥,包括公钥和私钥,并保存在文件中。其中,公钥放在本机,私钥需要放在目标主机。然后,每次进行键鼠操作,按键对应的整数都会被 RSA 公钥加密为一个 16bit 长的十六进制数,然后将该十六进制数和其他三个数字一同发往目标主机。目标主机接收后,将前十六位提取出来,并使用私钥解密,然后在它的屏幕上还原相应操作。流程图如图 11 所示。
错误提示功能主要是检测用户的使用是否规范。假如用户没有指定目标主机 IP 就开始进行抓包、视频监控或 ARP 攻击等行为,就会弹窗提示用户需要设置 IP。
2.调试分析
在编程过程中,遇到的第一个问题是 Scapy 只能确认到 TCP/UDP 这一层,无法确定具体是 Http 协议、Https 协议或 SMTP 协议等。我最初的想法是想办法去解析更深一层,即 RAW 层的内容,从中可以获得某些字符串如’Http’,进而确定具体的协议类型。但是查找了各种资料,依然没有可行方案,最后突然意识到,可以通过端口号来判断具体的协议类型。比如,Http 协议的数据包通过 TCP 80 端口,Https 协议的数据包通过 TCP 443 端口。而通过 Scapy 可以很轻松的获得端口号等信息。于是,我使用一个字典来保存端口号(或其他整数)和协议类型的映射关系,端口号(或其他整数)作为键,协议类型作为值,当抓到一个数据包后,通过端口号来找到字典中对应的键值对,进而就可以确定协议类型。
在做视频监控模块时,我本来计算将传送的每一张图片加密,密钥使用一张随机生成的图片,将密钥图片与要发送的每一张图片的每一个像素进行异或,然后发送加密后的图片。本机接收到图片后,再次与密钥图片进行异或,得到的就是原图片。但是,由于其中的格式转换过于复杂,我做了接近三天仍没有丝毫进展,只好放弃,去做了键鼠操作的加密。
另外就是发送图片的时候,在前文也叙述过,我最开始是采取整张图片完全发送的,这样对网络负担过大。我想过牺牲一些清晰度来减轻网络负担,但是为了本机监控方便,将画面缩放到原来的 0.6 倍本身就已经损失了很多清晰度,如果再压缩,那么在本机就很难看清楚画面了,监控也就失去了意义。后来在参考另外一个项目时得到了灵感,即使用差异化传输。这样,对网络的负担基本可以不需要考虑。
现在回顾整个设计过程,主要涉及到了 socket 编程、arp 攻击原理、scapy 库的使用、多线程模型、图片处理(opencv 的使用)、RSA 加密以及基本的计算机网络知识等。在学习计算机网络时曾经做过抓包实验,但那是使用 wireshark 工具来进行抓包,本次课设则是自己手写了一个抓包工具,对抓包的原理有了更加深刻的理解。而图片处理、opencv 库和 Pillow 库的使用则是之前没有接触过的,通过这次课设,也对它们的基本使用方法有了一个大概的了解。Socket 编程是这学期刚学习的内容,虽然 python 的 socket 操作与 C 语言相比简单了很多,但作为复习来讲还是有益处的,并且也算是增加了使用经验。
3.测试结果
接下来我将展示远程控制主机课程设计最终实现的功能:界面展示,视频监控,远程控制,硬件资源使用信息监控,网络活动监控的开始、暂停与终止,保存截图和数据包等。
首先是程序运行后的主界面,如下图所示。
输入目标主机 IP,开始视频监控。
远程控制打开浏览器并进行键盘输入(具体已在验收时展示):
结束监控,又回到初始界面:
监控目标主机硬件资源使用信息:
监控网络活动展示(打开浏览器,只抓取 Https 协议类型的数据包):
随便点击表格的一行,显示数据包具体信息:
点击断网,使用 ARP 攻击成功中断了网络访问(在图 17 中网络正常):
恢复网络访问:
保存抓包信息和当前屏幕截图:
到此这篇关于基于Python实现主机远程控制的文章就介绍到这了,更多相关Python实现主机远程控制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!