目前只遇到一个词典触发。
问题mdx供各位研究:
疑难字三考.mdx (25.0 KB)
Traceback (most recent call last):
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 737, in <module>
mdx = MDX(args.filename, args.encoding, args.substyle, args.passcode)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 660, in __init__
MDict.__init__(self, fname, encoding, passcode)
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 115, in __init__
self._key_list = self._read_keys()
^^^^^^^^^^^^^^^^^
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 365, in _read_keys
return self._read_keys_v1v2()
^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 448, in _read_keys_v1v2
key_block_info_list = self._decode_key_block_info(key_block_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 197, in _decode_key_block_info
assert(key_block_info_compressed[:4] == b'\x02\x00\x00\x00')
AssertionError
将
if self._version >= 2:
# zlib compression
assert(key_block_info_compressed[:4] == b'\x02\x00\x00\x00')
# decrypt if needed
if self._encrypt & 0x02:
key = ripemd128(key_block_info_compressed[4:8] + pack(b'<L', 0x3695))
key_block_info_compressed = key_block_info_compressed[:8] + _fast_decrypt(key_block_info_compressed[8:], key)
# decompress
key_block_info = zlib.decompress(key_block_info_compressed[8:])
# adler checksum
adler32 = unpack('>I', key_block_info_compressed[4:8])[0]
assert(adler32 == zlib.adler32(key_block_info) & 0xffffffff)
替换为
if self._version >= 2:
# 块头 4 字节是压缩方式(小端):02 00 00 00 = zlib(标准写法),
# 00 00 00 00 = 不压缩。官方 MdxBuilder 对 Encrypted=2(禁止导出)
# 的词典写后者,旧实现只认前者,于是报「魔数不匹配」。
# 后面仍有 adler32 校验兜底,放宽不会误放行损坏文件。
head = key_block_info_compressed[:4]
if head == b'\x02\x00\x00\x00': use_zlib = True
elif head == b'\x00\x00\x00\x00': use_zlib = False
else: raise ValueError("MDX key block info 魔数不匹配")
if self._encrypt & 0x02:
key = ripemd128(key_block_info_compressed[4:8] + pack(b'<L', 0x3695))
key_block_info_compressed = key_block_info_compressed[:8] + _fast_decrypt(key_block_info_compressed[8:], key)
payload = key_block_info_compressed[8:]
key_block_info = zlib.decompress(payload) if use_zlib else payload
adler32 = unpack('>I', key_block_info_compressed[4:8])[0]
actual = zlib.adler32(key_block_info) & 0xffffffff
if adler32 != actual:
raise ValueError(f"MDX key block info 校验失败 (adler32): 期望 {adler32:#x}, 实际 {actual:#x}")
可以解决。
AI分析如下:
文件没问题,是解析器的兼容性限制。 你用官方工具打包的 2.0 + Encrypted=2(禁止导出),这类词典的 key block info 用的是「无压缩」写法,而项目把魔数硬编码成了「zlib」。
| 线索 | 结论 |
|---|---|
| 740 处 0d 92 01 3d | 我算过 zlib.adler32(struct.pack(‘>QQQQQ’,1,1829,80,88,10048)) = 0x0d92013d,正是 40 字节索引头的校验和 → 布局完全标准,偏移没错 |
| 88 = 80 + 8 | 压缩后只比解压后多 8 字节头,说明根本没有 zlib 压缩 |
| [4] 在 832 找到的 02 00 00 00 | 744+88=832,是 key block 的块头(诊断脚本误判,已修正说明) |
| 744 处 00 00 00 00 | 块头 compression_method=0(不压缩),不是损坏 |
| 解密后 [8:16] = 00 00 00 00 00 00 07 25 | 大端 = 1829,正好等于 num_entries → 密钥 ripemd128([4:8]+0x3695) 和「只解密 [8:]」项目原本都是对的,唯独解压方式猜错了 |