Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Produktivität · SKILL.md

re-rtos

re-rtos

RTOS 结构分析:FreeRTOS/ThreadX/Zephyr/RT-Thread/VxWorks/QNX/RTEMS/NuttX/eCos/µC-OS/SYS-BIOS/SAFERTOS/CMSIS-RTX5/T-Kernel/TOPPERS/OSE/INTEGRITY/ARINC 653/PikeOS/Deos 运行模型判定、任务表与 TCB 定位、内核对象还原、按任务拆分反编译。触发词:RTOS、FreeRTOS、ThreadX、Zephyr、VxWorks、QNX、RTEMS、NuttX、eCos、µC/OS、Micrium、SYS/BIOS、SAFERTOS、CMSIS-RTX5、T-Kernel、TOPPERS、ITRON、OSE、OSEck、Nucleus、INTEGRITY、ARINC 6…

Independent GitHub snapshot · Automated classification · Original documentation governs

Ddslsdzc / rev-skillsApache-2.0

Skill-Dokumentation

GitHub

name: re-rtos description: RTOS 结构分析:FreeRTOS/ThreadX/Zephyr/RT-Thread/VxWorks/QNX/RTEMS/NuttX/eCos/µC-OS/SYS-BIOS/SAFERTOS/CMSIS-RTX5/T-Kernel/TOPPERS/OSE/INTEGRITY/ARINC 653/PikeOS/Deos 运行模型判定、任务表与 TCB 定位、内核对象还原、按任务拆分反编译。触发词:RTOS、FreeRTOS、ThreadX、Zephyr、VxWorks、QNX、RTEMS、NuttX、eCos、µC/OS、Micrium、SYS/BIOS、SAFERTOS、CMSIS-RTX5、T-Kernel、TOPPERS、ITRON、OSE、OSEck、Nucleus、INTEGRITY、ARINC 653、PikeOS、VxWorks 653、Deos、任务表、TCB、固件调度、MCU 固件、confdefs、devicetree、DKM、resource manager、FromISR、DSR、OSIntEnter、Swi、Hwi、module preamble、upper half、分区调度、major frame、Safety Class capabilities: [rtos-analysis]

RTOS 结构分析(FreeRTOS / ThreadX / Zephyr / RT-Thread / VxWorks / QNX / RTEMS / INTEGRITY)

各内核形态不同(链表任务表 / 编译期设备图 / 全局符号环境 / 用户态 server / 构建期配置),但共性是:注册模型决定你能看到什么——一个函数"没有直接交叉引用",在不同 RTOS 上可能分别意味着"正常(linker 注册)"、"正常(装载时符号解析)"、"正常(用户态 server)"或"真的没被引用"。

所以顺序永远是:先判这个 RTOS 的运行与注册模型,再谈任务与内核对象。 </CORE RULE>

运行模型差异(不是同义替换)

平台"驱动/服务"在哪注册与发现机制先判什么
FreeRTOS / ThreadX / RT-Thread与内核同镜像;任务 + 内核对象表显式创建 API + 静态对象实例任务表/TCB(本主文档)
Zephyr与内核同镜像,但设备图在编译期生成devicetree + Kconfig + iterable sections、SYS_INIT是否 linker 注册([[zephyr]])
VxWorks两种:DKM 内核态 / RTP 用户态DKM 动态加载 + 全局符号环境;RTP 走标准 ELF/.so先分 DKM 还是 RTP([[vxworks]])
QNX用户态 server;网络驱动是 io-pkt 内的共享对象pathname 注册 + 消息传递先判形态([[qnx]])
RTEMS与内核/应用同处单一地址空间构建期配置(confdefs.h)+ 设备驱动表 + 运行期链接器配置与驱动表([[rtems]])
INTEGRITY / ARINC 653 / VxWorks 653 / PikeOS分区(空间 + 时间 + 资源三域)静态配置;分区级 major frame / partition window + 分区内调度先对齐分区窗口与分区模式([[partitioned-rtos]])
NuttX与内核同镜像或分离,取决于构建方式由构建模型决定:FLAT 直接调用 / PROTECTED 走 syscall proxy / KERNEL 走 MMU先判 FLAT / PROTECTED / KERNEL([[nuttx]])
eCos与内核同镜像;中断处理分三层ISR → DSR → thread,各层同步机制不同判断工作落在哪一层([[ecos]])
ThreadX Modules常驻内核 + 可动态装载模块module preamble + request ID 经软件 dispatch先认 module ABI([[threadx-modules]])
FreeRTOS(上下文)与内核同镜像;中断上下文特殊task API 与 FromISR API 分离先判上下文([[freertos-context]])
µC/OS、SYS/BIOS与内核同镜像;中断参与调度ISR 显式通知内核(进入/退出);分层线程 Hwi > Swi > Task调度时机要把中断进出算进去([[ucos-sysbios]])
SAFERTOS、CMSIS-RTX5与内核同镜像;带访问控制与安全等级per-task 区域/保护域、API 与对象访问策略、ISR 延迟队列先判"谁能访问什么"([[safertos-rtx5]])
T-Kernel、TOPPERS与内核同镜像;服务调用合法性取决于上下文静态配置生成 task/handler;设备驱动以准任务部分运行先恢复上下文类型与规格家族([[tkernel-toppers]])
OSE / OSEck与内核同镜像但消息可跨节点消息式 IPC + 分布式透明传输层(共享内存/DMA/互连)先判消息对端在不在本地([[ose-oseck]])
Nucleus与内核同镜像;MMU/MPU 子系统隔离 + 线性内存映射动态 reload/restart/update 应用与内核模块(不必停机)"模块被替换但系统继续跑"与"隔离存在但 VA 不像每进程独立"都不是异常

失败模式决策表(本技能的主入口)

当"找不到调用关系""这段代码像死的""模块加载不了"时,按这张表先怀疑、再排除:

症状优先怀疑处理方向
某个 init / 设备对象没有直接 xref注册机制:iterable section / SYS_INIT / DEVICE_DEFINE(Zephyr)到 linker section 与 map 文件里裁决,别标 dead code([[zephyr]])
一整段规则排列的函数指针或结构体同上:linker 生成的注册表先按注册表理解,再考虑 vtable / jump table / 混淆([[zephyr]])
early init 里不调用内核服务PRE_KERNEL_* 阶段服务尚不可用(设计如此)别判"被裁剪";反之出现线程/互斥/睡眠应先怀疑阶段判错([[zephyr]])
一个进程没有内核模块却控制硬件QNX 用户态 resource manager找 resmgr_attach / dispatch_* / MsgReceive 与注册的 pathname([[qnx]])
网络驱动既不是进程也不是模块被 io-pkt 加载的 devnp-*.so找加载它的 io-pkt,确认原生还是经 shim 的旧驱动([[qnx]])
线程优先级在采样中突然变化QNX 消息驱动的优先级继承 / server boost不是主动调 pthread_setschedparam([[qnx]])
线程长时间阻塞在 IPCMsgSend 本就同步等待(正常状态)找"谁该 reply";pulse 才是非阻塞那类([[qnx]])
独立模块里大量 unresolved symbolsVxWorks DKM 链接到目标镜像的全局符号环境先定位 image 与 VSB/VIP 配置,别判 malformed([[vxworks]])
模块在同版本 VxWorks 上不工作具体 image configuration 不同核对 VSB/VIP 而不是版本字符串([[vxworks]])
dlopen() 行为不像 Unix 动态库RTEMS 运行时链接器重定位进当前地址空间;对象名可为 libfoo.a:bar.o([[rtems]])
找不到设备回调的 file_operationsRTEMS 设备驱动表(major = 表索引)恢复 rtems_driver_address_table 与 rtems_io_register_name([[rtems]])
任务数/调度器找不到运行期创建点RTEMS 构建期配置生成找定义 CONFIGURE_INIT 的那个翻译单元([[rtems]])
高优先级线程不运行(分区系统)分区级调度:当前没有它所属分区的执行窗口 / 预算,或分区还没进 NORMAL先对齐 major frame 与 partition window,再看线程优先级([[partitioned-rtos]])
"连写 A B C 只读到 C"采样端口的覆盖语义对队列端口才是异常([[partitioned-rtos]])
固定地址函数表被当成混淆APEX 服务表一类的 ABI先当服务表核对([[partitioned-rtos]])
同一个 API 反编译结果在不同样本里完全不同NuttX 的 FLAT/PROTECTED/KERNEL 构建差异先判构建模型;极短 API + 立即 trap 是自动生成的 syscall proxy([[nuttx]])
某地址"用户能访问 / 用户 fault"可能分别来自 malloc 与 kmalloc(双堆)分清 user heap 与 kernel heap([[nuttx]])
找不到真正操作硬件的地方NuttX 的 upper half / lower half 分层硬件实现常在 arch/ 或 boards/,不在 drivers/([[nuttx]])
ISR 里调用了 task 版 API上下文判定或符号识别有误(FreeRTOS)先判任务/ISR 上下文与 API 变体([[freertos-context]])
某地址"有时能访问、有时不能"MPU 受限任务或运行期改了 MPU 区域(FreeRTOS-MPU)查区域配置与运行期改区调用([[freertos-context]])
ISR 只清状态位就返回eCos 的 DSR 承担真正工作查 ISR 返回值是否调度 DSR([[ecos]])
大量「填 request ID → 跳公共 dispatcher」ThreadX Module 的 ABI建 request ID → 服务名映射,别判混淆([[threadx-modules]])
代码地址不在模块内存区内XIP 模块(指令在 Flash、数据在 RAM)别判控制流劫持([[threadx-modules]])
ISR 尾部发生切换 / task 已就绪却不切换中断进出参与调度(µC/OS 的进入退出协议;SYS/BIOS 的 Swi_disable 连带禁用 Task 调度)把中断进出算进调度时机([[ucos-sysbios]])
同一地址在不同 task 下可访问性不同per-task MPU 区域 / 保护域(SAFERTOS、RTX5)查区域配置与安全等级,别判内存损坏([[safertos-rtx5]])
句柄不像内存指针间接对象 ID + 交叉引用表(SAFERTOS ESM)别指望从它推出对象布局([[safertos-rtx5]])
ISR 里调用的 API 没立即生效ISR FIFO 延迟队列(RTX5)对象状态在 IRQ 退出后才变化,属正常([[safertos-rtx5]])
服务调用"非法"或被拒上下文类型(T-Kernel 任务/准任务/任务独立;TOPPERS 任务/非任务/ISR/循环/闹钟)对照规范的有效上下文表,别按 API 名推测([[tkernel-toppers]])
消息/信号的对端找不到消息可跨 core / CPU / DSP / node(OSE 的分布式透明传输层)别假定对端在本地,也别只查本地 syscall([[ose-oseck]])
模块被替换但系统继续运行Nucleus 的动态 reload/update(线性内存映射 + MMU/MPU 子系统隔离)见运行模型表;别先判劫持

何时使用 / 何时不用

  • 前置:先用特征串/魔数/符号确认是哪一个 RTOS(本家族内极易互认)→ [[re-analyze/system-fingerprints]] 的 RTOS 段与易混淆对
  • 用:MCU/IoT 固件跑 RTOS——定位任务表/TCB、按任务拆分反编译、还原队列/信号量/互斥/定时器等内核对象
  • 用:拿到的是裸镜像(无文件系统、无符号),需要从启动代码链找出调度器与全部任务入口
  • 用:商业 RTOS 固件(VxWorks/QNX/RTEMS/INTEGRITY)——车机中控、航电、工控场景,同样从任务/线程控制块定位出发,按进程/分区/任务拆分分析
  • 用:**"驱动/服务不以内核模块形式存在"或"注册关系不在源码里成立"**的情形——先判定运行模型(用户态 server / 全局符号环境 / linker 注册 / 构建期配置),见分支与决策表
  • 不用:裸机固件(无任务表/调度器,按普通 MCU 镜像分析,[[re-fw-extract]] → [[re-binary-core]])
  • 不用:Linux/Windows 内核(走 [[re-kernel]])
  • 不用:只需动态跑起来观察行为(走 [[re-fw-emulate]])

工具准备

本技能以纯静态分析为主(免沙箱,[[re-analyze/platform-tips]] 最高原则);需要动态验证时转 [[re-fw-emulate]]。工具可替换,方法为核心。

Ghidra(反编译与结构体定义主力)

  • 下载: GitHub NationalSecurityAgency/ghidra releases,解压即用(无需安装)
  • JDK 21(Ghidra 11.3+ 要求):
    • Linux: apt install openjdk-21-jdk / dnf install java-21-openjdk / pacman -S jdk21-openjdk
    • macOS: brew install openjdk@21 或 brew install --cask temurin
    • Windows: choco install temurin21
  • 启动: ./ghidraRun(GUI)/ ./support/analyzeHeadless(无头)
  • 验证: java -version(须 21+);./support/analyzeHeadless -help 正常输出
  • 用法核心:Data Type Manager 定义 TCB/内核对象结构体后,类型传播会显著改善反编译质量

binwalk(镜像提取先行)

  • 安装与版本形态以 [[re-fw-extract]]「工具准备」的安装矩阵为单一事实源,本技能不复制包名列表
  • 验证: binwalk --version

python3(脚本化解析与批量标注)

  • Linux: apt install python3 / dnf install python3 / pacman -S python
  • macOS: 自带;Windows: 官方安装器或 choco install python
  • 验证: python3 --version
  • 用途: 批量搜特征串/魔数、按字段偏移解析任务表、生成 Ghidra 脚本自动标注任务名/入口

操作步骤

按顺序执行,每步结果存档(任务清单、内核对象表、Ghidra 工程)。

  1. 前置:镜像提取与格式识别(衔接 [[re-fw-extract]] 流程):

    • 先按 [[re-fw-extract]] 完成:binwalk 解包 / dd 按偏移切分 / file + readelf -h 确认架构与字节序(大端 ARM/MIPS 固件常见)
    • 产物通常是裸镜像(raw binary)或单个 ELF;记录 reset handler 入口与 RAM 基址(从链接脚本/启动代码推断)——任务表与 TCB 都在 RAM 区,按链接地址解读
    • 确认字节序与架构后再导入 Ghidra,避免整个分析白做
  2. RTOS 识别:启动代码链 + 特征串/符号搜索:

    • 启动链形态:reset handler → 时钟/外设/内存初始化 → 创建任务(xTaskCreate / osThreadNew / tx_thread_create / k_thread_create / rt_thread_create / VxWorks taskSpawn(6.x 及更早常用;7 中仍存在,内部实现为 taskCreate+taskActivate)或 taskCreate(7 起,创建挂起任务需显式 taskActivate)/ QNX ThreadCreate / INTEGRITY ARINC 653 APEX CREATE_PROCESS)→ 调度器启动(vTaskStartScheduler / osKernelStart / tx_kernel_enter / rt_system_scheduler_start / VxWorks kernelInit / QNX 启动脚本拉起系统进程 / INTEGRITY START 进入运行态)。调度器启动调用点之前的代码全是初始化,不属于任何任务
    • 特征串:strings 搜内核名("FreeRTOS")、任务名("Idle" 等)、版本/断言串;ELF 未 strip 时直接搜符号(nm / Ghidra Symbol Table:pxCurrentTCB、_tx_thread_created_list、_kernel、rt_thread_ready_priority_group)
    • 商业 RTOS 特征串:VxWorks 任务名("tIdle" 空闲任务(VxWorks 6.x+)、"tRootTask" 根任务)与版本串;QNX 内核/镜像名("procnto"、"imagefs")与系统进程名(资源管理器惯用命名 io-*/devb-*/devc-*);INTEGRITY 分区名/进程名与 ARINC 653 APEX 服务名
    • ThreadX 无版本串可搜,靠调度入口 tx_kernel_enter + TX_THREAD 魔数 ID(步骤 3)确认
    • 不确定内核时:找 3-4 个任务创建调用点与调度入口的调用形态,对照各内核公开结构逐个排除
  3. 任务表定位(按内核选结构;用 Ghidra 定义结构体后逐字段还原优先级/状态/栈指针/任务名):

    • FreeRTOS:TCB(tskTaskControlBlock)关键字段——pxTopOfStack(栈顶指针)、uxPriority(优先级)、pcTaskName(任务名数组,默认 16 字节)、pxStack(栈起始,新版另有 pxEndOfStack);任务链表在静态区——pxReadyTasksLists[优先级数](按优先级索引的链表数组)、xDelayedTaskList1/2、xSuspendedTaskList;当前任务指针 pxCurrentTCB。定位方法:在上下文切换代码里找对 TCB 字段的读写(保存/恢复栈指针、更新当前任务指针),交叉引用回静态区
    • ThreadX:_tx_thread_created_list 全局双向链表(每个 TX_THREAD 经 created_next/created_previous 字段互链),配 _tx_thread_created_count 计数;TX_THREAD 关键字段——tx_thread_id(魔数 0x54485244 'THRD',用于确认结构)、tx_thread_name(任务名)、tx_thread_priority、tx_thread_state、tx_thread_stack_start/end/ptr(栈区)、tx_thread_entry(入口函数)
    • Zephyr:_kernel 全局结构(新版本为 struct _cpu,老版本为 struct _kernel)——current(当前线程指针)、ready_q(就绪队列:优先级位图 + 按优先级索引的队列数组)、timeout_q(超时队列)、idle 线程指针;另有 slist 全局线程链链着所有 k_thread;k_thread 关键字段——base.prio(优先级)、stack_info.start/size(栈区)、name(线程名)
    • RT-Thread:rt_thread_ready_priority_group(优先级位图)+ rt_thread_priority_table[RT_THREAD_PRIORITY_MAX](按优先级索引的链表数组);rt_thread 结构关键字段——name、priority、stack_addr/stack_size、entry(入口函数)
    • VxWorks:WIND_TCB 关键字段——td_name(任务名,字符串指针指向字符串池,非内联数组)、td_sp(保存的栈指针)、td_priority(优先级 0-255,0 最高)、td_status、td_options、td_entry(入口函数)、td_pStackBase/pStackLimit/pStackEnd(栈底/有效栈界/实际栈界)、td_stackSize/td_stackHigh(栈尺寸/历史最高用量)。注意版本差异:VxWorks 7 起 WIND_TCB 为不透明类型,taskLib.h 只提供 VX_WIND_TCB_SIZE 大小宏,字段偏移随版本/SMP 配置变化。定位方法:任务名串在字符串池里(搜 "tIdle"/"tRootTask"),交叉引用回指向它的 TCB;或从上下文切换代码(保存寄存器组到栈、写 td_sp、按 td_priority 挑选任务)反推字段偏移,再沿任务链表回静态区
    • QNX:procnto(微内核 + 进程管理器一体)管理线程控制块——线程是调度最小单位,进程只是地址空间容器;线程关键属性——tid(进程内线程号)、优先级(256 级,0 为 idle)、线程名(6.3.2+ 支持)、栈与 TLS 区(含 tid/pid/栈基/errno)(内部布局无官方公开定义,属性经系统调用参数与 /proc 侧信道观察)。定位方法:QNX 固件是 IFS 镜像(startup 头魔数 0x00ff7eeb + "imagefs" 签名),用 dumpifs 解出各系统进程 ELF 再逐个分析(procnto 即内核本体);应用侧从 ThreadCreate/MsgSend 等内核调用点定位线程,线程名串交叉引用回线程控制块;动态环境可用 /proc//ctl 的 DCMD_PROC_TIDSTATUS 读线程状态做侧信道
    • INTEGRITY:分区(partition)是空间+时间隔离单元——空间上每分区独立内存区(MMU 强制),时间上按模块调度表(module schedule)循环分配执行窗口(一轮 = major frame);分区内任务为 ARINC 653 进程,进程控制块属性含入口、栈尺寸、基优先级、周期/期限。定位方法:全静态配置——启动时一次性分配,无动态内存/无动态任务创建,对象地址固定,boot table 定义资源归属;分区/进程名串在固件里可读,交叉引用回配置表;ARINC 653 APEX 服务名(CREATE_PROCESS/SET_PRIORITY/GET_TIME 等)调用点即内核服务入口
    • 产出任务清单:逐个 TCB 读出任务名/优先级/栈区间/入口地址,每任务一行
  4. 任务栈识别:

    • 每任务 TCB 里有栈区字段:FreeRTOS pxStack/pxEndOfStack、ThreadX tx_thread_stack_start/end、Zephyr stack_info.start/size、RT-Thread stack_addr/stack_size、VxWorks td_pStackBase/pStackLimit/pStackEnd + td_stackSize(默认 0xee 填充,VX_NO_STACK_FILL 选项关闭)、QNX 线程栈界可从 TLS 区(栈基/tid/pid)辅助确认、INTEGRITY 进程栈在分区内存区内(栈尺寸在进程创建属性里)
    • 栈区形态:.bss 中按配置宏对齐的静态数组,或从内存池分配;FreeRTOS 开栈溢出检查时栈内为 0xa5 填充模式,可辅助确认栈范围
    • 按栈归属切分任务边界:栈区间属于该任务(局部变量、嵌套调用链),反编译时用"哪段栈属于哪个任务"划分代码归属;任务切换时保存/恢复的栈指针值直接对应 TCB 的栈顶字段
  5. 内核对象(队列/信号量/互斥/定时器):

    • 从内核 API 调用点反推:xQueueSend/xQueueReceive/xSemaphoreTake/xTimerCreate(FreeRTOS)、tx_queue_send/tx_semaphore_get/tx_mutex_put/tx_timer_create(ThreadX)、k_sem_take/k_mutex_lock/k_queue_get/k_timer_start(Zephyr)、rt_sem_take/rt_mutex_take/rt_mq_recv(RT-Thread)——调用点第一个参数就是对象指针,沿交叉引用回溯到对象定义处(.bss 静态实例或内存池)
    • 商业 RTOS 内核对象:VxWorks 信号量(semGive/semTake)、消息队列(msgQSend/msgQReceive)、事件(eventSend/eventReceive)、看门狗(wdCreate)——调用点参数即对象 ID,沿交叉引用回溯到静态区定义;QNX 是 channel/connection 模型——MsgReceive 线程建 channel、MsgSend 线程建 connection,同步消息使线程进入 SEND/REPLY/RECEIVE 阻塞态(消息跨地址空间直拷、无中间缓冲),pulse 是 4 字节数据 + 1 字节 code 的非阻塞通知;INTEGRITY 分区间通信是采样端口(sampling port,覆盖写语义)/队列端口(queuing port,排队语义),分区内为信号量/事件/缓冲/黑板,按 ARINC 653 服务名搜索
    • ThreadX 对象头有魔数 ID 可逐个确认(以官方源码为准,勿凭资料记忆):TX_QUEUE 0x51554555 'QUEU'、TX_SEMAPHORE 0x53454D41 'SEMA'、TX_MUTEX 0x4D555445 'MUTE'、TX_TIMER 0x4154494D 'ATIM'、TX_EVENT_FLAGS 0x4456444E 'DVDE'、TX_BYTE_POOL 0x42595445 'BYTE'、TX_BLOCK_POOL 0x424C4F43 'BLOC'(旧资料中 TIMR/EVEN 写法不实,勿沿用)
    • FreeRTOS 中信号量/互斥是队列(Queue_t)特例(结构同构),定时器为 Timer_t;用 Ghidra 定义结构体后,调用点参数类型传播自动改善反编译
    • 对象用途从语义推断:谁 send 谁 receive、take 之后处理什么,即任务间通信链路
  6. 按任务拆分反编译:

    • 每任务一个入口独立分析:任务创建 API 的 entry 参数 → 函数 → 重命名为 task_<优先级>_<名字>,Ghidra 中逐任务标记入口
    • 任务内阻塞点(延时/等信号量/收队列/等事件)是调度切换点,按阻塞点把任务逻辑切成状态段分析
    • 任务间通信对象(队列/信号量)连接不同任务:先画"任务-对象-任务"关系图,再按图逐个深挖

平台分支(references)

以下四个平台的"驱动/服务模型"与通用任务表方法差异足够大,单独成篇——先读分支判定运行模型,再回到本主文档做任务与对象分析:

  • [[qnx]] —— 用户态 server 模型:resource manager(dispatch_create → resmgr_attach → dispatch_block/handler,底层是 MsgReceive)、connect/I/O 两张函数表与 iofunc_* 默认实现的区分、devctl 与 _IO_DEVCTL、io-pkt 与 devnp-*.so(含单线程栈上下文)、消息驱动的优先级继承与 server boost、MsgSend 同步阻塞 vs pulse
  • [[vxworks]] —— DKM(.out,内核态)vs RTP(.vxe,用户态)、DKM 与全局符号环境的链接关系、undefined symbol 的真实成因(VIP 未含组件)、独立模块 unresolved 属常态、VSB/VIP 与"同版本不同 ABI 环境"
  • [[zephyr]] —— 编译期设备图:DEVICE_DEFINE/DEVICE_DT_DEFINE 与 linker section、SYS_INIT 的 level/prio 与返回值后果、iterable sections(规则排列的结构体未必是混淆表)、/chosen 与 /aliases 不是硬件节点、map 文件裁决归属、LLEXT(导出符号表、llext_unload 后指针失效、User Mode 下需 llext_add_domain)
  • [[rtems]] —— 单地址空间 + 构建期配置:confdefs.h 与 CONFIGURE_INIT 唯一性、rtems_driver_address_table 六入口与 major = 表索引、rtems_io_register_name、运行时链接器不是 Unix 共享库模型(libfoo.a:bar.o、懒/立即绑定等价、未解析不报错、重名即错误、基镜像需 rtems-syms)
  • [[partitioned-rtos]] —— 分区系统(INTEGRITY / ARINC 653 / VxWorks 653 / PikeOS):major frame + partition window 的两层调度(PikeOS 三层);分区模式 IDLE/COLD_START/WARM_START/NORMAL(进程"不跑"常是还没进 NORMAL);采样端口 vs 队列端口的覆盖语义;INTEGRITY 的固定 CPU/内存预算与静态启动表;PikeOS 的 APEX 固定地址服务表与 POSIX guest 的 system thread 映射
  • [[nuttx]] —— FLAT / PROTECTED / KERNEL 三种构建:同一 API 产物完全不同;PROTECTED 的自动生成 syscall proxy(极短函数 + 立即 trap,不是 hook);双堆(user heap / kernel heap);驱动的 upper half / lower half 分层
  • [[freertos-context]] —— ISR 与任务上下文:task 版 vs ...FromISR() 版 API、pxHigherPriorityTaskWoken 与 portYIELD_FROM_ISR(真正的切换发生在中断退出后)、configMAX_SYSCALL_INTERRUPT_PRIORITY(更紧急的 ISR 一个 API 都不能调,且优先级数值方向相反);FreeRTOS-MPU 的受限任务与运行期改区
  • [[threadx-modules]] —— module preamble(必在第一个地址、properties 位决定特权/MPU)+ request ID 经软件 dispatch 调用常驻 Module Manager(本质是 syscall table,不是混淆)+ XIP 与拷贝装载
  • [[ecos]] —— 运行期:ISR / DSR / thread 三层、三种同步级别与各自的锁(ISR 不能用 DSR 级锁;DSR 能 signal 条件变量但不能 wait)、三种驱动模型;构建期:CDL 配置系统决定编入项与构建目标、HAL 向量表(VSR)与虚拟向量、RedBoot 启动顺序与构造函数在向量表初始化之后运行(区域重叠会被冲掉)、调试桩的去向
  • [[ucos-sysbios]] —— 中断进出参与调度:µC/OS 的 OSIntEnter/OSIntExit 成对协议与"只有最后一个嵌套 ISR 退出才判断切换";SYS/BIOS 的 Hwi > Swi > Task 分层、Swi_disable() 连带禁用 Task 调度、Hwi/Swi 共用 ISR 栈
  • [[safertos-rtx5]] —— 认证 RTOS 的隔离特性:SAFERTOS ESM 的 API 访问策略 / 对象访问策略 / 间接对象 ID / per-task 区域;RTX5 的 Safety Class / MPU 保护域 / 线程看门狗 / 对象与 SVC 指针检查、ISR FIFO 延迟队列(溢出时系统状态已不一致)
  • [[tkernel-toppers]] —— 上下文合法性:T-Kernel 的任务/准任务/任务独立三种上下文与设备驱动(准任务部分、必须可重入、不保证互斥);TOPPERS 的四个家族(ASP3 / HRP3 / FMP3 / HRMP3)与静态配置生成
  • [[ose-oseck]] —— 信号模型(不是 POSIX 信号;信号号不唯一,需配合次级 id;先注册后发送否则丢;一次事件可能关联多个信号要取空)+ 进程/块/段/池的内存所有权(只能在自己的池里分配,跨域发送会被拷贝)+ 监督与错误处理器(含"结尾标记能检出什么、检不出什么")+ OSE 与 OSEck 的差异与异构边界(信号跨 core/CPU/DSP/节点;系统信息接口可看信号空间与保存的寄存器/栈)
  • [[nucleus]] —— 线性内存映射 + 受保护区域 + entitlement(MMU 在 Cortex-A、MPU 在 Cortex-M;不是每进程独立 VA);NU_PARTITION_POOL 是固定块内存池(与隔离域同名的术语坑);NU_SUSPEND 下池空则任务本就挂起;模块可动态 reload/restart/update 而不停机

跨域联合

  • [[re-fw-extract]]:镜像提取与格式识别前置(binwalk 解包、magic 扫描、字节序判断、偏移切分)
  • [[re-fw-emulate]]:需要动态验证(跑任务、触发调度、观察切换时序)时仿真目标固件
  • [[re-automotive]]:QNX 车机中控场景联动(车载系统侧固件/进程分析,与 CAN/ECU 侧互补)
  • [[re-binary-core]]:RTOS 应用深层反编译底座([[re-ghidra]] 定义结构体,或按环境选 [[re-radare2]])
  • 发现恶意逻辑 → [[re-malware]];任务与服务器通信 → [[re-protocol]]
  • 本技能可被 [[re-firmware]] 网关的 MCU 固件深挖路径调用

常见坑与陷阱

  • 调度器启动前的代码当任务分析:现象——把 reset handler 到调度器启动之间的初始化序列当成某个任务的主逻辑,分析半天对不上业务;原因——启动代码(时钟/外设/内存/创建任务)先于调度器执行,不属于任何任务,且与任务入口的调用形态相似;对策——先定位调度器启动调用点(vTaskStartScheduler/osKernelStart/tx_kernel_enter/rt_system_scheduler_start/kernelInit),之前的归为初始化,任务入口一律从创建 API 的 entry 参数取
  • stripped 固件没有任务名:现象——TCB 里名字字段全空/乱码/全 0;原因——固件 strip 符号且裁剪了字符串表,pcTaskName/tx_thread_name 无内容可读;对策——用栈指针范围(每任务独享栈区间)、优先级值、创建顺序编号区分任务,任务名只当辅助线索
  • 链表 vs 静态表结构差异:现象——按"静态数组任务表"假设在固件里找不到任务列表;原因——各内核组织方式不同:FreeRTOS 是静态链表数组(pxReadyTasksLists 按优先级索引)+ 当前指针 pxCurrentTCB,ThreadX 是全局双向链表 _tx_thread_created_list,Zephyr 是 slist 全线程链 + ready_q 位图队列,RT-Thread 是优先级位图 + 数组链表,VxWorks 任务挂全局任务链表(taskIdListGet 可枚举语义),QNX/INTEGRITY 布局不公开、从创建/服务调用点与句柄表反推;对策——先识别内核再选对应结构(步骤 3),别拿一种内核的布局套另一种
  • 新版 RTOS 去字符串/去符号后搜不到特征:现象——strings 和符号表里什么都没有,内核识别卡住;原因——发布固件常 strip 符号、关断言/关字符串、甚至裁剪版本串;对策——用结构特征兜底:ThreadX 魔数 ID(THRD/QUEU/SEMA…)、FreeRTOS 临界区模式(Cortex-M 上 BASEPRI 保存/恢复的固定序列)、调度入口与上下文切换代码形态、按版本比对 TCB 字段偏移(从任务入口参数如何写入 TCB 反推全结构)
  • idle/低优先级兜底任务当业务任务:现象——把空转循环任务当成主要业务逻辑深挖;原因——FreeRTOS 自动创建 prvIdleTask(最低优先级 0)、Zephyr 有 idle 线程、VxWorks 有 tIdle 任务,它们只跑钩子/清理/低功耗代码,与业务无关;对策——任务清单按优先级排序,最低优先级、无阻塞的无限循环先排除为兜底任务,业务任务从高优先级和含阻塞点(队列/信号量等待)的任务里找
  • 上下文切换/调度代码当普通业务函数:现象——PendSV/SVC handler 或调度循环被当业务逻辑跟踪,调用关系混乱;原因——RTOS 的上下文切换(保存/恢复寄存器组、切换 pxCurrentTCB/current)与任务代码同属固件,反编译器视为普通函数;对策——识别切换特征(保存全寄存器组、更新当前任务指针、从栈顶恢复 PC/LR)后标记为调度代码不深入,任务逻辑只看创建 API 入口往下的调用树
  • 商业 RTOS 结构无公开定义,旧资料偏移不可套用:现象——按网上 VxWorks 5.x 的 WIND_TCB 偏移在 VxWorks 7 固件里解出乱码;原因——VxWorks 7 起 WIND_TCB 为不透明类型(taskLib.h 只给 VX_WIND_TCB_SIZE)、QNX 线程控制块与 INTEGRITY 进程表布局未公开,且随版本/SMP 配置变化;对策——字段名只当语义线索,偏移一律从上下文切换/创建代码现场反推,用字段读写模式验证
  • 任务名字段是字符串指针不是内联数组:现象——在 TCB 里按 FreeRTOS 习惯找定长名字数组,读到的却是地址值;原因——VxWorks td_name 是 char* 指向字符串池,QNX/INTEGRITY 线程名同理;对策——拿到字段后先判断是地址还是内联数据(交叉引用看是否指向字符串区),固件裁剪字符串后名字字段会失效,改用栈范围/优先级区分任务
  • QNX 固件是 IFS 镜像,不能当裸二进制直接搜:现象——整块固件里搜不到 procnto 或进程代码;原因——QNX 镜像内文件常 LZO 压缩,字符串与代码都不可见;对策——先按 startup 头(0x00ff7eeb)+ "imagefs" 签名定位镜像,用 dumpifs 解压提取(startup 头字段被改过时加 -z),得到各进程 ELF 再分析
  • INTEGRITY 运行期没有动态创建:现象——把分区模式切换(SET_PARTITION_MODE 的 COLD_START/WARM_START/NORMAL)或进程启停(START/STOP)当"创建任务"逻辑分析;原因——INTEGRITY 资源启动时静态分配,运行期主要是状态迁移,无动态内存分配;对策——创建类代码只出现在初始化/配置路径,业务逻辑按周期调度(major frame)与 APEX 服务调用组织
Gespeicherte Skills