CFI(Control-Flow Integrity)来自于CCS 05!

简介

控制流完整性,可以防止那些任意控制程序行为的攻击。CFI的特点:

  • CFI实施是很简单的,保障很容易建立;更近一步说,它是很实用的,它可以兼容现存的。
  • CFI实施提供保护,即使是对整个执行程序的数据有完全控制的敌人。
  • CFI为实施进一步的安全策略提供一个有用的基础。

CFI的安全策略要求/命令软件执行过程必须按照一个提前设定的CFG中的路径,然后这个CFG可以通过源码分析、二进制分析或者执行剖析得到.这个提前设定的CFG是一个关键。

因为从我的感觉,这个方法就像是程序设计者或者说保护着预先设计了一个游戏,这个游戏规定用户只能做出这样或者那样的行为,不能跳出他的设计范围,否则即刻出局.

用原文中的话就是说,运行时的动态检测必须保证控制流保持在给定CFG的范围内。CFI的主要工作就是对于直接或者间接的控制流进行限制。

由于在一些攻击中不正常的控制流更改是必须的步骤,所以CFI对于它们的防御还是很有效果的。比如说classic, stack-based buffer overflow。CFI实施并不是万能钥匙,因为对于已允许CFG边界内的渗透无法防御。这些渗透包含依赖错误参数字符串转化的特定渗透等。就像上面说的游戏的例子,只要用户行为在游戏规定的范围之类,就算这属于攻击行为,游戏程序也是不会对它做出反应的。

CFI需要,程序执行期间,无论何时一个机器指令转移控制流,它目标定位于一个有效的目的地址,正如先前创建的CFG图判定的。因为大部分的指令目标是一个常量目标地址,所以这个要求通常静态地施行。然而,对于目的地址只能在动态运行时确定的计算控制流,这个要求必须实施一个动态检查.

实现

label

利用ID来进行跳转的动态检查,这里的call,ret的用法都不是原本这两个命令所有的用法,有可能是进行插桩修改过的!完全看不出来作者的实现方法.

instrumentation

这张图解析了两种可行的ID和ID检测方式。作者使用12345678h来作为ID,上图中第一部分是一个简单的间接跳转实例!左侧是直接跳转指令jmp ecx,右侧是一个从栈上取内容的mov指令。其中ecx中放的是目的指令所在的地址。

  • a方案:在目的地址mov指令处加上ID,同时在计算目的地址处加上lea指令(这个指令的 好处是不修改eflags,同时将ecx加4)。直接比较[ecx]12345678h,不等的话直接跳转到错误label,否则将ecx加上4,然后跳转.

  • b方案:使用ID-1作为ID检查的常量,在运行期间加1。相同的是,b方案也没有改变计算跳转地址,但是它并不是插入一个ID,而是加入了一个无副作用的prefetchnta指令来人工合成ID。要注意,这里所谓的无副作用指令,就是没有效果,单纯放在那里,引出来参数地址。这里有一个疑问3没有解决。

我们来说明一下核心思想:对于限制间接跳转的动态检查,我们可以这样做!假设我们有一个动态检查的可能集合。对于间接跳转,我们将动态运行的结果和我们的集合进行对比,如果动态结果不在我们预先设置的集合,就跳到错误处理的地方.

但是,对于动态集合大小的设定,我们需要在精确和效率做一个权衡,这里涉及到图1中的ID设定,如果sort2不同的放回位置设置不同的ID,我感觉也是可以的!但是这样就要考虑由于动态检查集合的增大而带来的性能损失.

implemention

这张图解释了函数调用和返回的时候使用的插桩方法.函数调用这里综合了a,b两种方案,你可以对比它们!对于后边prefetchnta的作用是为函数返回时增加动态验证.关于这个地方,我们可以从函数返回处的插桩代码很容易看出来.ecx原本指向prefetchnta [AABBCCDDh]这个指令的地址,所以使用cmp [ecx+4],AABBCCDDh来进行动态检查.

这篇文章向我讲述了很多关于间接转移指令,如函数返回,函数指针调用,switch结构和其他如C++ vtables之类的结构。

问题讨论

  1. 文章中说已给出的CFG是如何生成,间接跳转它是如何拿出来的?

  2. 关于作者自己定义的Lable ID; call ID,DST; ret ID这些指令是自己实现的,还是一个虚拟定义,具体实现的时候并不是这样的?为什么问这个,因为我去查过关于callret,没有这样的用法!ret指令,是可以带参数,但是这个表示的也不是ID啊.

  3. 关于mov eax,12345677h;inc eax;没有想出来原因.

  4. 关于prefetchnta这个指令的使用,无论是Figure 2(b)还是Figure 3中,完全不明白是什么意思?曾经去查过这个指令,它是intel用于缓存的命令,但是手册上面并没有详细说明?

  5. CFG结构正确处理了x86中执行计算控制转移的指令,包括函数返回,通过函数指针发出的函数调用,switch结构,动态调度。上述话语描述了程序中的间接跳转,但是我不是很明白这个可能集合如何得到??? 特别是switch结构的各种case如何得到?对于函数指针发出的函数调用,本文利用二进制文件中的重定位信息来获得.这个问题貌似又回到了问题1.