Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

Avatar: A Framework to Support Dynamic Security Analysis of Embedded Systems’ Firmwares

Abstract & Introduction

  • 作者设计并实现了一个动态分析框架,方便用户分析嵌入式设备
  • 作者讨论了一些可能用于该引擎的优化方式,说明复杂的动态分析可以应用在这个框架上
  • 作者在三个不同场景下(逆向分析,漏洞检测,后门检测)评估了这个框架

Dynamic Firmware Analysis

  • 嵌入式设备进行动态分析是有难度的,这主要是因为尝试模拟一个嵌入式系统不仅仅需要对CPU的模拟,还要很多模拟外围设备(DMA, 交换芯片)的行为。不能正确模拟这些外围设备的话,模拟执行的固件会经常挂起,crash,或者与物理设备的行为有很大差异。。。。
  • 目前已提出的分析方法包括:
    • 全硬件模拟: 模拟该设备上的所有硬件。 先不说复杂度,很多芯片的文档都是难以拿到的。
    • Hardware Over-Approximation: 作者举了几个例子,这种系统会假设CPU从IO端口可能读到任意的值,一个中断可能在任何时间发生,CPU从IO端口总是能读到数据,不需要等待。。
    • Firmware Adaptation: 固件的一部分是可以分离出来单独进行分析的,也就是固件本身是一个linux。。但是在低端设备上固件一般都一个是整体
  • 作者提出的是: 模拟CPU,然后把所有的IO中断都传给实际的物理设备。。

Avatar

  • 系统结构
    • 直觉的想法是直接连线,把cpu的所有引脚都抽出来,中断/IO相关的部分的引脚就是与外围相关的部分,然后虚拟CPU对应的针脚“连接”到物理设备的针脚上。。作者显然不想这么做。。而且实现难度无限大。。
    • 作者采用了一种比较通用的方式
    • 直接来看作者的整个系统框架图:Figure 1
      • 左边的Emulator就是一个带符号执行功能的ARM CPU模拟器:
        • qemu config和qemu gdb 是用来改变qemu的行为(在需要的时候修改CPU的寄存器状态)
        • S2E QMP/Lua 符号执行相关吧,不确定。。
        • RemoteMem plugin:是用来将获取VM中memory和修改memory用的
      • 右边是target device:
        • 两种方式获取/修改状态:
          • 在系统中植入gdb stub(Remote_Debugging)
          • 很多设备上可能有JTAG,那么可以直接访问寄存器和内存
        • 然后用户通过一个GDB adapter(或者别的adapter)访问,看起来就像是在调试一个普通的进程
  • Full-seperate mode
    • 所有指令都由Emulator执行,通过UART(38400bps)每秒只能传送5次内存写的请求(JTAG 应该会快一些)
    • 这根本慢的无法接受,况且很多执行过程还要求在一定时限内完成。。
      • 一些polling 的循环要跑好久。。
      • 一些来自时钟的中断不断触发,模拟器前一次的中断还没处理完,下一次的又来了。。。
    • 所以文章后面的部分作者都在尝试解决这个慢的问题。。
  • Context Switching
    • 我们可以先从某一特定位置开始才模拟执行
      • JTAG本来就是用来调试硬件的,可以下断点
      • debuger也可以下断点
    • 模拟执行完毕之后:
      • 我们也可以把控制权交回硬件,来看接下来硬件的执行效果。。

Overcoming the Limits of Full Separation

  • 内存访问:
    • 分析:
      • 首先,没有必要就不需要在每次取指令时通过adapter从物理内存中取,预先取好了之后在任何时候都不会变的。。
      • 其次,一个完整的函数进行模拟执行,整个栈也是不需要从物理内存中取的。。
      • 最后,自己想想的话,会被外围设备修改/访问的内存只会有特定的一些(内存映射),剩下所有的内存都是可以直接放到模拟器里的
    • 所以如果可以识别出那些地址空间是IO,哪些不是,然后在context switch到模拟器之前,将所有不是IO的部分都拷入模拟内存,然后在执行过程中将其他部分通过adapter传过去就好了。。
    • 下面是作者对硬盘的bootloader的内存访问的统计

      Access Type Read Write
      Code 61632 0
      Stack&Data 646 1795
      I/O 3614 2097
  • 自动迁移:
    • 首先是一个已经实现的,一个轮询的循环,等待某一个设备是否完成,只会访问某个IO,这个过程就不需要再模拟器上执行了,扔回到物理设备上执行,而且还不需要传输内存(因为这段代码完全不访问模拟内存)
    • 类似的,所有我们不关心的代码都可以这样做,如果他只访问很少的内存,那么迁移回到物理设备上执行,大幅提高效率(依赖静态分析,作者还没有完全实现)

Extending Avatar

  • 到此为止,宏观上看,作者已经有了一个模拟器,针对部分代码进行分析的话,执行效率不算差
  • 目前avatar拥有的符号执行相关的功能:
    • 检测PC是否是符号化的,读取内存,写入内存使用的地址是不是符号化的(其实看起来更像是污点分析)
    • 具体怎么实现的其实并不重要,模拟器都有了,符号执行就很自然了
    • (大不了把整个解释器放在一个符号执行引擎里跑也可以- –)
  • 目前的limitation
    • 局限性都在模拟器和target的状态同步上:
      • 有的设备上有DMA, 有些内存的修改并不通过CPU实现,而是通过CPU发送IO请求给DMA去做。。。。然而我们并不知道各种DMA具体的协议,所以我们不知道DMA做了什么。。。
      • 我们并不知道哪些内存被target访问过,因此如果迁移到target的代码的静态分析结果无法完全确定访问的内存,那么这段代码执行结束后,就需要把整个内存传输回模拟器
      • 符号执行只能在模拟器上实现,也就意味着target执行到分支点之后只能选择一个分支继续执行,执行之后难以再回到分支点(即使恢复了内存和寄存器,外围设备的状态也难以恢复。。)。。
        • 当然,我们可以尝试做重放。。。慢。。(而且不可靠。。)

Evaluation

  • 三个实验分别是对一块硬盘,一个zigbee传感器(zigbee是一种低功耗无线局域网协议)以及摩托罗拉C118的分析
    • 硬盘:
      • 硬盘的UART有一个用来升级的菜单
      • 硬盘的JTAG不具备调试功能,所以只能植入stub,
      • stub首先执行,然后才是bootloader,
      • 作者首先尝试模拟执行到UART输出menu并等待用户输入:
        • full-seperate执行了一天,太久了,放弃
        • 加上非IO内存访问的优化,花了8个小时
        • 由于大量的时间都花在了读取bootloader读取flash中的OS,解压到内存的过程中,作者虚拟了那块flash,现在就只需要4分钟就可以执行到menu了
      • 符号化menu的输入,并符号执行,用户就可以检测menu中是否有没有显示的隐藏命令。
      • 再作者的分析中并没有发现隐藏命令,不过发现一些命令参数解析的错误
    • zigbee 传感器:
      • 这个设备有JTAG
      • 直接再解析数据包的地方下断点,context switch 然后符号执行,发现有个地方可以控制返回地址为不合法的值
    • C118:
      • 有JTAG
      • 之前已经有关于畸形SMS导致错误的行为的报告,不过是fuzz出来的 * 作者这里使用自己的分析引擎断在接受到SMS数据之后,并将对应的内存标记为符号,开始符号执行:
        • 花了10个小时,。分支出120,000个状态。。。用尽了电脑的60G内存,没有跑出来。。。
        • 作者又尝试跑完了42个用来decode的subroutine,然后那个已知的问题也没能跑出来。。
        • 最后作者放弃了,说SMS的协议栈太过于复杂。。。符号执行的路径爆炸问题并不是本文的重点。。。

Conclusion

Avatar allows to analyze firmwares that rely on completely unknown peripherals.

  • 作者实现了模拟器和物理设备进行context switch的想法,
  • 通过最后的实验也论证了这种模拟执行的效率是可以接受的
  • 并且通过符号执行,证明再整个平台上去做已有的动态分析是可行的