真的泪目了,现在还有人在对古老的S-YXG50和S-YXG2006LE音源进行逆向…
必须狠狠支持了
个人觉得S-YXG2006LE那么好的高音质采样,却全败在无法启用的S-YXG50 GUI,败在被砍成XGlite和32个Polyphony上,实在太可惜了。
有朝一日希望看到2006LE也能被破解支持128复音和Full XG!
看了Veg.by大佬制作的S-YXG50 VSTi中的Readme,可以把S-YXG50的sxgwave4.tbl文件删掉替换为自己准备的波表文件,考虑到S-YXG50有GUI并且可以调复音数,就想试试能不能另辟蹊径把S-YXG2006LE的TBL波表移植给S-YXG50来破除复音限制,毫无疑问因为波表加密的缘故没法行得通,遂见此贴!
跪拜大佬们!
Yamaha S-YXG 50 逆向记录
话说这个是做什么用的音源呢?拿回去听了一下貌似就只有正弦波的采样,并且GM1 Reset后支持映射为正弦波的乐器反而比XG更多就很奇怪呢(
用来叠加多个正弦波来合成人声或许不错
那狠狠支持用爱发电的大佬了!
很希望有一天S-YXG2006LE采样这么好的音源也能用上Full XG和128个复音…
那个不全,缺少采样文件
别的不说,S-YXG50/70/100的原始2MB波表,String Ensemble 1音色听起来要比4MB波表好多了,很高昂的感觉。至少在我的音乐审美来看是这样的,哈哈 
Codex对三个文件做了第一轮静态分析,没有运行 DLL。
结果挺有料:
-
SGP2.DLL是 32 位 x86 VSTi DLL,导出函数只有main。 - DLL 内部明确包含:
sxgbnw6l.tblsxgdat6l.tblYAMAHA SoftSynthesizer S-YXG2006LE
- 它通过
GetModuleFileNameA找自身路径,再用CreateFileA / GetFileSize / ReadFile把两个.tbl整个读入内存。 -
sxgbnw6l.tbl不是波形本体,更像 索引/参数/映射表。开头是:UTG VPRM 06 07 28 15 28- 后面有一组 offset table。
-
sxgdat6l.tbl才更像大数据/波形数据,但它不是裸 WAV/PCM,原始内容高熵,DLL 里有解码逻辑。
Codex找到的关键代码位置:
SGP2.DLL+0x2DD0 负责加载两个 tbl
SGP2.DLL+0x2D60 复制字符串 sxgbnw6l.tbl
SGP2.DLL+0x2D80 复制字符串 sxgdat6l.tbl
SGP2.DLL+0x4C830 通用“读取整个文件”函数
SGP2.DLL+0x2EF0 sxgdat6l.tbl 解码例程
SGP2.DLL+0x4C900 解码 helper
SGP2.DLL+0x2EF0 里面能看到一个明显的处理:先调用 +0x4C900 做第一阶段变换,然后对数据做类似“每两个字节交换 + XOR 0x5A”的第二阶段处理。解码后仍然不是 RIFF/WAVE,所以后面很可能还有专有采样压缩、ADPCM 或 Yamaha 自己的波形编码格式。
另外,外部资料也能对应上:SGP2.DLL 确实被社区记录为 Yamaha MidRadio 7 里的 S-YXG2006LE VSTi,使用 sxgbnw6l.tbl / sxgdat6l.tbl 这组新 wavetable。参考:VEG.BY、XG-Central。
下一步最有价值的是用 Ghidra 或 x32dbg 深入 SGP2.DLL+0x2EF0、+0x4C900 和读取后的数据结构,把 sxgbnw6l.tbl 里的 20 字节表项、6048 个指针表项和 sxgdat6l.tbl 的偏移关系对应起来。这样才能进一步判断它到底是 PCM、ADPCM、循环采样,还是更复杂的 Yamaha AWM2 风格数据。
感谢 @gaozhe3321 带来新的逆向进展。
这种文件有反编译过的样本么,或者说具体结构可以形容下
闲话本人就折叠起来了,想看就展开吧
提到这个其实联想到的是Motif的乐器预设或波表(如wXa,wXv;只是举个例子实际上有更多变种)
https://archive.org/details/motif-es-sound-library
以上这张CD是购买Motif附赠的音色库,如果跑题的话可能就没什么研究价值了
雅马哈的其他私有格式Fmj_Awave说是整理吧(但它软件能读数据,所以基本是转了)
就看看得了
但也并非一无是处,至少得知了雅马哈习惯性的把乐器预设(voice)和样本(waveformat)分开放这个事实(但似乎也早说过了?)
https://www.fmjsoft.com/awavestudio.html#formats
(看一眼这几个格式的介绍也无妨?)
2605082330
你太牛了!
事实上 2006LE 也采取了跟 YXG-50 相似的索引+波表的方式
我事实上还发现,其实很多音色是共用了同一个采样,但是在调制方式上有区别。也就是说我们目前只是知道了这些数据是如何排布的,但是更复杂的调制算法以及效果器/SysEx这些功能是如何实现的,还有待进一步分析。
整个程序的结构也需要进一步去分析,但这可能需要动态调试了,我能力和时间都有限,只能暂时搁置了
大佬你也用 OpenCode? 
也许可以试试本地部署大模型(如果可能的话,虽然不太可能)
也许可以试试本地部署大模型(如果可能的话,虽然不太可能)
我没有很好的显卡……也没有¥
S-YXG2006LE 数据文件结构报告
该文档由AI生成,可能存在不准确的部分
1. 概述
S-YXG2006LE 合成器使用两个数据文件:
| 文件 | 大小 | 加密 | 用途 |
|---|---|---|---|
sxgbnw6l.tbl |
716,608 字节 | 否 (明文) | 参数表:音色定义、波形偏移、力度曲线 |
sxgdat6l.tbl |
11,723,868 字节 | 是 (Stage 1) | 波形数据:16-bit PCM 采样 |
2. sxgbnw6l.tbl 参数表结构
2.1 文件头部 (0x00-0x3F, 64字节)
偏移 大小 值 说明
0x00 28B "UTG VPRM 06 07 28 15 28\0" 魔数 + 版本号
0x1C uint32 0x00004040 Section A 偏移 (Voice 索引表)
0x20 uint32 0x00009740 Section B 偏移 (波形偏移表)
0x24 uint32 0x00032EE8 Section C 偏移 (音色参数数据)
0x28 uint32 0x0007B88C Section D 偏移 (力度/音量曲线)
0x2C uint32 0x0007BA8C Section E 偏移 (鼓组/音符参数)
0x30 uint32 0x0009CE8C Section F 偏移 (每音符 Voice 映射)
0x34 uint32 0xFFFFFFFF 保留
0x38 uint32 0x000A69F0 Section G 偏移 (鼓键参数)
0x3C uint32 0xFFFFFFFF 保留
2.2 段布局总览
| 段 | 偏移 | 大小 | 用途 |
|---|---|---|---|
| Header | 0x000000-0x00003F |
64 B | 文件头 |
| Lookup Table | 0x000040-0x00013F |
256 B | MIDI Program → Voice 索引映射 |
| Sparse Region | 0x000140-0x00403F |
16 KB | 填充 (0xFF) |
| Section A | 0x004040-0x00973F |
22 KB | Voice 索引表 |
| Section B | 0x009740-0x032EE7 |
170 KB | 波形偏移表 (42,474 个 uint32) |
| Section C | 0x032EE8-0x07B88B |
297 KB | 音色参数数据 (6,048 条记录) |
| Section D | 0x07B88C-0x07BA8B |
512 B | 力度曲线 (4×128 字节) |
| Section E | 0x07BA8C-0x09CE8B |
136 KB | 鼓组/音符参数 |
| Section F | 0x09CE8C-0x0A69EF |
40 KB | 每音符 Voice 映射 |
| Section G | 0x0A69F0-0x0AEF3F |
34 KB | 鼓键参数 (1,422×24 字节) |
3. 各段详细结构
3.1 Lookup Table (0x40-0x13F)
128 字节,每个字节对应一个 MIDI Program (0-127),值为内部 Voice 索引。
-
0xFF= 未映射 -
0x00-0x3D= 有效 Voice 索引
已映射的 MIDI Programs (59个):
0, 1, 3, 6, 8, 12, 14, 16-20, 24-25, 27-28, 32-38, 40-43, 45,
64-72, 96-101, 112-127
映射示例:
| MIDI Program | Voice Index | 说明 |
|---|---|---|
| 0 | 0 | Acoustic Grand Piano |
| 1 | 1 | Bright Acoustic Piano |
| 24 | 12 | Acoustic Guitar (nylon) |
| 40 | 23 | Violin |
3.2 Section B: 波形偏移表 (0x9740)
42,474 个 uint32 值,指向 sxgdat6l.tbl 中的波形数据。
结构:
偏移 = Section B 起始 + 索引 * 4
波形大小 = 偏移[索引+1] - 偏移[索引]
统计:
- 有效偏移 (< 文件大小): 21,057 个
- 无效偏移 (0xFFFFFFFF): 9,512 个
- 波形大小范围: 44-440 字节 (22-220 采样)
波形示例:
| 索引 | 偏移 | 大小 | 采样数 |
|---|---|---|---|
| 0 | 0x00A308 | 264 | 132 |
| 1 | 0x00A410 | 152 | 76 |
| 2 | 0x00A4A8 | 408 | 204 |
3.3 Section C: 音色参数 (0x32EE8)
Section C 开头是偏移表,每个条目指向一个音色定义记录。
音色定义记录大小:
| 大小 | 元素数 | 说明 |
|---|---|---|
| 28 字节 | 1 | 单元素音色 |
| 60 字节 | 2 | 双元素音色 |
| 108 字节 | 4 | 四元素音色 |
| 140 字节 | 5 | 五元素音色 |
| 176 字节 | 6 | 六元素音色 |
VoiceElement 结构 (28字节):
偏移 大小 说明
0x00 4B 标志 (通常为 0)
0x04 1B 音高范围低 (通常 0)
0x05 1B 音高范围高 (通常 127)
0x06 1B 波形索引 (指向 Section B)
0x07 1B 元素标志
0x08 1B 力度范围低 (通常 0)
0x09 1B 力度范围高 (通常 127)
0x0A 1B 粗调 (有符号)
0x0B 1B 微调 (有符号)
0x0C 1B 电平 (128 = 最大)
0x0D 3B 保留
0x10 1B 声像 (128 = 中央)
0x11 3B 保留
0x14 1B 滤波器截止频率 (128 = 最大)
0x15 3B 保留
0x18 1B 滤波器共振 (128 = 最大)
0x19 3B 保留
音色参数示例 (Program 0, Piano):
- Voice Index: 0
- 记录大小: 176 字节 (6 元素)
- 元素波形索引: [132, 127, 1, 0, 255, 37]
3.4 Section D: 力度曲线 (0x7B88C)
4 条曲线,每条 128 字节,将 MIDI 力度 (0-127) 映射到输出值 (0-127)。
| 曲线 | vel=0 | vel=32 | vel=64 | vel=96 | vel=127 | 特点 |
|---|---|---|---|---|---|---|
| 0 | 0 | 32 | 72 | 114 | 126 | 标准 |
| 1 | 0 | 26 | 60 | 98 | 126 | 柔和 |
| 2 | 0 | 26 | 64 | 104 | 126 | 中等 |
| 3 | 0 | 32 | 73 | 115 | 127 | 线性 |
3.5 Section G: 鼓键参数 (0xA69F0)
1,422 个记录,每个 24 字节。
默认记录:
40 40 7F 00 40 00 00 7F 00 01 01 40 40 40 40 40 40 40 0C 36 00 40 40 40
字段解释:
| 偏移 | 大小 | 默认值 | 说明 |
|---|---|---|---|
| 0x00 | 1B | 0x40 (64) | 电平 |
| 0x01 | 1B | 0x40 (64) | 声像 |
| 0x02 | 1B | 0x7F (127) | 编组 |
| 0x03 | 1B | 0x00 | 标志 |
| 0x04 | 1B | 0x40 (64) | 音调 |
| 0x07 | 1B | 0x7F (127) | 衰减 |
| 0x08 | 1B | 0x00 | 混响发送 |
| 0x09 | 1B | 0x01 | 合唱发送 |
| 0x0B | 1B | 0x40 (64) | 滤波器截止 |
4. sxgdat6l.tbl 波形数据
4.1 加密方式
波形数据使用 Stage 1 (nibble-swap XOR) 加密。
解密算法 (地址 0x1004c900):
void decrypt(uint8_t* data, uint32_t size) {
uint8_t key = 0x5B; // 初始密钥
uint8_t counter = 0; // 位置计数器
for (uint32_t i = 0; i < size; i++) {
// 1. XOR with key and counter
uint8_t val = data[i] ^ key ^ counter;
// 2. Nibble swap (高4位 ↔ 低4位)
val = ((val >> 4) & 0x0F) | ((val << 4) & 0xF0);
data[i] = val;
// 3. 更新密钥和计数器
counter++;
key = ~key; // 0x5B ↔ 0xA4
}
}
密钥演化:
- 字节 0: key=0x5B, counter=0
- 字节 1: key=0xA4, counter=1
- 字节 2: key=0x5B, counter=2
- 字节 3: key=0xA4, counter=3
- …
4.2 DLL 中的解密流程
LoadDataFiles (0x10002dd0)
│
├── OpenAndReadFile("sxgbnw6l.tbl") → 不解密 (明文)
│
├── OpenAndReadFile("sxgdat6l.tbl")
│
└── DecryptData(sxgdat6l_data, size) (0x10002ef0)
│
└── DecryptNibbleSwap(data, size, &key) (0x1004c900)
注意: sxgbnw6l.tbl 是明文,不需要解密。
4.3 解密后的数据格式
解密后的数据是 16-bit 小端 PCM 音频。
验证结果 (前 10 个波形):
| 索引 | 偏移 | 大小 | 前 5 个采样 |
|---|---|---|---|
| 0 | 0x00A308 | 264 | [5905, 17423, 8720, 3605, 287] |
| 1 | 0x00A410 | 152 | [7863, 16049, -4179, -10323, 30896] |
| 2 | 0x00A4A8 | 408 | [-18141, -2260, -1233, -29651, -28629] |
| 3 | 0x00A640 | 296 | [-2279, -31209, 24345, -13536, 26156] |
| 4 | 0x00A768 | 184 | [-22035, -23566, -22280, 20991, 13063] |
采样特征:
- 范围: ±32000 (16-bit)
- 采样率: 44100 Hz (推测)
- 格式: 单声道
5. 数据对应关系
5.1 音色加载流程
MIDI Program (0-127)
│
▼
Lookup Table (0x40-0x13F)
│
▼
Voice Index (0-6047)
│
▼
Section C 偏移表
│
▼
音色定义记录 (28-176 字节)
│
├── 元素 0: VoiceElement (28 字节)
│ └── 波形索引 (byte 6)
│ │
│ ▼
│ Section B 偏移表
│ │
│ ▼
│ sxgdat6l.tbl 波形数据
│
├── 元素 1: VoiceElement (28 字节)
│ └── ...
└── ...
5.2 MIDI 事件处理流程
Note On (channel, note, velocity)
│
├── 通道 9? → 鼓组模式 (Section G)
│
└── 其他通道 → 查找音色参数
│
├── 应用力度曲线 (Section D)
│
├── 查找 VoiceElement
│ ├── 检查音高范围
│ └── 检查力度范围
│
├── 获取波形数据 (Section B → sxgdat6l.tbl)
│
└── 设置合成器参数
├── 频率 (note → Hz)
├── 振幅 (velocity → 0.0-1.0)
├── 滤波器 (cutoff, resonance)
└── 包络 (ADSR)
5.3 全局变量地址
| 地址 | 名称 | 说明 |
|---|---|---|
0x1009e6cc |
g_refCount |
数据加载引用计数 |
0x1009e6d0 |
g_bnwData |
sxgbnw6l.tbl 数据指针 |
0x1009e6d4 |
g_datData |
sxgdat6l.tbl 数据指针 |
0x1009b2ec |
str_sxgbnw6l |
字符串 “sxgbnw6l.tbl” |
0x1009b2fc |
str_sxgdat6l |
字符串 “sxgdat6l.tbl” |
6. 关键函数地址
| 地址 | 函数 | 说明 |
|---|---|---|
0x10002dd0 |
LoadDataFiles |
加载两个 .tbl 文件 |
0x10002ef0 |
DecryptData |
两阶段解密 (实际只需 Stage 1) |
0x1004c900 |
DecryptNibbleSwap |
Stage 1: nibble-swap XOR |
0x10002d60 |
CopySxgbnw6lPath |
复制 “sxgbnw6l.tbl” 字符串 |
0x10002d80 |
CopySxgdat6lPath |
复制 “sxgdat6l.tbl” 字符串 |
0x10002db0 |
ValidateData |
验证文件路径 |
0x1004c830 |
OpenAndReadFile |
打开并读取文件 |
0x100030a0 |
SynthInit |
合成器初始化 |
0x10003ec0 |
VoiceDispatcher |
音色参数分发器 |
0x10005b38 |
RenderVoice |
读取波形索引 [esi+6]
|
7. 未解密问题
7.1 Stage 2 解密
DLL 中的 DecryptData 函数包含两个阶段:
- Stage 1: Nibble-swap XOR (已验证有效)
- Stage 2: Byte-pair swap + XOR 0x5A
经验证,sxgdat6l.tbl 只需 Stage 1 即可得到有效 PCM 数据。Stage 2 可能用于其他文件或已被废弃。
7.2 sxgbnw6l.tbl 加密
DLL 代码显示 DecryptData 被调用两次 (对两个文件都解密),但 sxgbnw6l.tbl 是明文。可能的原因:
- sxgbnw6l.tbl 的数据部分 (偏移 0x40 之后) 需要解密
- 解密函数对明文数据是幂等的
- 代码被修改或版本不一致
8. 附录
8.1 完整 Lookup Table 映射
Program 0 → Voice 0 (Piano)
Program 1 → Voice 1 (E.Piano)
Program 3 → Voice 2 (E.Piano 2)
Program 6 → Voice 3 (Harpsichord)
Program 8 → Voice 4 (Clavinet)
Program 12 → Voice 5 (Celesta)
Program 14 → Voice 6 (Vibraphone)
Program 16 → Voice 7 (Organ)
Program 17 → Voice 8 (Organ)
Program 18 → Voice 9 (Organ)
Program 19 → Voice 10 (Church Organ)
Program 20 → Voice 11 (Reed Organ)
Program 24 → Voice 12 (Guitar)
Program 25 → Voice 13 (Guitar)
Program 27 → Voice 14 (Guitar)
Program 28 → Voice 15 (Guitar)
Program 32 → Voice 16 (Bass)
Program 33 → Voice 17 (Bass)
Program 34 → Voice 18 (Bass)
Program 35 → Voice 19 (Bass)
Program 36 → Voice 20 (Bass)
Program 37 → Voice 21 (Bass)
Program 38 → Voice 22 (Bass)
Program 40 → Voice 23 (Strings)
Program 41 → Voice 24 (Strings)
Program 42 → Voice 25 (Strings)
Program 43 → Voice 26 (Strings)
Program 45 → Voice 27 (Strings)
Program 64 → Voice 28 (Brass)
Program 65 → Voice 29 (Brass)
Program 66 → Voice 30 (Brass)
Program 67 → Voice 31 (Brass)
Program 68 → Voice 32 (Brass)
Program 69 → Voice 33 (Brass)
Program 70 → Voice 34 (Brass)
Program 71 → Voice 35 (Brass)
Program 72 → Voice 36 (Brass)
Program 96 → Voice 37 (Synth)
Program 97 → Voice 38 (Synth)
Program 98 → Voice 39 (Synth)
Program 99 → Voice 40 (Synth)
Program 100 → Voice 41 (Synth)
Program 101 → Voice 42 (Synth)
Program 112 → Voice 43 (Percussion)
Program 113 → Voice 44 (Percussion)
Program 114 → Voice 45 (Percussion)
Program 115 → Voice 46 (Percussion)
Program 116 → Voice 47 (Percussion)
Program 117 → Voice 48 (Percussion)
Program 118 → Voice 49 (Percussion)
Program 119 → Voice 50 (Percussion)
Program 120 → Voice 51 (Percussion)
Program 121 → Voice 52 (Percussion)
Program 122 → Voice 53 (Percussion)
Program 123 → Voice 54 (Percussion)
Program 124 → Voice 55 (Percussion)
Program 125 → Voice 56 (Percussion)
Program 126 → Voice 57 (Percussion)
Program 127 → Voice 58 (Percussion)
我这边跑出来的结果,好像是不需要做第二阶段的 字节交换+XOR 0x5A
Update:如果不做第二阶段,能听出乐器的声音,但杂音很重,所以还是要考虑第二阶段
我觉得大概率还是 PCM,你可以把解密后的数据文件用 音频编辑器打开看一下,如果你用 Linux,也可以用 aplay 命令播一下听听
用AI做了几天逆向,我的感觉是,这玩意没有预想中那么智能
AI很会偷懒,有的时候跟智障一样,总之需要大量调教才可以









