@מצ-ופצ-ף הקוד שלך נראה פחות או יותר ככה עכשיו
import customtkinter as ctk
from tkinter import filedialog, messagebox
import os
import re
import io
import threading
import subprocess
import platform
from PIL import Image
ctk.set_appearance_mode('Dark')
ctk.set_default_color_theme('blue')
class MTKExplorer(ctk.CTk):
def __init__(self):
super().__init__()
self.title('MTK Explorer V4 (Uncensored)')
self.geometry('1000x700')
self.bin_path = ''
self.resources = []
self.extract_dir = ''
# --- UI Header ---
self.lbl_title = ctk.CTkLabel(self, text='MTK EXPLORER - גלוי הכל', font=('Roboto Medium', 24))
self.lbl_title.pack(pady=10)
self.frame_top = ctk.CTkFrame(self)
self.frame_top.pack(fill='x', padx=20, pady=10)
self.btn_load = ctk.CTkButton(self.frame_top, text='BIN טען קובץ', command=self.load_bin_file)
self.btn_load.pack(side='left', padx=10)
self.lbl_status = ctk.CTkLabel(self.frame_top, text='(קריאים לא קבצים כולל)...הכל סורק', text_color='orange')
self.lbl_status.pack(side='left', padx=10)
self.progress_bar = ctk.CTkProgressBar(self.frame_top, width=300)
self.progress_bar.set(0)
self.progress_bar.pack(side='right', padx=10)
# --- Tabs ---
self.tabview = ctk.CTkTabview(self)
self.tabview.pack(fill='both', expand=True, padx=20, pady=5)
self.tab_img = self.tabview.add('וגרפיקה תמונות') # "Images and Graphics"
self.tab_audio = self.tabview.add('אודיו')
self.tab_text = self.tabview.add('טקסטים (Strings)')
self.list_img = self.create_scrollable_list(self.tab_img)
self.list_audio = self.create_scrollable_list(self.tab_audio)
self.textbox = ctk.CTkTextbox(self.tab_text, wrap='none', font=('Courier', 12))
self.textbox.pack(fill='both', expand=True, padx=5, pady=5)
# --- Bottom ---
self.frame_bottom = ctk.CTkFrame(self)
self.frame_bottom.pack(fill='x', padx=20, pady=10)
# This button is for the "Selected" logic, but we also have per-row buttons now
self.btn_replace_global = ctk.CTkButton(self.frame_bottom, text='חדש BIN ושמור פריט החלף 💾',
fg_color='#E74C3C', state='disabled')
self.btn_replace_global.pack(pady=10)
self.lbl_info = ctk.CTkLabel(self.frame_bottom, text='להחלפה פריט בחר')
self.lbl_info.pack()
def create_scrollable_list(self, parent):
frame = ctk.CTkScrollableFrame(parent)
frame.pack(fill='both', expand=True)
return frame
def load_bin_file(self):
path = filedialog.askopenfilename(filetypes=[
('BIN Files', '*.bin'),
('All Files', '*.*')])
if not path:
return
self.bin_path = path
# Clear previous UI
for widget in self.list_img.winfo_children(): widget.destroy()
for widget in self.list_audio.winfo_children(): widget.destroy()
self.textbox.delete('0.0', 'end')
self.lbl_status.configure(text='...סורק', text_color='orange')
threading.Thread(target=self.scan_file_thread, daemon=True).start()
def scan_file_thread(self):
try:
self.resources = []
with open(self.bin_path, 'rb') as f:
data = f.read()
self.extract_dir = os.path.join(os.path.dirname(self.bin_path), 'Full_Extraction')
if not os.path.exists(self.extract_dir):
os.makedirs(self.extract_dir)
signatures = {
'png': b'\x89PNG\r\n\x1a\n',
'jpg': b'\xff\xd8\xff',
'gif': b'GIF8',
'bmp': b'BM',
'mp3': b'ID3',
'wav': b'RIFF'
}
total_len = len(data)
count_valid = 0
for ext, sig in signatures.items():
start = 0
while True:
index = data.find(sig, start)
if index == -1:
break
if count_valid % 50 == 0:
self.progress_bar.set(index / total_len)
end_index = index + 50000
try:
if ext == 'png':
iend = data.find(b'IEND', index)
if iend != -1: end_index = iend + 8
elif ext == 'jpg':
eoi = data.find(b'\xff\xd9', index)
if eoi != -1: end_index = eoi + 2
elif ext == 'gif':
terminator = data.find(b';', index + 6)
if terminator != -1 and (terminator - index) < 100000: end_index = terminator + 1
elif ext == 'bmp':
size_bytes = data[index + 2 : index + 6]
bmp_size = int.from_bytes(size_bytes, 'little')
if 0 < bmp_size < 1000000: end_index = index + bmp_size
raw_data = data[index : end_index]
status_text = 'תקין'
display_path = ''
if ext in ('png', 'jpg', 'gif', 'bmp'):
img_obj = Image.open(io.BytesIO(raw_data))
filename = f"img_{index}.png"
display_path = os.path.join(self.extract_dir, filename)
img_obj.save(display_path, 'PNG')
else:
filename = f"sound_{index}.{ext}"
display_path = os.path.join(self.extract_dir, filename)
with open(display_path, 'wb') as tmp:
tmp.write(raw_data)
res_type = 'audio' if ext in ('mp3', 'wav') else 'image'
except Exception:
status_text = '(נתמך לא) RAW'
filename = f"raw_{index}.{ext}"
display_path = os.path.join(self.extract_dir, filename)
with open(display_path, 'wb') as tmp:
tmp.write(raw_data)
res_type = 'image'
res_info = {
'id': count_valid,
'type': res_type,
'ext': ext,
'offset': index,
'size': end_index - index,
'path': display_path,
'status': status_text
}
self.resources.append(res_info)
# Update UI in batches to prevent freezing
if count_valid % 5 == 0:
self.after(0, lambda r=res_info: self.add_item_to_list(r))
else:
# For speed, only fully render every 5th item immediately or just render all at end?
# The logic below renders one by one safely
self.after(0, lambda r=res_info: self.add_item_to_list(r))
count_valid += 1
start = end_index
# String extraction
text_data = ''
strings = re.findall(b'[a-zA-Z0-9\\s\\.\\-\\_\\:\\@]{4,}', data)
for s in strings:
try:
decoded = s.decode('utf-8').strip()
if len(decoded) > 3: text_data += decoded + '\n'
except: pass
self.after(0, lambda: self.textbox.insert('0.0', text_data))
self.after(0, lambda: self.finish_scan(count_valid))
except Exception as e:
print(e)
self.lbl_status.configure(text='שגיאה בסריקה', text_color='red')
def add_item_to_list(self, item):
target_list = self.list_img if item['type'] == 'image' else self.list_audio
# Main Row Frame
frame = ctk.CTkFrame(target_list, height=40)
frame.pack(fill='x', pady=2, padx=5)
# Info Text (Left aligned like screenshot)
# Format: מיקום: 610240 | גודל: 27599 | סוג: PNG | סטטוס: תקין
text_info = f"מיקום: {item['offset']} | גודל: {item['size']} | סוג: {item['ext'].upper()} | סטטוס: {item['status']}"
lbl = ctk.CTkLabel(frame, text=text_info, anchor="w", text_color="#F1C40F" if "RAW" in item['status'] else "white")
lbl.pack(side='left', padx=10)
# Buttons (Right aligned)
# Open Button (Blue)
btn_open = ctk.CTkButton(frame, text="פתח", width=60, height=25,
command=lambda: self.open_file(item['path']))
btn_open.pack(side='right', padx=5, pady=5)
# Replace Button (Orange)
btn_replace = ctk.CTkButton(frame, text="החלף", width=60, height=25, fg_color="#E67E22", hover_color="#D35400",
command=lambda: self.replace_specific_item(item))
btn_replace.pack(side='right', padx=5, pady=5)
def open_file(self, filepath):
if not os.path.exists(filepath): return
try:
if platform.system() == 'Darwin': # macOS
subprocess.call(('open', filepath))
elif platform.system() == 'Windows': # Windows
os.startfile(filepath)
else: # linux variants
subprocess.call(('xdg-open', filepath))
except:
pass
def replace_specific_item(self, item):
"""Logic to replace a specific item and save the BIN"""
new_file_path = filedialog.askopenfilename(title=f"בחר קובץ להחלפת {item['ext']}")
if not new_file_path: return
try:
with open(new_file_path, 'rb') as f:
new_data = f.read()
if len(new_data) > item['size']:
if not messagebox.askyesno("אזהרה", "הקובץ החדש גדול מהמקורי! האם להמשיך? (עלול לגרום לנזק)"):
return
# Read original bin
with open(self.bin_path, 'rb') as f:
bin_data = bytearray(f.read())
# Patch
offset = item['offset']
bin_data[offset : offset + len(new_data)] = new_data
# Save
save_path = filedialog.asksaveasfilename(defaultextension=".bin", filetypes=[("BIN", "*.bin")])
if save_path:
with open(save_path, 'wb') as f:
f.write(bin_data)
messagebox.showinfo("הצלחה", "הקובץ נשמר בהצלחה!")
except Exception as e:
messagebox.showerror("שגיאה", str(e))
def finish_scan(self, count):
self.progress_bar.set(1)
self.lbl_status.configure(text=f'נמצאו {count} קבצים', text_color='green')
if __name__ == "__main__":
app = MTKExplorer()
app.mainloop()
מה שדי איטי ולוקח זמן בגלל שהקוד רץ 6 פעמים על אותו קובץ במקום לעשות סריקה אחת כללית,
לכן אני ממליץ לך במקום מה שיש עכשיו שתעבור להשתמש בחיפוש regex או ליצור תוכנה שמתבססת על binwalk
בנוסף הממשק קופא ונהיה מאוד איטי בגלל שtiknter לא מיועד לכזאת מהירות של עדכונים