KORG PA600 中文化完整技术手册
目标读者: 本文档站在”普通人看了能还原全部操作”的角度编写,包含完整的思路、原理和操作步骤。
目录
- 项目背景
- 核心技术发现
- PKG固件完整封包解包流程
- 三大需求技术方案
- Style文件修改流程
- 工具链完整说明
- 测试验证记录
- 关键警告与注意事项
- 附录
项目背景
项目目标
KORG PA600电子琴固件v2.10中文化,包含三个核心需求:
- 固件菜单汉化 - UI界面中文显示
- U盘文件名中文显示 - MEDIA界面支持中文文件夹/文件名
- Style名称中文化 - 风格文件名称中文显示
技术挑战
| 挑战 | 描述 | 解决状态 |
|---|---|---|
| PKG格式未知 | KORG专有封装格式 | ✅ 已逆向 |
| ZLIB压缩特殊 | 大端序解压大小 | ✅ 已解决 |
| 字体系统封闭 | 内部/外部字体切换 | ✅ 已突破 |
| Unicode转换 | 中文被转成问号 | ✅ 字体劫持绕过 |
| OPOS加密 | 主程序不可修改 | ⚠️ 无法触碰 |
核心技术发现
发现1: FONTS.PEG字体标记机制
位置: 每个字体文件名前3字节
04 b1 80 → 内部编译字体(默认,从ROM读取)
ff ff 80 → 外部BDF文件(从文件系统读取)
验证实验:
- 修改verdana11.BDF中字符”C”为方块
- 将FONTS.PEG中verdana11的标记改为
ff ff 80 - 刷机后界面所有”C”变方块
结论: 系统支持运行时从外部BDF文件加载字体!
发现2: 中文文件名转换路径
FAT32 (UTF-16 LFN)
↓
OPOS编码转换层
↓
未知字符 → 0x3F ('?')
↓
BDF字体渲染 → 显示问号
劫持点: 使用高位ASCII (0x80-0xFF)绕过转换
发现3: PKG文件ZLIB压缩特殊性
关键: 解压大小字段使用大端序(Big-Endian),与其他字段不同!
comp_size = struct.unpack('<I', f.read(4))[0] - 4 # 小端序
uncomp_size = struct.unpack('>I', f.read(4))[0] # 大端序!
PKG固件完整封包解包流程
本节是普通人复现操作的核心,详细说明每一步的原理和操作。
一、PKG文件格式详解
1.1 整体结构
┌─────────────────────────────────────────┐
│ [16 bytes] PKG MD5 Hash │ ← 文件16字节后所有内容的MD5
├─────────────────────────────────────────┤
│ [Chunk 1] Header │
├─────────────────────────────────────────┤
│ [Chunk 2] SystemFile (kernel) │
├─────────────────────────────────────────┤
│ [Chunk 3] SystemFile (ramdisk) │
├─────────────────────────────────────────┤
│ ... │
├─────────────────────────────────────────┤
│ [Chunk N] FILE/DIRECTORY/LINK │
└─────────────────────────────────────────┘
1.2 Chunk通用结构
┌────────────┬────────────┬─────────────────┬────────────┐
│ Chunk ID │ Chunk Size │ Chunk Data │ Padding │
│ 4 bytes LE │ 4 bytes LE │ N bytes │ 0-3 bytes │
└────────────┴────────────┴─────────────────┴────────────┘
↑
4字节对齐填充
1.3 Chunk类型表
| ID | 名称 | 说明 |
|---|---|---|
| 1 | HEADER | 固件版本信息 |
| 2 | UPDATE_KERNEL | 更新内核镜像 |
| 3 | UPDATE_RAMDISK | 更新内存盘 |
| 15 | INSTALLER_SCRIPT | 安装脚本 |
| 16 | DIRECTORY | 目录 |
| 17 | FILE | 文件(重点修改目标) |
| 18 | LINK | 符号链接 |
| 19 | ROOT_FS | 根文件系统 |
1.4 FILE Chunk详细格式(核心)
┌─────────────────────────────────────────────────────────────────┐
│ FILE Chunk Body │
├─────────────────────────────────────────────────────────────────┤
│ [16 bytes] MD5 Hash ← 解压后数据的MD5 │
│ [2 bytes] Owner ← 文件属主 (little-endian) │
│ [2 bytes] Group ← 文件属组 (little-endian) │
│ [2 bytes] Attributes ← 文件权限 (little-endian) │
│ [2 bytes] Condition ← 条件标志 (little-endian) │
│ [4 bytes] Data Size ← 解压后大小 (little-endian) │
│ [1 byte] Compression ← 压缩类型: 0=RAW, 1=ZLIB, 16=ENCRYPTED │
│ [N bytes] Name ← 文件路径 (null-terminated) │
│ [N bytes] Date ← 日期字符串 (null-terminated) │
│ [N bytes] Time ← 时间字符串 (null-terminated) │
│ [N bytes] Data ← 压缩/原始数据 │
└─────────────────────────────────────────────────────────────────┘
1.5 ZLIB多块压缩格式
当Compression Type = 1时,数据按以下格式分块压缩:
┌────────────────────────────────────────────────────────────────┐
│ ZLIB Block │
├────────────────────────────────────────────────────────────────┤
│ [4 bytes] Block Type ← 0x00000100=数据块, 0x00000101=结束 │
│ [4 bytes] Comp Size + 4 ← 压缩大小+4 (little-endian) │
│ [4 bytes] Uncomp Size ← 解压大小 (BIG-ENDIAN! 关键!) │
│ [N bytes] Zlib Data ← zlib压缩数据 │
│ [0-3 bytes] Padding ← 4字节对齐 │
├────────────────────────────────────────────────────────────────┤
│ [下一个Block...] │
├────────────────────────────────────────────────────────────────┤
│ [4 bytes] 0x00000101 ← 结束标记 │
│ [4 bytes] 0x00000000 ← 空大小 │
└────────────────────────────────────────────────────────────────┘
二、解包操作流程(普通人步骤)
步骤1: 准备环境
# 创建工作目录
mkdir -p /tmp/PA600 && cd /tmp/PA600
# 准备原始固件文件
cp /path/to/_Operating_System_v210.pkg ./
# 确认Python环境
python3 --version # 需要Python 3.6+
步骤2: 列出PKG内所有文件
python3 pkg_tool.py list _Operating_System_v210.pkg
输出示例:
PKG MD5 Hash: 112f8e917c4c97a7d495597fc1bffb67
Files in package:
1. /omega_sys/EDITRES/ENG/Z103AENG.PEG (971561 bytes, ZLIB)
2. /omega_sys/STARTUP/ALL/EDITRES/FONTS.PEG (113743 bytes, ZLIB)
3. /omega_sys/STARTUP/ALL/EDITRES/verdana11.BDF (100326 bytes, ZLIB)
...
24. /omega_sys/OPOS (11240692 bytes, ENCRYPTED) ← 加密文件,不可修改!
步骤3: 提取目标文件
# 提取字体配置文件
python3 pkg_tool.py extract _Operating_System_v210.pkg "FONTS.PEG" ./FONTS.PEG
# 提取字体文件
python3 pkg_tool.py extract _Operating_System_v210.pkg "verdana11.BDF" ./verdana11.BDF
# 提取语言资源文件
python3 pkg_tool.py extract _Operating_System_v210.pkg "Z103AENG.PEG" ./Z103AENG.PEG
步骤4: 验证提取结果
# 检查文件大小
ls -la *.PEG *.BDF
# 验证BDF格式
head -20 verdana11.BDF
# 应该看到: STARTFONT 2.1 / FONT -misc-verdana...
三、修改操作流程
3.1 修改FONTS.PEG(启用外部BDF)
原理: 将verdana系列字体的标记从04 b1 80改为ff ff 80
def modify_fonts_peg(data):
"""修改FONTS.PEG - 启用外部BDF加载"""
data = bytearray(data)
verdana_files = [
b'verdana10.BDF', b'verdana11.bdf', b'verdana9.BDF',
b'verdanab10.BDF', b'verdanab11.BDF', b'verdanab12.BDF',
b'verdanab13.BDF', b'verdanab19.BDF', b'verdanab9.BDF'
]
modified = 0
for vf in verdana_files:
pos = data.find(vf)
if pos != -1:
marker_pos = pos - 3 # 标记在文件名前3字节
if data[marker_pos:marker_pos+3] == bytearray([0x04, 0xb1, 0x80]):
data[marker_pos] = 0xff
data[marker_pos+1] = 0xff
data[marker_pos+2] = 0x80
modified += 1
print(f' {vf.decode()}: 04b180 -> ffff80')
print(f'修改了 {modified} 个字体引用标记')
return bytes(data)
3.2 修改BDF字体(注入汉字)
BDF字符条目格式:
STARTCHAR CN_YIN ← 字符名称
ENCODING 192 ← 字符编码 (0xC0 = 192)
SWIDTH 1000 0 ← 可缩放宽度
DWIDTH 11 0 ← 设备宽度(像素)
BBX 11 11 0 -2 ← 边界框: 宽 高 X偏移 Y偏移
BITMAP ← 位图开始
FFE0 ← 第1行: 11111111 11100000
8020 ← 第2行: 10000000 00100000
... ← (共11行)
ENDCHAR ← 字符结束
注入汉字到高位槽位:
def inject_chinese_char(bdf_content, encoding, char_name, bitmap_lines):
"""向BDF添加一个汉字字符"""
new_entry = f'''STARTCHAR {char_name}
ENCODING {encoding}
SWIDTH 1000 0
DWIDTH 11 0
BBX 11 11 0 -2
BITMAP
{chr(10).join(bitmap_lines)}
ENDCHAR'''
# 在ENDFONT前插入
return bdf_content.replace('ENDFONT', new_entry + '\\nENDFONT')
四、封包操作流程(普通人步骤)
这是最关键的部分,必须正确执行否则固件无法使用!
步骤1: 理解封包流程
1. 打开原始PKG
2. 逐个复制Chunk到新文件
3. 遇到目标文件时:
a. 解压原数据
b. 应用修改函数
c. 重新压缩
d. 计算新MD5
e. 构建新Chunk
4. 保持其他Chunk不变
5. 重新计算PKG总MD5
6. 写入文件头
步骤2: 使用Python工具封包
方法A: 单文件修改 (pkg_modifier.py)
# 测试修改: SOUND → AUDIO
python3 pkg_modifier.py test _Operating_System_v210.pkg output.pkg
方法B: 多文件修改 (pkg_font_patch.py)
# 定义修改列表
patches = [
('FONTS.PEG', modify_fonts_peg), # 修改字体标记
('verdana11.BDF', inject_chinese), # 注入汉字
('verdanab11.BDF', inject_chinese), # 粗体版本
]
# 执行批量修改
multi_file_patch('_Operating_System_v210.pkg', 'output.pkg', patches)
步骤3: 验证封包结果
# 1. 验证文件完整性
python3 pkg_verify.py verify output.pkg
# 2. 对比原始和修改后的包
python3 pkg_verify.py compare _Operating_System_v210.pkg output.pkg
# 3. 提取修改后的文件验证
python3 pkg_tool.py extract output.pkg "FONTS.PEG" ./FONTS_modified.PEG
验证输出示例:
======================================================================
Verifying: output.pkg
======================================================================
File size: 108,871,656 bytes
MD5 Hash Verification:
Stored: 1d0860cd5eef178da99caccf6efe907d
Calculated: 1d0860cd5eef178da99caccf6efe907d
Status: ✓ MATCH
Chunk Structure Verification:
# Type Size Status
---- ------------------------- ------------ ------------------------------
0 HEADER 1844 ✓ OK
1 UPDATE_KERNEL 1608788 ✓ OK
...
24 FILE (FONTS.PEG) 26048 ✓ OK (ZLIB verified)
...
Summary:
Total chunks: 130
Files: 89 (88 valid, 1 encrypted)
✓ Package is VALID
五、ZLIB压缩/解压代码详解
解压函数(完整注释版)
def decompress_zlib_blocks(f, data_size):
"""
解压PKG中的ZLIB多块数据
参数:
f: 文件句柄,位置在压缩数据开始处
data_size: 期望的解压后总大小
返回:
解压后的完整数据 (bytes)
注意:
- 块大小字段是小端序
- 解压大小字段是大端序(关键!)
"""
result = bytearray()
while len(result) < data_size:
# 读取块类型 (4字节, 小端序)
block_type = struct.unpack('<I', f.read(4))[0]
# 0x00000101 = 结束标记
if block_type == 0x00000101:
f.read(4) # 跳过后面的0
break
# 0x00000100 = 数据块
if block_type != 0x00000100:
break
# 压缩大小 (4字节, 小端序) - 包含4字节头所以要减4
comp_size = struct.unpack('<I', f.read(4))[0] - 4
# 解压大小 (4字节, 大端序!) - 这是关键发现
uncomp_size = struct.unpack('>I', f.read(4))[0]
# 读取压缩数据
comp_data = f.read(comp_size)
# 解压
decompressed = zlib.decompress(comp_data)
result.extend(decompressed)
# 处理4字节对齐填充
rem = comp_size % 4
if rem != 0:
f.seek(4 - rem, 1) # 跳过填充字节
return bytes(result)
压缩函数(完整注释版)
def compress_zlib_blocks(data):
"""
将数据压缩为PKG格式的ZLIB多块
参数:
data: 原始数据 (bytes)
返回:
PKG格式的压缩数据 (bytes)
"""
result = bytearray()
offset = 0
block_size = 0x100000 # 每块最大1MB
while offset < len(data):
# 取一块数据
chunk = data[offset:offset + block_size]
# 压缩(最高压缩级别)
compressed = zlib.compress(chunk, 9)
# 写入块头
result.extend(struct.pack('<I', 0x00000100)) # 块类型 (小端)
result.extend(struct.pack('<I', len(compressed) + 4)) # 压缩大小+4 (小端)
result.extend(struct.pack('>I', len(chunk))) # 解压大小 (大端!)
# 写入压缩数据
result.extend(compressed)
# 4字节对齐填充
rem = len(compressed) % 4
if rem != 0:
result.extend(b'\\x00' * (4 - rem))
offset += block_size
# 写入结束标记
result.extend(struct.pack('<I', 0x00000101))
result.extend(struct.pack('<I', 0x00000000))
return bytes(result)
六、KorgPackage Java工具说明
6.1 GUI工具的问题
KorgPackage v1.2 是一个JavaFX GUI程序,存在以下问题:
- 依赖JavaFX - 需要额外安装JavaFX运行时
- 修改OPOS - 重新保存会触碰加密的OPOS文件
- 无法自动化 - GUI操作不适合批量处理
6.2 我们的解决方案: KorgPkgCLI
从KorgPackage源码编译命令行版本:
编译步骤:
# 1. 获取源码
git clone <https://github.com/Polprzewodnikowy/KorgPackage.git>
cd KorgPackage
# 2. 编译核心库
mkdir -p classes
cd src/main
javac -d /tmp/PA600/classes korgpkg/*.java
# 3. 编译CLI工具
cd /tmp/PA600
javac -cp classes KorgPkgCLI.java -d classes
使用方法:
# 列出文件
java -cp classes KorgPkgCLI list _Operating_System_v210.pkg
# 提取文件
java -cp classes KorgPkgCLI extract _Operating_System_v210.pkg "FONTS.PEG" output.PEG
# 打补丁
java -cp classes KorgPkgCLI patch input.pkg output.pkg "verdana11.BDF" modified.BDF
6.3 Java vs Python工具对比
| 特性 | Java (KorgPkgCLI) | Python (pkg_tool.py) |
|---|---|---|
| 依赖 | JDK 8+ | Python 3.6+ |
| 速度 | 快 | 中等 |
| 灵活性 | 一般 | 高(易修改) |
| OPOS保护 | ✅ 不触碰 | ✅ 不触碰 |
| 推荐场景 | 简单提取 | 批量修改 |
结论: 推荐使用Python工具链进行生产环境操作。
三大需求技术方案
需求一: 固件菜单汉化
目标文件
/omega_sys/EDITRES/ENG/Z103AENG.PEG (971KB)
字符串格式
0a 53 4f 55 4e 44 20 4d 65 6e 75
│ └─────────────────────────────┘
│ "SOUND Menu" (10字节)
└── 长度前缀 (0x0a = 10)
修改约束
铁律: 替换后字节长度必须完全相同!
| 原文 | 替换 | 字节数 | 结果 |
|---|---|---|---|
| SOUND | AUDIO | 5 | ✅ 可行 |
| Cancel | 取消 | 6 (UTF-8) | ✅ 可行 |
| OK | 好 | 2 vs 3 | ❌ 需填充 |
实施代码
def safe_replace(data, old_str, new_str):
old_bytes = old_str.encode('latin-1')
new_bytes = new_str.encode('utf-8')
# 确保长度相同
if len(new_bytes) < len(old_bytes):
new_bytes += b' ' * (len(old_bytes) - len(new_bytes))
elif len(new_bytes) > len(old_bytes):
new_bytes = new_bytes[:len(old_bytes)]
return data.replace(old_bytes, new_bytes)
需求二: U盘文件名中文显示
问题分析
| 测试文件夹 | 显示结果 | 含义 |
|---|---|---|
| AAAA | 4个方块 | MEDIA使用BDF字体 |
| 测试 | 2个问号 | 中文被转成0x3F |
解决方案: 字体劫持法
原理:
正常: 中文 → OPOS转换 → ? (0x3F) → 渲染问号
劫持: 0xC0-0xFF → OPOS保留 → 渲染汉字
字符映射表:
CHAR_MAP = {
'音': 0xC0, '乐': 0xC1, '文': 0xC2, '件': 0xC3,
'夹': 0xC4, '歌': 0xC5, '曲': 0xC6, '测': 0xC7,
'试': 0xC8, '取': 0xC9, '消': 0xCA, '删': 0xCB,
'除': 0xCC, '保': 0xCD, '存': 0xCE, '加': 0xCF,
# ... 最多128个字符 (0x80-0xFF)
}
U盘重命名工具:
def rename_for_pa600(filename):
"""将中文文件名转为PA600可显示格式"""
result = bytearray()
for char in filename:
if char in CHAR_MAP:
result.append(CHAR_MAP[char])
else:
result.extend(char.encode('latin-1', errors='replace'))
return bytes(result)
# 示例: "音乐" → b'\\xC0\\xC1'
需求三: Style名称中文化
Style文件格式
类型: 标准MIDI + KORG SFF2扩展
结构分析:
0x0000: 4D 54 68 64 00 00 00 06 00 00 00 01 07 80 (MThd MIDI头)
0x0010: 4D 54 72 6B 00 00 2E DD (MTrk 轨道)
0x0026: FF 06 04 53 46 46 32 (FF 06 = Marker "SFF2")
0x002E: FF 03 20 ... (FF 03 = Track Name)
└─ 32字节名称字段
名称存储位置
| 位置 | 示例值 | PA600显示 |
|---|---|---|
| 文件名 | XinJiangJieZou 01.sty |
待确认 |
| 内部FF03 | 01.sty (含填充) |
待确认 |
修改方法
def modify_style_name(sty_path, new_name):
"""修改Style文件内部名称"""
with open(sty_path, 'rb') as f:
data = bytearray(f.read())
# 找到SFF2标记
sff2_pos = data.find(b'SFF2')
if sff2_pos == -1:
print("Not a valid SFF2 style file")
return
# FF 03跟在SFF2后面约5字节
name_pos = sff2_pos + 5
# 检查是否是Track Name事件
if data[name_pos:name_pos+2] == b'\\xff\\x03':
length = data[name_pos+2] # 通常是32字节
# 编码新名称,填充到指定长度
encoded = new_name.encode('utf-8')[:length].ljust(length, b'\\x00')
data[name_pos+3:name_pos+3+length] = encoded
with open(sty_path, 'wb') as f:
f.write(data)
Style文件修改流程
STY文件结构详解
┌──────────────────────────────────────────────────────────────┐
│ MIDI Header (MThd) │
│ ├─ Chunk ID: "MThd" (4 bytes) │
│ ├─ Chunk Size: 6 (4 bytes, big-endian) │
│ ├─ Format: 0 (2 bytes) - Single track │
│ ├─ Tracks: 1 (2 bytes) │
│ └─ Division: 1920 (2 bytes) - Ticks per quarter note │
├──────────────────────────────────────────────────────────────┤
│ MIDI Track (MTrk) │
│ ├─ Chunk ID: "MTrk" (4 bytes) │
│ ├─ Chunk Size: N (4 bytes, big-endian) │
│ └─ Track Data: │
│ ├─ FF 06 04 "SFF2" - Marker (KORG SFF2标识) │
│ ├─ FF 03 20 <name> - Track Name (风格名称,32字节) │
│ ├─ FF 51 03 <tempo> - Tempo │
│ ├─ FF 58 04 <time> - Time Signature │
│ └─ ... MIDI事件 ... │
└──────────────────────────────────────────────────────────────┘
STY修改操作步骤
步骤1: 分析现有Style
# 查看文件头
xxd XinJiangJieZou\\ 01.sty | head -10
# 搜索SFF2标记
grep -oba "SFF2" XinJiangJieZou\\ 01.sty
步骤2: 定位名称字段
with open('XinJiangJieZou 01.sty', 'rb') as f:
data = f.read()
sff2_pos = data.find(b'SFF2')
print(f"SFF2 at: 0x{sff2_pos:x}")
# 名称通常在SFF2后约5-10字节
print(f"Context: {data[sff2_pos:sff2_pos+50]}")
步骤3: 修改并保存
# 使用上面的modify_style_name函数
modify_style_name('XinJiangJieZou 01.sty', '新疆节奏')
工具链完整说明
工具位置: 所有工具脚本位于 ./tools/ 目录下
核心工具清单(可复用)
| 脚本 | 路径 | 功能 | 使用场景 |
|---|---|---|---|
pkg_tool.py |
./tools/pkg_tool.py | PKG解析/提取 | 查看和提取文件 |
pkg_modifier.py |
./tools/pkg_modifier.py | 完整PKG修改封包 | 核心修改工具 |
pkg_font_patch.py |
./tools/pkg_font_patch.py | 多文件批量修改 | 字体+配置修改 |
pkg_verify.py |
./tools/pkg_verify.py | 完整性验证 | 刷机前检查 |
pkg_patch.py |
./tools/pkg_patch.py | 精确字符串补丁 | PEG文字替换 |
pkg_multi_patch.py |
./tools/pkg_multi_patch.py | 通用多文件补丁器 | 批量修改 |
font_hijack.py |
./tools/font_hijack.py | 汉字字形注入 | 字体制作 |
create_cn_pack.py |
./tools/create_cn_pack.py | 生成中文汉化包 | 一键汉化 |
Java CLI工具(复用KorgPackage库)
| 文件 | 路径 | 说明 |
|---|---|---|
KorgPkgCLI.java |
./tools/KorgPkgCLI.java | 命令行入口 |
korgpkg/ |
./tools/korgpkg/ | KorgPackage核心库源码 |
korgpkg库包含:
PackageReader.java- PKG读取器PackageWriter.java- PKG写入器FileChunk.java- 文件块处理HeaderChunk.java- 头部块处理Chunk.java- 基类- 其他Chunk类型…
pkg_tool.py 详细用法
# 进入工具目录
cd ./tools/
# 列出所有文件
python3 pkg_tool.py list ../firmware.pkg
# 按关键词过滤
python3 pkg_tool.py list ../firmware.pkg ENG
# 提取单个文件
python3 pkg_tool.py extract ../firmware.pkg "verdana11.BDF" output.BDF
# 分析文件详情
python3 pkg_tool.py analyze ../firmware.pkg "FONTS.PEG"
pkg_modifier.py 详细用法
cd ./tools/
# 测试模式: SOUND → AUDIO
python3 pkg_modifier.py test ../input.pkg ../output.pkg
# 自定义替换
python3 pkg_modifier.py replace ../input.pkg ../output.pkg "Cancel" "取消"
编程接口:
# 导入工具模块
import sys
sys.path.append('./tools')
from pkg_modifier import modify_pkg
def my_modifier(data):
# 自定义修改逻辑
return modified_data
modify_pkg('input.pkg', 'output.pkg', 'target_file', my_modifier)
pkg_font_patch.py 详细用法
import sys
sys.path.append('./tools')
from pkg_font_patch import multi_file_patch
# 定义修改函数
def modify_fonts_peg(data):
# ... 修改逻辑
return modified_data
def inject_chinese(data):
# ... 注入汉字
return modified_data
# 批量修改
patches = [
('FONTS.PEG', modify_fonts_peg),
('verdana11.BDF', inject_chinese),
]
multi_file_patch('input.pkg', 'output.pkg', patches)
pkg_verify.py 详细用法
# 验证单个包
python3 pkg_verify.py verify firmware.pkg
# 对比两个包
python3 pkg_verify.py compare original.pkg modified.pkg
验证项目:
- ✅ PKG MD5校验
- ✅ Chunk结构完整性
- ✅ 文件MD5验证
- ✅ ZLIB解压测试
- ✅ 加密文件识别
测试验证记录
测试固件列表
| 包名 | 修改内容 | 测试目的 | 结果 |
|---|---|---|---|
fontfix.pkg |
FONTS.PEG标记 + C→方块 | 验证外部BDF加载 | ✅ 成功 |
multitest.pkg |
S/T/Y/L/E/A各改不同图案 | 识别活跃字体 | ✅ verdana11确认 |
comprehensive.pkg |
?→方块 + 添加测/试字形 | 验证转换路径 | ✅ 场景1确认 |
fontchain.pkg |
A→方块 | 验证MEDIA字体 | ✅ BDF生效 |
qmark_test.pkg |
?→实心方块 | 验证问号渲染 | ✅ 转换确认 |
关键测试结论
- FONTS.PEG
04b180→ffff80启用外部BDF加载 - verdana11.BDF 是MEDIA界面主要字体
- 中文文件名 被OPOS转换为
?后渲染 - 高位ASCII(0x80-0xFF) 不被转换,可用于劫持
关键警告与注意事项
⚠️ 绝对禁止
- 不要修改OPOS文件
- 路径:
/omega_sys/OPOS - 类型: ENCRYPTED (16)
- 后果: 设备变砖
- 路径:
- 不要使用KorgPackage GUI重新保存
- 会触碰OPOS文件
- 即使不修改也会改变
⚠️ 必须遵守
字符串替换长度相同
assert len(old_bytes) == len(new_bytes)BDF高度限制11像素
BBX 11 11 0 -2 ← 第二个11是高度刷机前验证
python3 pkg_verify.py verify output.pkg
⚠️ 强烈建议
- 保留原始PKG文件备份
- 了解PA600恢复刷机方法
- 先在非关键设备测试
附录
A. PKG Chunk完整类型表
CHUNK_TYPES = {
1: "HEADER",
2: "UPDATE_KERNEL",
3: "UPDATE_RAMDISK",
4: "UPDATE_INSTALLER_APP",
5: "UPDATE_INSTALLER_APP_CONFIG",
6: "SERVICE_KERNEL",
7: "SERVICE_RAMDISK",
8: "SERVICE_APP",
9: "SERVICE_APP_CONFIG",
10: "UPDATE_LAUNCHER_APP",
11: "UPDATE_LAUNCHER_APP_CONFIG",
12: "MLO",
13: "UBOOT",
14: "USER_KERNEL",
15: "INSTALLER_SCRIPT",
16: "DIRECTORY",
17: "FILE",
18: "LINK",
19: "ROOT_FS",
}
B. FONTS.PEG字体条目
内部字体 (04 b1 80):
- verdana9/10/11.BDF
- verdanab9/10/11/12/13/19.BDF
- AnMB-11/20.bdf
外部字体 (ff ff 80):
- CK13Small6.bdf
- Kords-14/15.bdf
- Notation-47.bdf
C. 高频汉字映射表
# 基于UI翻译需求的前60个高频字
CHAR_MAP = {
# 基础操作
'取': 0xC0, '消': 0xC1, '删': 0xC2, '除': 0xC3,
'保': 0xC4, '存': 0xC5, '加': 0xC6, '载': 0xC7,
'退': 0xC8, '出': 0xC9, '返': 0xCA, '回': 0xCB,
'下': 0xCC, '一': 0xCD, '打': 0xCE, '开': 0xCF,
# 编辑操作
'关': 0xD0, '闭': 0xD1, '编': 0xD2, '辑': 0xD3,
'复': 0xD4, '制': 0xD5, '播': 0xD6, '放': 0xD7,
'停': 0xD8, '止': 0xD9, '录': 0xDA, '音': 0xDB,
# 确认操作
'是': 0xDC, '否': 0xDD, '确': 0xDE, '定': 0xDF,
# 功能分类
'风': 0xE0, '格': 0xE1, '色': 0xE2, '歌': 0xE3,
'曲': 0xE4, '全': 0xE5, '局': 0xE6, '设': 0xE7,
'置': 0xE8, '菜': 0xE9, '单': 0xEA, '基': 0xEB,
'础': 0xEC, '量': 0xED, '轨': 0xEE, '道': 0xEF,
# 效果相关
'效': 0xF0, '果': 0xF1, '选': 0xF2, '择': 0xF3,
'错': 0xF4, '误': 0xF5, '警': 0xF6, '告': 0xF7,
}
D. 参考资源
官方资源:
- KORG PA600固件: https://www.korg.com/us/support/download/
- KorgPackage源码: https://github.com/Polprzewodnikowy/KorgPackage
字体资源:
- GNU Unifont: https://unifoundry.com/unifont/
- Zpix像素字体: https://github.com/SolidZORO/zpix-pixel-font
技术标准:
- BDF格式: X11 Bitmap Distribution Format
- MIDI格式: Standard MIDI File 1.0
文档版本: 3.0
创建日期: 2025-12-18
最后更新: 2025-12-18 01:29
状态: 技术验证完成,待实施
欢迎指出任何有错误或不够清晰的表达,可以在下面评论区评论。