简单的发包工具——网络协议编辑器(python+scapy+pycharm)

 

发包工具

一、实现的功能

基于Python+scapy设计协议编辑器,基于Tkinter的Python GUI界面设计。实现了MAC、ARP、ip 、TCP、udp协议的编辑与发送,并且支持生成协议字段的默认值,支持用户输入协议字段值,发包前对协议字段的合理性进行检查,发包前自动计算并显示校验和,支持单次发包、多次发包,支持连续发包,连续发包时可随时停止和计算并显示数据包发送速度的功能。

注:

程序代码HTTPs://download.csdn.net/download/wmrem/10439779

运行前需要先安装第三方库scapy,安装方法:https://blog.csdn.net/wmrem/article/details/80004819

二、主要函数说明——IP包的编辑与发送为例

1.创建IP包编辑器界面,为每个按钮绑定单击响应时间。

def create_ip_sender():

1.设置协议编辑器的界面

ip_fields = ‘ip协议的版本:’,…… , ‘目的IP地址:’

entries = create_protocol_editor(protocol_editor_panedwindow, ip_fields)

2.创建发送,默认值,清空按钮,并绑定功能

send_packet_button, reset_button, default_packet_button = create_bottom_buttons(protocol_editor_panedwindow)

3.为”回车键”的Press事件编写事件响应代码,发送IP包

tk.bind(‘‘, (lambda event: send_ip_packet(entries, send_packet_button))) # 代表回车键

4.为”发送”、默认值、按钮的单击事件编写事件响应代码,发送IP包

send_packet_button.bind(‘‘, (

lambda event: send_ip_packet(entries, send_packet_button)))

2. 在协议字段编辑框中填入默认IP包的字段值,为IP数据包的发送做好准备

def create_default_ip_packet(entries):

1.清空各字段的值

clear_protocol_editor(entries)

2.创建默认的IP数据包,并将其各字段的值填入协议编辑器的对应的文本框

default_ip_packet = IP()

entries[0].insert(0, int(default_ip_packet.version))

3.获取协议编辑器文本框的值,创建对应的数据包并开启一个线程用于连续发送数据包。

def send_ip_packet(entries, send_packet_button):

if 按钮为发送时:

1. 从协议编辑框中获取要发送的数据包的各个字段的值

ip_version = int(entries[0].get())

2.用获取的数据包的各字段的值创建相应的数据包

packet_to_send = IP(version=ip_version,……,src=ip_src, dst=ip_dst)

3.开一个线程用于连续发送数据包,并启动

t = threading.Thread(target=send_packet, args=(packet_to_send,))

t.start()

4.使协议导航树不可用

toggle_protocols_tree_state()

send_packet_button[‘text’] = ‘停止’

else 按钮为停止时:

5.按钮为停止时可以终止数据包发送线程

stop_sending.set()

6.恢复协议导航树可用

toggle_protocols_tree_state()

send_packet_button[‘text’] = ‘发送’

4.发送数据包的线程函数,并计算数据包发送速度

def send_packet(packet_to_send):

stop_sending.clear()

1.计算待发送数据包的长度(用于计算发送速度)

packet_size = len(packet_to_send)

2.推导数据包的协议类型

3.计算发包开始发送时间点

begin_time = datetime.now()

4.连续发送数据包直到进程关闭

while 进程没有关闭:

if 发送Ether:

sendp(packet_to_send, verbose=0) # verbose=0,不在控制回显’Sent 1 packets’.

else:

send(packet_to_send, verbose=0)

5.计算发送的总字节

total_bytes = packet_size * n

6.计算发包用的总时间

total_time = (end_time – begin_time).total_seconds()

7.计算发包的速度

bytes_per_second = total_bytes / total_time / 1024

三、基础知识准备

1.构造数据包,发送数据包——“/”运算符数据包的拼装,send()用于3层发包,可直接发送IP数据包,自动加以太帧;只发送以太帧使用sendp()。

2.计算校验和——IP包的校验和默认值为None,在IP包被发送时,其校验和被被自动计算并填充在IP包中

以下方式可以在发包前计算IP包的校验和,直接用packet.show2()命令也可以显示校验和。raw(packet)将数据包的内容转换为字节。

3.查看数据包的字段值(使用ls()),查看某层协议数据包对象支持的函数(使用help())

4.ls()列出scapy支持的所有数据包,协议;lsc()列出scapy支持的全部命令;conf列出scapy的当前配置。

四、主要功能实现代码——以IP包为例

1.创建IP包编辑器的界面

# 创建协议字段编辑区 def create_protocol_editor(root, field_names):     """     创建协议字段编辑区     :param root: 协议编辑区     :param field_names: 协议字段名列表     :return: 协议字段编辑框列表     """     entries = []     for field in field_names:         row = Frame(root)         label = Label(row, width=15, text=field, anchor='e')         entry = Entry(row, font=('Courier', '12', 'bold'), state='normal')  # 设置编辑框为等宽字体         row.pack(side=TOP, fill=X, padx=5, pady=5)         label.pack(side=LEFT)         entry.pack(side=RIGHT, expand=YES, fill=X)         entries.APPend(entry)     return entries
def create_ip_sender():     """     创建IP包编辑器     :return: None     """     # IP帧编辑区     ip_fields = 'IP协议的版本:', '首部长度(5-15):', '区分服务:', '总长度:', '标识:', '标志(0-2)DF,MF:',                  '片偏移:', '生存时间:', '协议(数据部分):', '首部校验和:', '源IP地址:', '目的IP地址:'     entries = create_protocol_editor(protocol_editor_panedwindow, ip_fields)     send_packet_button, reset_button, default_packet_button = create_bottom_buttons(protocol_editor_panedwindow)     # 为"回车键"的Press事件编写事件响应代码,发送ARP包     tk.bind('', (lambda event: send_ip_packet(entries, send_packet_button)))  # 代表回车键     # 为"发送"按钮的单击事件编写事件响应代码,发送ARP包     send_packet_button.bind('', (         lambda event: send_ip_packet(entries, send_packet_button)))  # 代表鼠标左键单击     # 为"清空"按钮的单击事件编写事件响应代码,清空协议字段编辑框     reset_button.bind('', (lambda event: clear_protocol_editor(entries)))     # 为"默认值"按钮的单击事件编写事件响应代码,在协议字段编辑框填入ARP包字段的默认值     default_packet_button.bind('', (lambda event: create_default_ip_packet(entries)))

2.在协议字段编辑框中填入默认IP包的字段值,填入前需要先清空当前值。

def clear_protocol_editor(entries):     """     清空协议编辑器的当前值     :param entries: 协议字段编辑框列表     :return: None     """     for entry in entries:         # 如果有只读Entry,也要清空它的当前值         state = entry['state']         entry['state'] = 'normal'         entry.delete(0, END)         entry['state'] = state
# 当前网卡的默认网关 default_gateway = [a for a in os.popen('route print').readlines() if ' 0.0.0.0 ' in a][0].split()[-3] 
def create_default_ip_packet(entries):     """         在协议字段编辑框中填入默认IP包的字段值          :param entries: 协议字段编辑框列表          :return: None          """     clear_protocol_editor(entries)     default_ip_packet = IP()     entries[0].insert(0, int(default_ip_packet.version))     entries[1].insert(0, 5)     entries[3].insert(0, 20)     entries[2].insert(0, hex(default_ip_packet.tos))     entries[4].insert(0, int(default_ip_packet.id))     entries[5].insert(0, int(default_ip_packet.flags))     entries[6].insert(0, int(default_ip_packet.frag))     entries[7].insert(0, int(default_ip_packet.ttl))     entries[8].insert(0, int(default_ip_packet.proto))     entries[9]['state'] = NORMAL # 可操作     entries[9].insert(0, "单机发送时自动计算")     entries[9]['state'] = disableD  # 不可操作     # 目标IP地址设成本地默认网关     entries[11].insert(0, default_gateway)     default_ip_packet = IP(dst=entries[11].get())#可以省略     entries[10].insert(0, default_ip_packet.src)

3.发送IP包

def send_ip_packet(entries, send_packet_button):     """     发IP包     :param entries:     :param send_packet_button:     :return:     """     if send_packet_button['text'] == '发送':         ip_version = int(entries[0].get())         ip_ihl = int(entries[1].get())         ip_tos = int(entries[2].get(), 16)         ip_len = int(entries[3].get())         ip_id = int(entries[4].get())         ip_flags = int(entries[5].get())         ip_frag = int(entries[6].get())         ip_ttl = int(entries[7].get())         ip_proto = int(entries[8].get())         ip_src = entries[10].get()         ip_dst = entries[11].get()         # ip_options = entries[12].get()         packet_to_send = IP(version=ip_version, ihl=ip_ihl, tos=ip_tos, len=ip_len, id=ip_id,                             frag=ip_frag, flags=ip_flags, ttl=ip_ttl, proto=ip_proto, src=ip_src, dst=ip_dst)         packet_to_send = IP(raw(packet_to_send))         entries[9]['state'] = NORMAL  # 重新激活         entries[9].delete(0, END)         entries[9].insert(0, hex(packet_to_send.chksum))         entries[9]['state'] = DISABLED  # 不可操作         # 开一个线程用于连续发送数据包         t = threading.Thread(target=send_packet, args=(packet_to_send,))         t.setDaemon(True)         t.start()         # 使协议导航树不可用         toggle_protocols_tree_state()         send_packet_button['text'] = '停止'     else:         # 终止数据包发送线程         stop_sending.set()         # 恢复协议导航树可用         toggle_protocols_tree_state()         send_packet_button['text'] = '发送'

4.线程中运行的用于发送数据包的函数,可以计算发包速度

def send_packet(packet_to_send):     """     在我们给出的发包程序中,如果电脑速度太快,send_packet函数中的send(...)函数执行前后,     datetetime返回的begin_time和end_time可能是相同的,结果会报除零错误,所以,send_packet函数应该做修改      用于发送数据包的线程函数,持续发送数据包     :type packet_to_send: 待发送的数据包     """     # print(packet.show(dump=True))     # 对发送的数据包次数进行计数,用于计算发送速度     n = 0     stop_sending.clear()     # 待发送数据包的长度(用于计算发送速度)     packet_size = len(packet_to_send)     # 推导数据包的协议类型     proto_names = ['TCP', 'UDP', 'ICMP', 'IP', 'ARP', 'Ether', 'Unknown']     packet_proto = ''     for pn in proto_names:         if pn in packet_to_send:             packet_proto = pn             break     # 开始发送时间点     begin_time = datetime.now()     while not stop_sending.is_set():         if isinstance(packet_to_send, Ether):             sendp(packet_to_send, verbose=0)  # verbose=0,不在控制回显'Sent 1 packets'.         else:             send(packet_to_send, verbose=0)         n += 1         end_time = datetime.now()         total_bytes = packet_size * n         #修改         total_time = (end_time - begin_time).total_seconds()         if total_time == 0:             total_time = 2.23E-308  # 当begin_time和end_time相等时,将total_time设为IEEE 745标准中规定的最小浮点数         bytes_per_second = total_bytes / total_time / 1024         # bytes_per_second = total_bytes / ((end_time - begin_time).total_seconds()) / 1024         status_bar.set('已经发送了%d个%s数据包, 已经发送了%d个字节,发送速率: %0.2fK字节/秒',                        n, packet_proto, total_bytes, bytes_per_second)

五、运行结果

相关阅读

记账工具可行性分析:还有继续的必要吗?

现在支付宝都那么牛逼了,我每天花什么用多少都会自动记账,而且还有月账单,根本不需要什么记账工具啊!真的是这样嘛?记账的起源是由于生

【收藏】最强大的rar密码破解工具 在线秒破rar/zip/ex

先说一下我遇到的麻烦。很多年之前我用winrar加密了一个技术文档,由于当时感觉资料存储在自己的电脑上,加上我平时又没有安装杀毒软

效率为王!11款最高效的团队协作工具

每个团队都有协作办公的需求,对协作类工具的需求也比较强烈。为满足这一需求,国内外陆续涌现了很多协作类工具,涵盖文档协作、项目协

【爬虫工具】哔哩哔哩插件姬(bilibili-plugin)

完整原文(含源码):http://exp-blog.com/2018/09/09/pid-2223/(转载请注明出处,仅供分享学习,严禁用于商业用途) 声明 写这个插件纯粹是

Driller工具分析

1. Driller介绍 driller在afl的基础上开发的crash模糊测试工具。Driller在AFL的基础上加入了动态符号执行引擎,当模糊测试发生stu

发表评论