业余无线电爱好者常常希望对设备进行自定义修改,以扩展功能或优化性能。然而,Yaesu FT-70D 这样的设备,其固件更新过程使用了加密机制,依赖专有的 Windows 更新工具,这限制了独立开发者的操作。本文聚焦于使用静态和动态分析方法,从固件中提取加密密钥,从而实现无需官方工具的自定义修改。这种方法不仅适用于 FT-70D,还可扩展到类似嵌入式设备的逆向工程。
观点上,固件加密的主要目的是防止篡改和确保更新完整性,但通过逆向工程,我们可以安全地提取密钥,实现合法的自定义功能,如添加新频段支持或优化功耗管理。证据显示,Yaesu 的更新工具(FT-70D_ver111(USA).exe)将固件嵌入资源部分,并使用自定义加密算法保护。静态分析揭示了资源加载和解密函数的结构,而动态分析确认了密钥生成过程依赖于 Unix 时间戳,这使得每次更新都有独特密钥,但也暴露了可逆向的弱点。
在静态分析阶段,首先使用工具如 XPEViewer 检查可执行文件的 .rsrc 部分。资源类型 23 下隐藏了加密固件,名为 RES_UPDATE_INFO 的二进制数据无法直接读取字符串,表明其加密。加载到 IDA Pro 或 Ghidra 中,搜索 FindResourceA 调用,定位到加载资源的函数。该函数将资源复制到动态缓冲区,并调用解密例程 sub_408350。伪代码显示,该函数处理输入数据长度为 0x100000(约 1MB),输出缓冲区同样大小。通过交叉引用,识别出解密核心涉及位级操作:将 8 字节输入膨胀为 64 字节位数组,然后调用 sub_407980 进行变换,最后 deflate 回字节。
动态分析进一步验证了这些发现。使用 WinDbg 的 Time Travel Debugging (TTD) 记录更新过程:在资源复制后(地址如 0x406968 的 rep movsd 指令),设置内存读断点(ba r4 <缓冲区地址>),捕获解密调用(地址 0x4047DC)。前后比较内存窗口,确认解密前后数据变化:加密数据为随机字节,解密后出现可读字符串,如设备特定标识。TTD 的回溯功能(Go Back)帮助追踪密钥来源,揭示时间戳(前 4 字节)格式化为 YYYYMMDDHHMMSS 字符串,用于生成动态密钥。
解密算法细节如下:首先,提取时间戳并膨胀每个字节为 8 位数组(bit_idx 从 7 到 0 右移)。该位数组与 4 个静态密钥(static_key_1 到 4)逐次 XOR,输出作为最终密钥缓冲区(64 字节)。set_key 函数对密钥进行混淆:复制到 56 字节临时数组,进行 16 轮置换(每轮 1 或 2 次 28 字节循环移位,基于全局配置如 unk_424DE0),然后使用交换表(byte_424E20 等)填充持久密钥数组(48*16=768 字节)。主解密循环处理输入 8 字节块:膨胀为 64 位,调用 decrypt_data(sub_407980),其中构建 48 字节 XOR 缓冲(密钥块 XOR 输入位 + 静态表 byte_424E50),然后索引 0x800 字节 S-盒(dword_424E80 等)生成 32 字节变换表,最后对输出字节 XOR 该表(索引由 unk_425680 等 32 字节缓冲提供)。
为落地实现,提供以下参数和清单:
-
环境准备:
- 工具:IDA Pro/Ghidra(静态),WinDbg with TTD(动态),Rust/C++(实现)。
- 固件获取:从 Yaesu 官网下载更新 ZIP,提取 exe 资源。
- 缓冲区大小:输入/输出 1MB(0x100000),密钥 64 字节,scratch 64 字节。
-
解密实现清单(伪代码参数):
- inflate_byte_to_bits(input_byte: u8) -> [u8; 8]:for bit in (7..0).rev() { bits[7-bit] = (input_byte >> bit) & 1; }
- generate_key_from_timestamp(ts_str: &str, static_keys: [&[u8]; 4]) -> [u8; 64]:初始化零缓冲,逐字节膨胀并 XOR 静态密钥 4 次。
- set_key(key: &[u8; 64], persistent_key: &mut [u8; 768]):16 轮循环,swap_rounds=1 或 2,循环移位 28 字节两次部分,然后 48 次交换(GLOBAL_KEY_SWAP_TABLE[swap_idx] -1 索引)。
- decrypt_block(inflated: &[u8; 64], key: &[u8; 768], sbox: &[u8; 2048]) -> [u8; 64]:构建 48 字节 xor_buf(6 组 8 字节,每组从 key[48round + offset] XOR inflated[table[i]+31]),然后 8 次 S-盒索引(bit 组合如 (v38[0]+2) | (32v34+2) 等),生成 32 字节 table,最后 8 字节输出 XOR table[buf_idx]。
- 主循环:读取加密数据(跳过前 4 字节 ts),while len >0 { process 8 字节,累积输出 }。
-
自定义修改参数:
- 加载 IDA:选择 Hitachi H8SX advanced,设备 H8S/2215R。向量表从 0x0000,定义代码从 0x142A(双字值)。
- 修改示例:定位功耗函数(搜索字符串如 "POWER"),调整阈值寄存器(如 mov.b #0x05, r0 为低功耗模式)。重新加密:逆过程生成新 ts,加密修改固件,使用 Renesas SDK 闪存。
- 监控点:解密后校验字符串完整性,回滚若 CRC 不匹配。阈值:密钥轮次 16,块大小 8 字节,S-盒偏移 0x100。
这种方法的风险包括潜在的砖化设备(备份原固件)和法律合规(仅个人使用)。通过这些步骤,开发者可独立修改 FT-70D,实现如自定义语音提示或扩展内存分配,而无需 Yaesu 工具。
资料来源:基于 https://landaire.net/reversing-yaesu-firmware-encryption/ 的逆向分析,以及 GitHub porkchop 实现。引用:“使用 WinDbg TTD 记录执行跟踪,捕获解密数据变化。” 进一步参考 Renesas H8SX 文档。