VxWorks 固件
VxWorks 是美国 Wind River 公司开发的实时操作系统(RTOS),广泛应用于工控、航空航天、网络设备、医疗仪器等嵌入式场景
其固件镜像通常是一个单体内核映像,包含内核、驱动、应用程序和文件系统
固件镜像格式
典型镜像类型
Bootrom:引导加载程序,负责初始化硬件、加载主映像
VxWorks 主映像:包含内核、任务、符号表(可选),通常被压缩或直接以 ELF/二进制形式存在
文件系统(TFFS/DOSFS/HRFS):挂载于 /tffs0 等,存放配置、Web 页面、应用程序模块
镜像结构特征
压缩壳:常见压缩算法为 deflate(zlib)或 LZMA,可通过 binwalk -e 自动识别并解压
符号表(Symbol Table):VxWorks 为方便动态加载模块和调试,默认在映像中保留完整的符号表,位于 symTbl 段,包含函数名、地址、类型。这是逆向分析的最大助力
段布局
1 | +-------------------+ |
实战案例
某嵌入式设备固件升级包(VxWorks 固件)

题目给出的是一个名为 UpgradePackage.bin 的固件升级包
首先需要理解固件升级包的常见结构:大多数升级包包含一个明文头部(记录设备型号、版本等信息),后面跟着压缩或加密的固件本体
用十六进制编辑器或 binwalk 查看文件,能发现开头有可读字符串:140-NOE-771-01 和 Quantum Ethernet Executive firmware Ver. 6.40
这告诉我们设备型号和固件版本,同时也提示固件可能是 VxWorks 操作系统
VxWorks 是一种嵌入式实时操作系统,广泛应用于工业控制、网络设备中,其固件镜像通常包含符号表用于调试
继续分析升级包,需要找到真正的固件数据在哪里
偏移 0x385 处存在 zlib 压缩数据,用 Python 直接从 0x385 开始 zlib 解压
1 | import zlib |
在解压后的固件里可以看到 VxWorks 痕迹
1 | # -a:全文件扫描(--all) |

1 | # 该固件使用 VxWorks 实时操作系统(RTOS),版本信息格式为 L8 |
题目说要找 bsolute__C14SequenceNumber 函数所对应的文件偏移
1 | # -t x 输出字符串所在的十六进制文件偏移 |
得到偏移是 0x26634c,并且是 Absolute__C14SequenceNumber,题目可能给错了

固件里的符号表一般不会保存 “文件偏移”,而是保存运行时地址
1 | 运行时地址 = 文件偏移 + 加载基址 |
获取加载基址的思路如下
1 | 固件中有很多字符串文件偏移 |
所以我们枚举 base,看哪个 base 能解释最多的 “指向字符串的指针”
1 | from pathlib import Path |
可以看到 0x10000 命中数遥遥领先,所以基址就是 0x10000

所以目标字符串运行地址 = 0x26634C + 0x10000 = 0x27634C
因为 PowerPC 是大端,所以 0x0027634C 在文件里的字节形式是 00 27 63 4C
接下来就是找到哪个符号表项引用了 Absolute__C14SequenceNumber 这个字符串
1 | from pathlib import Path |

将 symbol item bytes 按 4 字节大端拆开
1 | 00 00 00 00 00 27 63 4C 00 11 FD 38 00 00 05 00 |
对应结构体
1 | struct symbol_item { |
解析结果
1 | unk = 0x00000000 |
value_addr 就是 Absolute__C14SequenceNumber 的函数运行时地址
题目要的是 函数所对应的文件偏移,所以要减去基址
得到 flag 后半部分 0x0011FD38 - 0x00010000 = 0x0010FD38
symbol item start 是符号表项,值为 0x302010,那么整张符号表应该是一段连续的 16 字节结构数组
所以我们要做的是
1 | 从 0x302010 开始 |
判断 “像符号表项” 的标准是:
- 第 1 字段通常为
0 - 第 2 字段
name_addr - 0x10000后能指向一个合法字符串 - 第 3 字段
value_addr落在固件地址范围内 - 第 4 字段
type是少量重复的类型值,例如0x500、0x700、0x900等
1 | from pathlib import Path |
输出
1 | symbol table start: 0x301e60 |
symbol table end 说明 0x3293B0 起就不再是符号表项
手动观察表尾
1 | # -g 4:改为 4 个字节一组 |
回显
1 | 00329380: 00000000 00232b08 00367788 00000900 |
前三行仍然符合符号表项结构
1 | 00000000 [name_addr] [value_addr] [type] |
但到了 0x3293B0,第一字段变成了 00002755。它不再是符号表项,而是表项数量
所以表尾就是 0x3293B0,第一部分 flag 已经确认为 00002755
最终 flag 为 flag{000027550010FD38}