December 26, 2025Dec 26 https://hiddenpalace.org/Ben_10_(Aug_5,_2007_prototype) I cannot find any tools or scripts to unpack this file any help? I noticed a lot of gsc.zlib , .txt, .jpg , .png , .txt.zlip , .3GM , and .3gm.zlib by a quick examination in HxD code.rar
December 26, 2025Dec 26 Supporter Hard to tell. I'd suggest to start the exe from the prototype in a sandbox/virtual machine and examine its RAM contents.
December 27, 2025Dec 27 Localization Solution import tkinter as tk from tkinter import filedialog, messagebox, scrolledtext import struct import os import threading import zlib class GrvExtractorApp: def __init__(self, root): self.root = root self.root.title("GRV Extractor Tool") self.root.geometry("650x500") self.root.resizable(True, True) self.file_path = tk.StringVar() self.output_path = tk.StringVar() self.auto_decompress = tk.BooleanVar(value=True) self.create_widgets() def create_widgets(self): main_frame = tk.Frame(self.root, padx=10, pady=10) main_frame.pack(fill=tk.BOTH, expand=True) main_frame.columnconfigure(1, weight=1) tk.Label(main_frame, text="Select .grv File:").grid(row=0, column=0, sticky="w", pady=5) entry_file = tk.Entry(main_frame, textvariable=self.file_path, width=30) entry_file.grid(row=0, column=1, sticky="ew", padx=5, pady=5) tk.Button(main_frame, text="Browse", command=self.browse_file).grid(row=0, column=2, sticky="e", padx=5, pady=5) tk.Label(main_frame, text="Output Folder:").grid(row=1, column=0, sticky="w", pady=5) entry_out = tk.Entry(main_frame, textvariable=self.output_path, width=30) entry_out.grid(row=1, column=1, sticky="ew", padx=5, pady=5) tk.Button(main_frame, text="Browse", command=self.browse_folder).grid(row=1, column=2, sticky="e", padx=5, pady=5) chk_decompress = tk.Checkbutton(main_frame, text="Auto-decompress .zlib files", variable=self.auto_decompress) chk_decompress.grid(row=2, column=0, columnspan=3, sticky="w", pady=5) self.extract_btn = tk.Button(main_frame, text="Extract Files", command=self.start_extraction, bg="#dddddd", height=2) self.extract_btn.grid(row=3, column=0, columnspan=3, sticky="ew", pady=15) self.log_area = scrolledtext.ScrolledText(main_frame, height=15) self.log_area.grid(row=4, column=0, columnspan=3, sticky="nsew") main_frame.grid_rowconfigure(4, weight=1) def browse_file(self): filename = filedialog.askopenfilename(filetypes=[("GRV Files", "*.grv"), ("All Files", "*.*")]) if filename: self.file_path.set(filename) def browse_folder(self): foldername = filedialog.askdirectory() if foldername: self.output_path.set(foldername) def log(self, message): self.log_area.insert(tk.END, message + "\n") self.log_area.see(tk.END) def read_string(self, f): chars = [] while True: c = f.read(1) if not c or c == b'\x00': break chars.append(c) return b"".join(chars).decode('utf-8', errors='ignore') def start_extraction(self): input_file = self.file_path.get() output_dir = self.output_path.get() if not input_file or not os.path.exists(input_file): messagebox.showerror("Error", "Please select a valid input file.") return if not output_dir: messagebox.showerror("Error", "Please select an output folder.") return self.extract_btn.config(state=tk.DISABLED) self.log_area.delete(1.0, tk.END) thread = threading.Thread(target=self.run_extraction, args=(input_file, output_dir)) thread.start() def run_extraction(self, filename, output_dir): try: with open(filename, 'rb') as f: self.log(f"Opening {filename}...") f.seek(19) count_bytes = f.read(2) if not count_bytes: self.log("Error: Failed to read file count.") return file_count = struct.unpack('>H', count_bytes)[0] self.log(f"Found {file_count} files.") self.log("-" * 40) files_list = [] for _ in range(file_count): meta_chunk = f.read(12) if len(meta_chunk) < 12: break try: offset_val = struct.unpack('>I', meta_chunk[4:8])[0] size_val = struct.unpack('>I', meta_chunk[8:12])[0] except struct.error: self.log("Error parsing header.") break name = self.read_string(f) files_list.append({ 'name': name, 'offset': offset_val, 'size': size_val }) for item in files_list: if not item['name'] or item['offset'] == 0: continue try: f.seek(item['offset']) raw_data = f.read(item['size']) final_name = item['name'] final_data = raw_data decompressed = False if self.auto_decompress.get() and final_name.lower().endswith('.zlib'): try: if len(raw_data) > 4: payload = raw_data[4:] final_data = zlib.decompress(payload) final_name = final_name[:-5] decompressed = True except Exception as zlib_error: self.log(f"Warning: Decompression failed for {final_name} ({zlib_error}). Saving original.") save_path = os.path.join(output_dir, final_name) os.makedirs(os.path.dirname(save_path), exist_ok=True) with open(save_path, 'wb') as out_f: out_f.write(final_data) status = " [Decompressed]" if decompressed else "" self.log(f"Extracted: {final_name}{status}") except Exception as e: self.log(f"Error extracting {item['name']}: {e}") self.log("-" * 40) self.log("Done.") messagebox.showinfo("Success", "Extraction complete!") except Exception as e: self.log(f"Critical Error: {e}") messagebox.showerror("Error", str(e)) finally: self.extract_btn.config(state=tk.NORMAL) if __name__ == "__main__": root = tk.Tk() app = GrvExtractorApp(root) root.mainloop() code for unpacking a file, with support for unpacking .zlib files. .jpg files are not .jpg image files because they have a different Magic header.
February 10Feb 10 Localization Added proper support for it in my extractor which also covers edge cases which the above script doesn't (namely the root name thingy being named something other than root) https://github.com/smiRaphi/UniPyX
Create an account or sign in to comment