-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
330 lines (274 loc) · 13.5 KB
/
Copy pathmain.py
File metadata and controls
330 lines (274 loc) · 13.5 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
import customtkinter as ctk
import re
import base64
import base58
import base91
import threading
import urllib.parse
BG_COLOR = "#F3F4F6"
CARD_COLOR = "#FFFFFF"
TEXT_MAIN = "#1F2937"
ACCENT_COLOR = "#4F46E5"
HOVER_COLOR = "#4338CA"
SEC_COLOR = "#9CA3AF"
SEC_HOVER = "#6B7280"
BORDER_COLOR = "#E5E7EB"
ctk.set_appearance_mode("Light")
root = ctk.CTk(fg_color=BG_COLOR)
root.title("CryptexLab智能解码器")
root.geometry("850x700")
font_title = ('Microsoft YaHei UI', 20, 'bold')
font_label = ('Microsoft YaHei UI', 13, 'bold')
font_text = ('Microsoft YaHei UI', 13)
font_code = ('Consolas', 13)
# 全局变量
latest_process_log = ""
thread_final_result = ""
thread_process_log = ""
process_window_instance = None # 记录子窗口实例,防多开
# ===========================
# 核心探测与解码算法
# ===========================
def looks_like_url(s):
return '%' in s and re.search(r'%[0-9a-fA-F]{2}', s) is not None
def url_decode_to_bytes(s):
res = urllib.parse.unquote_to_bytes(s)
if res == s.encode('utf-8'):
raise ValueError("No URL encoding found")
return res
def looks_like_ascii_decimal(s):
# 情景 1:连续的纯数字(无空格),例如 "545155"
if s.isdigit() and len(s) % 2 == 0:
pairs = [s[i:i+2] for i in range(0, len(s), 2)]
return all(32 <= int(p) <= 126 for p in pairs)
# 情景 2:传统的带空格或逗号分隔的数字,例如 "72 101 108"
if not re.search(r'[\s,]', s): return False
nums = re.findall(r'\d+', s)
if len(nums) < 2: return False
return all(0 <= int(n) <= 255 for n in nums)
def ascii_decimal_decode(s):
if s.isdigit() and len(s) % 2 == 0:
nums = [s[i:i+2] for i in range(0, len(s), 2)]
else:
nums = re.findall(r'\d+', s)
return bytes(int(n) for n in nums)
def is_binary(s): return all(c in '01' for c in s) and len(s) % 8 == 0
def decode_bytes(byte_data):
try: text = byte_data.decode('utf-8'); return text, True
except UnicodeDecodeError: return byte_data.hex(), False
def looks_like_base64(s): return len(s) % 4 == 0 and re.fullmatch(r'[A-Za-z0-9+/=]+', s) is not None
def looks_like_base32(s): return len(s) % 8 == 0 and re.fullmatch(r'[A-Z2-7=]+', s, re.IGNORECASE) is not None
def looks_like_base58(s): return all(c in base58.alphabet.decode() for c in s)
def looks_like_base91(s): return all(33 <= ord(c) <= 126 for c in s)
def looks_like_base85(s): return re.fullmatch(r'(?:[!-u]|z)+', s) is not None
def try_decode(s, func):
decoded = func(s)
return decode_bytes(decoded)
def recursive_decode(s, path=None, all_paths=None, max_depth=20):
if path is None: path = []
if all_paths is None: all_paths = []
if len(path) >= max_depth: return all_paths
decoders = [
('URL Encode', looks_like_url, url_decode_to_bytes),
('Base64', looks_like_base64, base64.b64decode),
('Base32', looks_like_base32, base64.b32decode),
('Base58', looks_like_base58, base58.b58decode),
('Binary', is_binary, lambda x: bytes(int(x[i:i + 8], 2) for i in range(0, len(x), 8))),
('ASCII Dec', looks_like_ascii_decimal, ascii_decimal_decode),
('Hex', lambda x: True, lambda x: bytes.fromhex(x)),
]
insert_idx = 4
if 'consider_base91_var' in globals() and consider_base91_var.get():
decoders.insert(insert_idx, ('Base91', looks_like_base91, base91.decode)); insert_idx += 1
if 'consider_base85_var' in globals() and consider_base85_var.get():
decoders.insert(insert_idx, ('Base85', looks_like_base85, base64.a85decode))
for name, detector, func in decoders:
if detector(s):
try: text, is_utf8 = try_decode(s, func)
except Exception: continue
if text == s: continue
# ==========================================
# 【核心修复】:强化版“无意义数据”过滤器
# ==========================================
stripped_text = text.strip()
# 1. 过滤纯空白
if not stripped_text: continue
# 2. 过滤全是"不可见控制字符"的垃圾数据 (ASCII码小于32,或等于127)
if all(ord(c) < 32 or ord(c) == 127 for c in stripped_text): continue
# ==========================================
mode = '(UTF-8)' if is_utf8 else '(hex)'
new_path = path + [(name, text, mode)]
all_paths.append(new_path)
if is_utf8: recursive_decode(text, new_path, all_paths, max_depth)
return all_paths
def select_final_path(paths):
utf_paths = [p for p in paths if p[-1][2] == '(UTF-8)']
if utf_paths:
max_len = max(len(p) for p in utf_paths)
for p in utf_paths:
if len(p) == max_len: return p
max_len = max(len(p) for p in paths)
for p in paths:
if len(p) == max_len: return p
# ===========================
# 后台多线程任务
# ===========================
def decoding_task(raw_text, user_depth):
global thread_final_result, thread_process_log
thread_final_result = ""
thread_process_log = ""
paths = recursive_decode(raw_text, max_depth=user_depth)
if not paths:
thread_final_result = '⚠️ 无法识别或解码此内容。'
return
final = select_final_path(paths)
process_log = f"=== 解码追踪日志 (最大探测深度: {user_depth}) ===\n\n"
final_result = ""
for i, (name, text, mode) in enumerate(final, 1):
process_log += f"● 步骤 {i}:使用 {name} 进行解码 {mode}\n"
process_log += f"结果截断预览:{text[:100]}{'...' if len(text)>100 else ''}\n\n"
final_result = text
# 尝试二段 Hex 显示
if len(final) == 1 and final[0][2] == '(UTF-8)':
s = final[0][1]
extra_decoders = [
('URL Encode', looks_like_url, url_decode_to_bytes),
('Base64', looks_like_base64, base64.b64decode),
('Base32', looks_like_base32, base64.b32decode),
('Base58', looks_like_base58, base58.b58decode),
]
if 'consider_base91_var' in globals() and consider_base91_var.get():
extra_decoders.append(('Base91', looks_like_base91, base91.decode))
if 'consider_base85_var' in globals() and consider_base85_var.get():
extra_decoders.append(('Base85', looks_like_base85, base64.a85decode))
extra_decoders.append(('ASCII Dec', looks_like_ascii_decimal, ascii_decimal_decode))
extra_decoders.append(('Binary', is_binary, lambda x: bytes(int(x[i:i + 8], 2) for i in range(0, len(x), 8))))
for name, detector, func in extra_decoders:
if detector(s):
try:
data = func(s)
hex_out = data.hex()
process_log += f"● 可能的步骤 2:使用 {name} 解码 (hex)\n"
process_log += f"结果:{hex_out}\n"
final_result = hex_out
break
except Exception: continue
thread_final_result = final_result
thread_process_log = process_log
# ===========================
# UI 控制与交互逻辑
# ===========================
def check_thread_alive(thread):
global latest_process_log
if thread.is_alive():
root.after(100, lambda: check_thread_alive(thread))
else:
loading_bar.stop()
loading_bar.pack_forget()
decode_btn.configure(text='🚀 运行解码', state="normal")
latest_process_log = thread_process_log
decode_output_text.insert(ctk.END, thread_final_result)
if "⚠️" not in thread_final_result and thread_process_log:
btn_show_process.configure(state="normal")
else:
btn_show_process.configure(state="disabled")
def start_decode_thread():
# 读取原始内容以保留 ASCII 的空格
original_raw = input_text.get('1.0', ctk.END).strip()
# 彻底清理 \n 解决卡死问题
raw = original_raw.replace('\n', '')
# 智能去空格:如果看起来像带空格的 ASCII,则保留;否则去除所有空格。
if not looks_like_ascii_decimal(original_raw):
raw = raw.replace(' ', '')
decode_output_text.delete('1.0', ctk.END)
if not raw: return
try:
user_depth = int(entry_max_depth.get().strip())
if user_depth <= 0: user_depth = 20
except ValueError:
user_depth = 20
entry_max_depth.delete(0, ctk.END)
entry_max_depth.insert(0, "20")
decode_btn.configure(text='⏳ 正在解码...', state="disabled")
btn_show_process.configure(state="disabled")
loading_bar.pack(side=ctk.LEFT, padx=20)
loading_bar.start()
decode_thread = threading.Thread(target=decoding_task, args=(raw, user_depth))
decode_thread.daemon = True
decode_thread.start()
check_thread_alive(decode_thread)
def show_process():
global latest_process_log, process_window_instance
# 修复:非模态单例弹窗,防止多开,且支持最小化
if process_window_instance is not None and process_window_instance.winfo_exists():
process_window_instance.deiconify()
process_window_instance.lift()
process_window_instance.focus()
return
process_window_instance = ctk.CTkToplevel(root)
process_window_instance.title("完整解码过程")
process_window_instance.geometry("600x500")
process_window_instance.configure(fg_color=BG_COLOR)
# 使其依附于主窗口,最小化主窗口时子窗口也会缩小
process_window_instance.transient(root)
ctk.CTkLabel(process_window_instance, text="Process History / 历史追溯", font=font_title, text_color=TEXT_MAIN).pack(pady=(25, 10), padx=30, anchor="w")
log_textbox = ctk.CTkTextbox(process_window_instance, font=font_code, wrap=ctk.WORD,
fg_color=CARD_COLOR, text_color=TEXT_MAIN,
border_width=1, border_color=BORDER_COLOR, corner_radius=10)
log_textbox.pack(fill=ctk.BOTH, expand=True, padx=30, pady=(0, 30))
log_textbox.insert(ctk.END, latest_process_log)
log_textbox.configure(state="disabled")
# ===========================
# 极简卡片式布局
# ===========================
main_frame = ctk.CTkFrame(root, fg_color="transparent")
main_frame.pack(fill=ctk.BOTH, expand=True, padx=45, pady=35)
title_label = ctk.CTkLabel(main_frame, text="CryptexLab智能解码器", font=font_title, text_color=TEXT_MAIN)
title_label.pack(pady=(0, 25))
ctk.CTkLabel(main_frame, text='INPUT / 输入编码内容', font=font_label, text_color="#6B7280").pack(anchor="w", pady=(0, 5))
# 关键设置:wrap=ctk.CHAR 防止超长文本卡死
input_text = ctk.CTkTextbox(main_frame, height=130, font=font_code, wrap=ctk.CHAR,
fg_color=CARD_COLOR, text_color=TEXT_MAIN,
border_width=1, border_color=BORDER_COLOR, corner_radius=12)
input_text.pack(fill=ctk.BOTH, pady=(0, 15))
# 控制栏
options_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
options_frame.pack(fill=ctk.X, pady=(0, 15))
consider_base91_var = ctk.BooleanVar(value=False)
consider_base85_var = ctk.BooleanVar(value=False)
cb_91 = ctk.CTkCheckBox(options_frame, text='启用 Base91', variable=consider_base91_var,
font=font_text, text_color=TEXT_MAIN,
fg_color=ACCENT_COLOR, border_color="#9CA3AF", hover_color=HOVER_COLOR)
cb_91.pack(side=ctk.LEFT, padx=(0, 20))
cb_85 = ctk.CTkCheckBox(options_frame, text='启用 Base85', variable=consider_base85_var,
font=font_text, text_color=TEXT_MAIN,
fg_color=ACCENT_COLOR, border_color="#9CA3AF", hover_color=HOVER_COLOR)
cb_85.pack(side=ctk.LEFT, padx=(0, 40))
ctk.CTkLabel(options_frame, text="最大解码轮数:", font=font_text, text_color=TEXT_MAIN).pack(side=ctk.LEFT, padx=(0, 5))
entry_max_depth = ctk.CTkEntry(options_frame, font=font_text, width=60, justify="center",
fg_color=CARD_COLOR, text_color=TEXT_MAIN,
border_color=BORDER_COLOR, border_width=1, corner_radius=6)
entry_max_depth.pack(side=ctk.LEFT)
entry_max_depth.insert(0, "20")
# 按钮区
btn_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
btn_frame.pack(fill=ctk.X, pady=(10, 25))
decode_btn = ctk.CTkButton(btn_frame, text='运行解码', font=('Microsoft YaHei UI', 15, 'bold'),
height=45, corner_radius=8, width=150,
fg_color=ACCENT_COLOR, hover_color=HOVER_COLOR,
command=start_decode_thread)
decode_btn.pack(side=ctk.LEFT, padx=(0, 15))
btn_show_process = ctk.CTkButton(btn_frame, text='查看过程', font=('Microsoft YaHei UI', 14),
height=45, corner_radius=8, width=120,
fg_color=SEC_COLOR, hover_color=SEC_HOVER,
state="disabled",
command=show_process)
btn_show_process.pack(side=ctk.LEFT)
loading_bar = ctk.CTkProgressBar(btn_frame, mode="indeterminate", width=150, fg_color=BORDER_COLOR, progress_color=ACCENT_COLOR)
ctk.CTkLabel(main_frame, text='OUTPUT / 最终解码结果', font=font_label, text_color="#6B7280").pack(anchor="w", pady=(0, 5))
decode_output_text = ctk.CTkTextbox(main_frame, height=220, font=font_code, wrap=ctk.WORD,
fg_color=CARD_COLOR, text_color=TEXT_MAIN,
border_width=1, border_color=BORDER_COLOR, corner_radius=12)
decode_output_text.pack(fill=ctk.BOTH, expand=True)
# 启动主循环
root.mainloop()