使用Python构造数据包

本文介绍了Python中的socket函数及其参数,包括套接字家族、类型和协议。通过示例展示了如何使用socket进行TCP和UDP通信,以及如何构造自定义的数据包。还提到了指定网卡的使用,并提供了发送和接收数据的客户端和服务端脚本。此外,文章探讨了如何使用RAW SOCKET来构造TCP、IP甚至MAC头部的数据包。

一、socket函数

在这里插入图片描述

1、socket函数参数及方法

1)参数

Python 中,用 socket()函数来创建套接字,语法格式如下

socket.socket([family[, type[, proto]]])

· family: 套接字家族可以使 AF_UNIX 或者 AF_INET。
· type: 套接字类型可以根据是面向连接的还是非连接分为 SOCK_STREAM 或 SOCK_DGRAM。
· protocol: 一般不填默认为 0。
https://gist.github.com/kevinkindom/108ffd675cb9253f8f71

2)方法

https://www.runoob.com/python/python-socket.html

2、TCP/UDP通讯

该方法自动补充MAC、IP、TCP包头,意味着我们需要填充的是包结构图中的 [ 数据 ]

1)send_udp_tcp.py

import argparse
import socket  
  
parser = argparse.ArgumentParser(description='Client')
parser.add_argument('--TCP_UDP', type=str, default='UDP')
parser.add_argument('--src_ip', type=str, default='172.16.200.1')
parser.add_argument('--dst_ip', type=str, default='172.16.200.2')
parser.add_argument('--dst_port', type=int, default=31500)
parser.add_argument('--send_times', type=int, default=10)
args = parser.parse_args()

if args.TCP_UDP == 'UDP':
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # s.bind((args.src_ip,0))                                                   # in windows
    s.setsockopt(socket.SOL_SOCKET, 25, 'ens3f0'.encode(encoding="utf-8"))      # in linux

    print("now using:"+str(args.TCP_UDP))
    print("src_ip:"+str(args.src_ip))
    print("dst_ip:"+str(args.dst_ip))
    print("dst_port:"+str(args.dst_port))
    print("send_times"+str(args.send_times))
    print("send data begin")

    for i in range(args.send_times):  
        s.sendto("test udp".encode(encoding="utf-8"), (args.dst_ip, args.dst_port)) 
    
    print("send ok")  
    s.close() 

elif args.TCP_UDP == 'TCP' : # TCP尚未测试
    print("now using:"+str(args.TCP_UDP))
    print("src_ip:"+str(args.src_ip))
    print("dst_ip:"+str(args.dst_ip))
    print("dst_port:"+str(args.dst_port))
    print("send_times"+str(args.send_times))
    print("send data begin")
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
    try:
        s.connect((args.dst_ip, args.dst_port)) 
    except Exception:
        print("server port not connect!")
    
    for i in range(args.send_times):
        s.send('test tcp')

    print("send ok")
    s.close()

else:
    print("error TCP/UDP type")

2)recv_udp_tcp.py

import argparse
import socket  
  
parser = argparse.ArgumentParser(description='Server')
parser.add_argument('--TCP_UDP', type=str, default='UDP')
parser.add_argument('--my_ip', type=str, default='172.16.200.2')
parser.add_argument('--my_port', type=int, default=31500)
args = parser.parse_args()

if args.TCP_UDP == 'UDP':
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind((args.my_ip, args.my_port))

    print("now using:"+str(args.TCP_UDP))
    print("my_ip:"+str(args.my_ip))
    print("my_port:"+str(args.my_port))
    print("recv data begin")

    while True:  
        data, addr = s.recvfrom(2048)
        datas = str(data,encoding='utf-8')
        print("received:" + datas + "\n")
        # print("received:" + data + "\nfrom:" + addr)
    
    s.close()

elif args.TCP_UDP == 'TCP' : # TCP尚未测试
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
    s.bind((args.my_ip, args.my_port)) 
    

    print("now using:"+str(args.TCP_UDP))
    print("my_ip:"+str(args.my_ip))
    print("my_port:"+str(args.my_port))
    print("recv data begin")

    s.listen(5)
    ss, addr = s.accept() # 被动接受TCP客户端连接,(阻塞式)等待连接的到来
    print('got connected from',addr)

    ra = ss.recv(512)
    print(ra)

    ss.close()
    s.close()

else:
    print("error TCP/UDP type")

3、自行构造数据包

1)自行构造TCP部分及后面数据

意味着我们需要填充的是包结构图中的 [ TCP包头 | 数据 ]

需要使用RAW SOCKET 通信,AF_INET表示使用IPv4协议(自动补充以太网和IPv4部分),socket.SOCK_RAW指TCP及后面自行构造,NGA_TYPE指IPv4部分协议类型,6表示下一个部分为TCP,17表示下一个部分为UDP,一般自行构造NGA_TYPE=18

import socket  
  
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, NGA_TYPE) 
nga = struct.pack( # ngaa包头部分
                '!IbbIbI',  # I 表示unsigned int(4byte), b表示signed char(1byte), !表示顺序解析
                worker_id,
                degree,
                0,
                aggindex,
                switch_id,
                sequence + pkt_id
            )
s.sendto(nga, (self.dst_ip, 0))

2)自行构造IP部分及以后

也即是说,需要填充的是上图中的 [ IP包头 | TCP包头 | 数据 ] 的内容

socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))

3)完全自行构造

意味着我们需要填充的是上图中的 [ MAC包头 | IP包头 | TCP包头 | 数据 ] 的内容

socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))

4、指定网卡

https://stackoverflow.com/questions/8437726/can-python-select-what-network-adapter-when-opening-a-socket

二、参考资料

https://www.cnblogs.com/JenningsMao/p/9487465.html

构造JDWP (Java Debug Wire Protocol) Socket 数据包涉及一些底层通信协议的知识,并需要对 JDWP 的命令集有所了解。通过 Python 实现这个过程,通常是为了实现 Java 应用程序调试工具或自动化测试框架的一部分功能。 为了构造 JDWP 数据包并发送它们,您可以按照下面的基本步骤操作: ### 1. 创建Socket连接 首先建立到目标 JVM 的网络套接字(socket)连接。JVM 启动时指定的调试端口用于创建此连接。 ```python import socket def create_socket_connection(host='localhost', port=8000): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (host, port) print(f"Connecting to {server_address[0]} on port {server_address[1]}.") try: sock.connect(server_address) except Exception as e: print("Failed to connect:", str(e)) return None return sock ``` 请注意,默认情况下,端口号 `8000` 只是一个示例值;实际使用的端口号取决于启动 JVM 调试模式时所设置的具体值。 ### 2. 构建JDWP数据包结构 每个 JDWP 消息由一个固定的头部和可变长度的消息体组成。消息头包含版本信息、标志位等字段,而消息主体则依据具体的命令类型有所不同。 由于直接从零开始构建所有必要的比特流较为复杂且容易出错,在实践中可以考虑使用现有的库如 [pydbg](https://github.com/crackinglandia/pydbg),它提供了更高级别的API帮助处理低级细节。 然而,如果你想手动编码,则可以参考官方文档([Oracle's JPDA documentation](https://docs.oracle.com/javase/7/docs/platform/jpda/jdwp-spec.html)) 来理解如何组织各个部分的数据帧格式。 #### 示例函数 - 发送简单握手请求 这是一个非常简化的例子,仅演示了怎样打包最基本的 'handshake' 请求: ```python HANDSHAKE = b'\n\r'# ASCII for CR+LF which serves as the handshake in simple form. def send_handshake(sock): if not sock: raise ValueError("Invalid socket connection.") sent_bytes = sock.send(HANDSHAKE) # Read response from server. data = sock.recv(64).strip() print('Received:', repr(data)) # 使用上面定义好的create_socket_connection 函数获取sock 对象然后调用send_handshake. if __name__ == '__main__': s = create_socket_connection() if s is not None: send_handshake(s) ``` 以上代码片段展示了向远程调试代理发出简单的“握手”信号的过程,这是每次会话初始化阶段必须要做的第一步。之后你可以继续发送其他类型的命令来进行线程管理、断点设定等活动。 请记住这只是一个起点——真正的应用程序将涉及到更多的工作来解析响应结果以及异常情况下的错误恢复机制设计。 段落最后提供的链接指向 Oracle 关于 JDWP 协议规范的页面,对于深入了解每种命令的确切语法及含义是非常有帮助的资源之一。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值