Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.
Zero Tolerance for Disrespect

Majin And The Forsaken Kingdom pak file

Featured Replies

  • Sentinel changed the title to Majin And The Forsaken Kingdom pak file
  • Supporter

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.

majin-us-pak.png.dbcfc8f7f7db09a5824915e8fc8a951d.png

Edited by shak-otay

  • Supporter
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.

majin-us-pak.png.dbcfc8f7f7db09a5824915e8fc8a951d.png

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?

  • Supporter
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 by shak-otay

  • Supporter
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

.

  • Supporter

This is not encrypted:

Quote

Of critical importance to defeating
the darkness is the trust
between our hero and the Majin.

 

Edited by shak-otay

  • Author
  • Localization
7 hours ago, shak-otay said:

This is not encrypted:

 

Yes, he is a hero. 

  • Localization


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()

 

  • Author
  • Localization
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

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.