Members Sentinel Posted February 12 Members Posted February 12 (edited) Hi, guys. Someone help me? I need extract and repack phyton script or quickbms script for this game file... Sample file here https://www.mediafire.com/file/5hoyfzm50m4w14u/Majin+and+Forsaken+Kingdom.rar/file Edited February 12 by Sentinel
Engineers shak-otay Posted February 12 Engineers Posted February 12 (edited) Guess, this request is better addressed in compressed files forum. Anyways, using offzip I got a 2 MB dat file (besides 5 *.kap). The contents of the .dat ("gfxfontlibD"), a blurred picture, gives me a déjà-vu but I have no idea what exactly. Edited February 12 by shak-otay
Supporter wq223 Posted February 12 Supporter Posted February 12 1 hour ago, shak-otay said: Guess, this request is better addressed in compressed files forum. Anyways, using offzip I got a 2 MB dat file (besides 5 *.kap). The contents of the .dat ("gfxfontlibD"), a blurred picture, gives me a déjà-vu but I have no idea what exactly. This file has only two compression blocks, both of which are zlib compressed. The first compressed block needs to use the -15 parameter, the second compressed block has a 78DA compression header and can be decompressed directly The first metadata contains multiple file name indexes, but there is only one compressed data. Could it be that the decompressed data contains multiple file data? 1
Engineers shak-otay Posted February 12 Engineers Posted February 12 (edited) 1 hour ago, wq223 said: The first compressed block needs to use the -15 parameter, the second compressed block has a 78DA compression header and can be decompressed directly What do you mean by "directly"? (78DA can be found 32 times in the pak, btw.) Edited February 12 by shak-otay
Supporter wq223 Posted February 12 Supporter Posted February 12 37 minutes ago, shak-otay said: What do you mean by "directly"? (78DA can be found 32 times in the pak, btw.) My script includes 78DA in the compressed data 78DA is the best compression. It should have this compressed data part and can be decompressed directly without parameters, because there is no offset to prove whether the original file detached from this file starts with CFX, 78DA, or subsequent compressed data. But for the data starting with the first compressed data AC97, I must use parameters to decompress, otherwise my script cannot recognize that this is a zlib compressed data .
Engineers Rabatini Posted February 13 Engineers Posted February 13 2 hours ago, Sentinel said: Result? kb_text_us.zip 1
Members Sentinel Posted February 13 Author Members Posted February 13 8 hours ago, Rabatini said: kb_text_us.zip 113.96 kB · 2 downloads I think the localization files are inaccessible. The file seems to be encrypted.
Engineers shak-otay Posted February 13 Engineers Posted February 13 (edited) This is not encrypted: Quote Of critical importance to defeating the darkness is the trust between our hero and the Majin. Edited February 13 by shak-otay 1
Members Sentinel Posted February 13 Author Members Posted February 13 7 hours ago, shak-otay said: This is not encrypted: Yes, he is a hero.
Members Sentinel Posted February 15 Author Members Posted February 15 On 2/13/2026 at 4:40 AM, Rabatini said: kb_text_us.zip 113.96 kB · 3 downloads Could you make a tool for Localization?
Members zbirow Posted February 17 Members Posted February 17 I analyzed the text data blocks. Below you can see their structure, along with a simple Python preview tool. (The first few dozen entries are empty, so you have to scroll down quite a bit.) That's all I can help with. Structures: 4 MAGIC 2 padding 2 ID1 13 UNK 4 UNK2 8 UNK3 2 padding 2 ID2 5 UNK4 4 LENGTH (BE) TEXT (UTF-16LE) 2 00 00 8 FF import tkinter as tk from tkinter import filedialog, ttk import struct MAGIC = b"\x17\xD2\x25\xE3" class ParserGUI: def __init__(self, root): self.root = root self.root.title("Binary Text Parser") self.records = [] btn = tk.Button(root, text="Load File", command=self.load_file) btn.pack(pady=5) self.tree = ttk.Treeview(root, columns=("offset", "id1", "id2", "len"), show="headings") self.tree.heading("offset", text="OFFSET") self.tree.heading("id1", text="ID1") self.tree.heading("id2", text="ID2") self.tree.heading("len", text="TEXT LEN") self.tree.pack(fill="both", expand=True) self.tree.bind("<<TreeviewSelect>>", self.show_record) self.tabs = ttk.Notebook(root) self.tabs.pack(fill="both", expand=True) self.fields = {} for name in ["ID1", "UNK", "UNK2", "UNK3", "ID2", "UNK4", "TEXT"]: frame = ttk.Frame(self.tabs) self.tabs.add(frame, text=name) txt = tk.Text(frame, wrap="word") txt.pack(fill="both", expand=True) self.fields[name] = txt self.log = tk.Text(root, height=12, bg="black", fg="lime") self.log.pack(fill="both", expand=False) def log_print(self, msg): self.log.insert("end", msg + "\n") self.log.see("end") def load_file(self): path = filedialog.askopenfilename(title="Select a binary file") if not path: return with open(path, "rb") as f: data = f.read() self.records.clear() self.tree.delete(*self.tree.get_children()) self.log.delete("1.0", "end") self.parse(data) def parse(self, data): offset = 0 magic_count = 0 while True: pos = data.find(MAGIC, offset) if pos == -1: break magic_count += 1 self.log_print(f"\n--- MAGIC found @ 0x{pos:X} ---") try: cur = pos + 4 padding1 = data[cur:cur+2] cur += 2 id1 = data[cur:cur+2] cur += 2 hash1 = data[cur:cur+13] cur += 13 A = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 hash2 = data[cur:cur+8] cur += 8 padding2 = data[cur:cur+2] cur += 2 id2 = data[cur:cur+2] cur += 2 hash3 = data[cur:cur+5] cur += 5 length = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 self.log_print(f"ID1={id1.hex().upper()} ID2={id2.hex().upper()} LENGTH={length}") if length <= 0 or length > 10000: self.log_print("❌ Suspicious length — skipping record") offset = pos + 4 continue text_bytes = data[cur:cur + (length * 2)] cur += length * 2 text = text_bytes.decode("utf-16be", errors="ignore").replace("\x00", "") if data[cur:cur+2] == b"\x00\x00": cur += 2 if data[cur:cur+8] == b"\xFF"*8: cur += 8 record = { "offset": pos, "ID1": id1.hex().upper(), "UNK": hash1.hex().upper(), "UNK2": A, "UNK3": hash2.hex().upper(), "ID2": id2.hex().upper(), "UNK4": hash3.hex().upper(), "TEXT": text } self.records.append(record) except Exception as e: self.log_print(f"❌ Parsing error: {e}") offset = pos + 4 self.log_print(f"\nMAGIC occurrences found: {magic_count}") self.log_print(f"Records parsed: {len(self.records)}") for r in self.records: self.tree.insert("", "end", values=( hex(r["offset"]), r["ID1"], r["ID2"], len(r["TEXT"]) )) def show_record(self, event): sel = self.tree.selection() if not sel: return index = self.tree.index(sel[0]) record = self.records[index] for key in self.fields: self.fields[key].delete("1.0", "end") self.fields[key].insert("1.0", str(record[key])) if __name__ == "__main__": root = tk.Tk() root.geometry("1000x800") app = ParserGUI(root) root.mainloop() 1
Members Sentinel Posted February 17 Author Members Posted February 17 10 hours ago, zbirow said: I analyzed the text data blocks. Below you can see their structure, along with a simple Python preview tool. (The first few dozen entries are empty, so you have to scroll down quite a bit.) That's all I can help with. Structures: 4 MAGIC 2 padding 2 ID1 13 UNK 4 UNK2 8 UNK3 2 padding 2 ID2 5 UNK4 4 LENGTH (BE) TEXT (UTF-16LE) 2 00 00 8 FF import tkinter as tk from tkinter import filedialog, ttk import struct MAGIC = b"\x17\xD2\x25\xE3" class ParserGUI: def __init__(self, root): self.root = root self.root.title("Binary Text Parser") self.records = [] btn = tk.Button(root, text="Load File", command=self.load_file) btn.pack(pady=5) self.tree = ttk.Treeview(root, columns=("offset", "id1", "id2", "len"), show="headings") self.tree.heading("offset", text="OFFSET") self.tree.heading("id1", text="ID1") self.tree.heading("id2", text="ID2") self.tree.heading("len", text="TEXT LEN") self.tree.pack(fill="both", expand=True) self.tree.bind("<<TreeviewSelect>>", self.show_record) self.tabs = ttk.Notebook(root) self.tabs.pack(fill="both", expand=True) self.fields = {} for name in ["ID1", "UNK", "UNK2", "UNK3", "ID2", "UNK4", "TEXT"]: frame = ttk.Frame(self.tabs) self.tabs.add(frame, text=name) txt = tk.Text(frame, wrap="word") txt.pack(fill="both", expand=True) self.fields[name] = txt self.log = tk.Text(root, height=12, bg="black", fg="lime") self.log.pack(fill="both", expand=False) def log_print(self, msg): self.log.insert("end", msg + "\n") self.log.see("end") def load_file(self): path = filedialog.askopenfilename(title="Select a binary file") if not path: return with open(path, "rb") as f: data = f.read() self.records.clear() self.tree.delete(*self.tree.get_children()) self.log.delete("1.0", "end") self.parse(data) def parse(self, data): offset = 0 magic_count = 0 while True: pos = data.find(MAGIC, offset) if pos == -1: break magic_count += 1 self.log_print(f"\n--- MAGIC found @ 0x{pos:X} ---") try: cur = pos + 4 padding1 = data[cur:cur+2] cur += 2 id1 = data[cur:cur+2] cur += 2 hash1 = data[cur:cur+13] cur += 13 A = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 hash2 = data[cur:cur+8] cur += 8 padding2 = data[cur:cur+2] cur += 2 id2 = data[cur:cur+2] cur += 2 hash3 = data[cur:cur+5] cur += 5 length = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 self.log_print(f"ID1={id1.hex().upper()} ID2={id2.hex().upper()} LENGTH={length}") if length <= 0 or length > 10000: self.log_print("❌ Suspicious length — skipping record") offset = pos + 4 continue text_bytes = data[cur:cur + (length * 2)] cur += length * 2 text = text_bytes.decode("utf-16be", errors="ignore").replace("\x00", "") if data[cur:cur+2] == b"\x00\x00": cur += 2 if data[cur:cur+8] == b"\xFF"*8: cur += 8 record = { "offset": pos, "ID1": id1.hex().upper(), "UNK": hash1.hex().upper(), "UNK2": A, "UNK3": hash2.hex().upper(), "ID2": id2.hex().upper(), "UNK4": hash3.hex().upper(), "TEXT": text } self.records.append(record) except Exception as e: self.log_print(f"❌ Parsing error: {e}") offset = pos + 4 self.log_print(f"\nMAGIC occurrences found: {magic_count}") self.log_print(f"Records parsed: {len(self.records)}") for r in self.records: self.tree.insert("", "end", values=( hex(r["offset"]), r["ID1"], r["ID2"], len(r["TEXT"]) )) def show_record(self, event): sel = self.tree.selection() if not sel: return index = self.tree.index(sel[0]) record = self.records[index] for key in self.fields: self.fields[key].delete("1.0", "end") self.fields[key].insert("1.0", str(record[key])) if __name__ == "__main__": root = tk.Tk() root.geometry("1000x800") app = ParserGUI(root) root.mainloop() Thanks a lot
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now