PS2 《日本语大词典》 格式分析和解压脚本(mdx已经制作)

之前我尝试安装过,结果失败了,我以为是缺数据,因为这个iso太小了不正常,后来发现是没有正确把虚拟硬盘格式化为ps2的格式,PS2版本身似乎没有原版的大量插图。

这次试了下ai辅助逆向,发现非常好用,从bin里面解压了压缩数据包和可执行文件,然后配置ida的mcp server,后面直接全部交给ai处理,然后调整几次指令ai直接就分析完然后写好代码了,下面是ai输出的格式分析文档。

PS2 gj1.arh & gj1.arz Archive Reverse Engineering Walkthrough

1. Finding the Archive Parsing Logic

The objective was to reverse engineer gj1.arh and gj1.arz. By searching strings in the binary (SLPS_201.16) within IDA via idassistmcp, load_archive (at 0x142398) was located. It verifies two signatures:

  • adzh at the start of .arh
  • adzp00000000 at the start of .arz

Tracing how buf_arh is utilized led to sub_102C60 and sub_103C90, which opens the archives, followed by sub_142530 that looks up files by name.

2. .arh Header Format

The *.arh file acts as an index directory structure:

  1. 0x00 - 4 bytes: Magic signature adzh
  2. 0x04 - 4 bytes: Number of index blocks (UInt32)
  3. 0x08 onwards: Records containing entries for internal paths. Each record includes:
    • Null-terminated String: The directory path/label.
    • 4 bytes (UInt32): Offset of this directory block inside the .arz file.
    • 2 bytes (UInt16): Size of the directory block inside the .arz file.

3. .arz Block Internal Format

Inside .arz, at the offset designated by .arh, lies a directory block mapping file names to raw data:

  • Repeating null-terminated entries.
  • Immediately following the null-terminator:
    • 4 bytes (UInt32): Absolute offset to the file data inside .arz.
    • 4 bytes (UInt32): Size of the file chunk.
    • 1 byte (UInt8): Compression flag (0 = Uncompressed, 1 = Compressed).

4. Uncovering the Compression Algorithm

The user provided a hint that the data is compressed. I analyzed the read_file wrapper logic and sub_1040E0, encountering the decompression function at sub_143B20.

The algorithm is a custom variant of LZSS:

  1. XOR Encryption: The compressed payload (starting at offset 0x08) is XORed with 0x72.
  2. Header: The first 8 bytes contain metadata. Specifically, offset 0x04 (4 bytes) dictates the original decompressed size.
  3. LZSS Parameters:
    • Sliding window (ring buffer) size: 4096 (0x1000) bytes, initialized to 0x00.
    • Initial write position: 4078.
    • Control byte flags read incrementally. If the lowest bit is 1, a raw byte is outputted. If 0, a 2-byte LZSS back-reference is read (Offset=12 bits, Length=4 bits + 2).

5. Reverse Engineering the .agi Image Format

After extracting the .arz blocks, many of the visual assets possessed the .agi extension.
Inspecting the binary layout of these files reveals that they represent raw PlayStation 2 Graphical Synthesizer (GS) texture mappings:

  1. Header (48 bytes):

    • offset 0x08: File offset to pixel data.
    • offset 0x0E: Format Flag (0x13 = 8-bit indexed, 0x14 = 4-bit indexed).
    • offset 0x18: Width (4 bytes).
    • offset 0x1A: Height (4 bytes).
    • The rest consists of memory-mapping relocations handled by PS2 hardware.
  2. Pixel Data: Stored directly starting at the Pixel Offset. It is entirely linear.

  • For 4-bit images, nibbles encode indices pixel-by-pixel.
  • For 8-bit images, full bytes encode indices.
  1. Palette Data: Stored immediately following the pixel data chunk.
  • 4-bit: 16 colors (64 bytes).
  • 8-bit: 256 colors (1024 bytes). PS2 256-color palettes are ‘swizzled’ in blocks of 8 entries, so the index mapping requires swapping bits 3 and 4 of the color index lookup.
  • The PS2 alpha channel (A) only ranges from 0 to 128 (translating 128255 in modern RGBA).

6. Verification

A Python script ([extract_arz.py](extract_arz.py)) was developed that fully parses the .arh index, reads the .arz block tables, unpacks the custom XOR+LZSS scheme, and writes out standard, uncompressed assets. Successfully extracted 5759 files into the extracted_decomp_gj1 workspace folder.

Another Python script ([parse_agi.py](parse_agi.py)) was developed to read those raw PS2 textures, un-swizzle the indexed palettes, unpack half-bytes, and convert them to standard .png images. Validated correctly via visual checks with the user.

数据似乎就是epwing版本的源文件,格式很好:

后续我将尝试ocr中文版,然后把这个也整理成双解版。数据包含原始数据,解压脚本,解压后的文件和转换后的图片。
数据和文档下载:PS2 日本语大词典
链接: 百度网盘 请输入提取码 提取码: 1234

8 Likes

好可怕,图像格式的逆向,AI只看了二进制就知道了?看来人力逆向真被淘汰了。

我感觉模型本身应该有前置知识,因为ps2相关的研究挺多的了,然后ai分析代码后还运行了指令测试。我之前也没试过,刚开始手动分析了两个函数,然后感觉比较费时间,就改去研究vibe re的流程,没想到这么快。

深表谢忱!虽然确实看不懂,但感觉很厉害!
有些坐等其享了,现在的技术真的太厉害了,几年前还都是看着纸质版,摘录不懂的词汇,写到纸上,再录入表格中···
再次感谢!
心情有些迫不及待,想请问您,我已经下载了本贴的数据,从HTML就可以预览了,真心激动····
想再咨询您,是否可以将这个HTML合成TXT呢?总占用您时间,很冒昧···谢谢!

不是的,agi是这个日本公司自造的,在ps2不通行,基于bmp的魔改,基本结构和bmp差不多,test目录有它们测试的转换,基于gif和bmp转换测试了两次。

我是怀疑我曾经偷懒让gemini写代码,它都记住了。。

图像基本就是长宽高,mip,像素格式这些字段,主要是数据格式。因为ps2能读取的格式是有限的而且是网上有相关资料的。就和windows下DXT和手机上的PVRTC一样的。要是手动分析也是从怎么传给渲染api开始分析。

渲染函数我看过,之后基本就是交给gpu光栅化过程,很复杂,我的水平是读不懂。我是笨方法,对着test目录下的案例,一个个字节比对,发现差不多,文件头全靠猜。不过看到ai很顺利解出来了,有点不甘啊。

1 Like

还有,代码要调整,我记得彩色图片(8-bit图片)调色板有坑,我是来回改了好几次,你有转换结果是错的(sample目录下的test.png图片完全不符合原来的gif和bmp,果然gemini还是会犯这个错误),虽然也不关键就是了,对4bit的灰度书法图片无影响。TVWare情报革命同系列的其他词典彩图比较多,会有点影响。



具体细节好像可以参考这里,我忘了:

1 Like

代码和数据都调整了,之前没注意这里,只看了汉字那部分。

不懂技术真要命啊,尝试用了工具转HTML为TXT,可能因为编码问题吧,全是乱码····今年要好好利用论坛资源,好好学习了

还是错的啊,别让AI写了,自己看看吧。检验正确的基准就是sample目录的test.png是否和原始的test.bmp和test.gif一致。nload1.png还是错的,不信你自己打开模拟器自己运行下程序就知道了,肉眼都能看出来不一样,ps2模拟器有texture dump的功能,这也是我检验自己成果的方式之一。不过做这个texture dump的人没有考虑alpha通道的问题,导致dump出来的都是半透明的,把PS2中128最大值基准的不透明当成了其他图片格式的256最大值的半透明。谁有空的话可以给pcsx2的作者提个issue。不过我也不确定这算不算一个需要解决的问题。

转换程序是最好写成转为gif,html里用的也是gif,官方也是用gif转换为agi的,bmp不支持透明度(我是图省事才转的bmp)。

1 Like

这些html文件都是shift jis编码的,如果用其他编码读取再保存就会乱码。

再次请教您有方法能转为TXT格式吗,不行的话,我笨一点儿,导入浏览器,一个个复制也行···11年看到《新世纪日汉》的时候,一下买了三本,撕成一页页地看···当年没技术,现在有了却不会用···

中文系统所有no bom的文本都是默认用GBK解码,很蛋疼,能自主选择解码方式的文本编辑器就emeditor比较好用(甚至能自动检测编码),我暂时没找到别的轻量级的。

你都撕开了啊,送去扫描得了。得到一个高清pdf,OCR一下变成可检索pdf不比txt好用吗?

转成txt是要删除全部格式吗,我是准备制作成mdx词典的。

年纪大了,让您见笑了,那会儿不懂啊,讲谈社的这个也是从二手市场买了好几本,也是撕开了看

感谢 wynick27的支持和协助。MDX文件我倒是会转为TXT,然后在电脑上看,因为年纪缘故,看纸质太费眼睛了,还要用放大镜···讲谈社这本辞典虽然已经快三十年了,作为百科读物还是很有意思的,就是两本辞典同时翻阅真的很费力,后来入手了电子版,导入pad作为阅读书籍也挺好的···个人主要用途不是查词,当然您只做了分享出来,更多的日语学习者会获得更大的帮助····

期待您的巨作!

paddleocr完整识别了日文版的原书,分割了图片:


日本语大词典OCR
链接: 百度网盘 请输入提取码 提取码: 1234

2 Likes