Android的fuzz测试技术之符号执行浅谈-android学习之旅(82)

时间:2023-03-09 03:43:30
Android的fuzz测试技术之符号执行浅谈-android学习之旅(82)

简单的漏洞越来越少,需要改进目前的方法 :

通过符号执行,得出执行路径,然后在进行fuzzy是较为有效的方法之一

1)为待测单元自动地生成可到达的测试数据,即提高测试目标的覆盖率

2)根据特定的漏洞模式和路径条件,缩小 Fuzzing 测试范围,减少Fuzzing盲目性

Android的fuzz测试技术之符号执行浅谈-android学习之旅(82)

符号执行(symbolic execution)是一种代码执行空间遍历技术。枚举了程序所有可能的路径,穷尽所有执行空间,给定漏洞特征,理论上可以检测所有符合特征的安全漏洞

#

过程内符号执行从 CFG 的入口点开始。将所涉及到的变量符号化(使用符号表示变量值),依次解析程序中的语句和指令,翻译为符号表达式。每个变量的值都由符号化的变量和常数构造表达式来表示,并在每一个结点记录变量的符号运算表达式。符号执行过程中遇到流程控制语句,则将条件判断语句对变量值的要求附加到路径条件中,使用约束求解器判定哪条分支可行,并根据预先设计的路径调度策略实现对该过程所有路径的遍历分析,最后输出每条可执行路径的分析结果

静态分析和动态符号执行的最大区别在于静态分析并不真正执行被测试程序

静态符号执行的核心思想是探索执行树(execution tree)上所有的控制路径(control path),前提是所有可能的输入值都被考虑到

可行路径的数量随着路径长度的增长呈现指数增长的趋势。因此,要把所有可行路径都探索完是几乎不可能的

Int x,y
If(x=hash(y))abort;

任意x对y赋值,求出hash(y),得到满足条件的解
例如y=5,hash(y)=2,求出,2,5满足条件

If(hash(x)=hash(y),动态也不行了,具体执行
Concretization,完了又回到符号执行
(conclic symbolic execution)

混合符号执行介绍

混合符号执行的核心思想是在程序真实运行过程中,运行时判断哪些代码需要经过符号执行,哪些代码可以直接运行。这样一来符号执行就充分利用了程序的运行时信息,提高了分析的精确性

Android的fuzz测试技术之符号执行浅谈-android学习之旅(82)

如何知道哪些是符号值?

静态对变量符号化,需要源码(具体实现没研究)Klee需要源码,然后转换成中间代码IR(.BC文件)S2e可执行文件

源码插桩,二进制文件插桩

具体事例介绍

#include <stdio.h>
#include <string.h>
#include "s2e.h"
int main(void)
{
  char str[3];
  // printf("Enter two characters: ");
  // if(!fgets(str, sizeof(str), stdin))
  //   return 1;
  s2e_enable_forking();
  s2e_make_symbolic(str, 2, "str");
  if(str[0] == '\n' || str[1] == '\n') {
    printf("Not enough characters\n");
  } else ……
  s2e_disable_forking();
}
if (size)
fb_info_size += PADDING;
p = kzalloc(fb_info_size + size, GFP_KERNEL);

char tmp_info[] = “drivers/video/fbsysfs.c”;
s2e_message(info);
u32 tmp_l = fb_info_size;
u32 tmp_r = size;
s2e_detect_int(&tmp_l, &tmp_r, 4, UADD);
控制权交给s2e
if (!p)
return NULL;

通过内联汇编向二进制代码中插入一条 x86 指令集中没有定义的指令,当 Linux 内核在 S2E 上执行到这里时,会识别这条指令并将控制权交给 S2E,S2E 会根据其中一个固定字节的值来选择我们编写的整数溢出检测插件,函数的参数会通过 RAX 等寄存器传入 S2E 以供使用

X86(bin)->ucode(IR) ->instrument->x86

1. 首先判断传入的左右操作数中是否有符号化数据,如果没有,直接返回,因为我们只关心符号值所影响到的数据。

2. 根据传入的整数溢出错误类型重构表达式,即整数溢出发生的验证条件

3. 将重构的表达式加入到当前路径下的约束表达式中,通过约束求解器进行求解 。

4. 如果存在可行解,则输出可行解并报告当前路径下存在整数溢出漏洞。

 if(x==0xdeadbeef){
2. return 100/(x-0xdeadbeaf);
3. }
4. else
5. return 100;

当x为0xdeadbeaf时,代码会发生除0异常。在32bit空间上随机生成x的方式仅有1/232的概率触发除0异常。
void klee_div_zero_check(long long z) {
  if (z == 0)
    klee_report_error(__FILE__, __LINE__, "divide by zero", "div.err");

二进制符号执行介绍:

过于依赖程序源代码,可扩展性受限,运行平台苛刻,无法评估第三方模块、库函数的安全影响

二进制分析缺乏大量信息,没有程序变量的概念,处理的对象是内存单元和寄存器

低级指令系统也十分复杂

程序的执行轨迹包含的指令数目庞大