符号执行初识

一、符号执行概念

符号执行(Symbolic Execution)是一种程序分析技术,它 可以通过分析程序来得到让特定代码区域执行的输入
符号执行的 目的 是在给定的时间内, 生成一组输入,并通过这些输入尽可能多的探索执行路径。根据运行目的来分,主要有两个:
  • 从测试的角度来看,它可以模拟出各个路径的输入值,从而创建高覆盖率的测试套件。
  • 从缺陷查找的角度来看,它为开发人员提供了触发缺陷的具体输入,利用该输入,程序可用于缺陷的确认与调试。符号执行不仅限于查找诸如缓冲区溢出之类的问题,而且可以通过根据缺陷发现的条件,生成复杂的断言,来判断缺陷发生的可能性。
符号执行的优势是能够以尽可能少的测试用例达到高测试覆盖率,从而挖掘出复杂软件程序的深层错误。但会受到 路径爆炸问题约束求解困内存建模等问题。
  
符号执行经过了 传统符号执行动态符号执行 性符 执行 的发展过程,动态符号执行包括 混合测试  和  测试两种。
  • 经典符号执行并不真实地执行,而是基于解析程序,通过符号值模拟执行;有代价小、效率高的优点,但是执行效率比较低、误报高。
  • 动态符号执行结合使用了具体执行与符号执行,综合了具体执行和经典符号执行的优点,并出现了 混合执行  和  执行生成测试 两种符号执行技术;
  • 选择性符号执行可以对程序员感兴趣的部分进行符号执行,其它部分用真实值执行,代表工具 S2E

二、经典符号执行

经典符号执行的核心思想是通过使用符号值来代替具体值作为程序输入,并用符号表达式来表示与符号值相关的程序变量的值。在遇到程序分支指令时,程序的执行也相应地搜索每个分支,分支条件被加入到符号执行保存的程序状态的PC中,PC表示当前路径的约束条件。在收集了路径约束条件之后,使用约束求解器来验证约束的可解性,以确定该路径是否可达。若该路径约束可解,则说明该路径是可达的;反之则说明该路径不可达,结束对该路径的分析。
 
这里举一个经典的例子,来说明符号执行的具体过程 :
1 int twice(int v){
2     return 2*v;
3 }
4
5 void testme(int x, int y){
6     z = twice(y);
7     if (z == x){
8         if (x > y+10)
9             ERROR;
10     }
11 }
12
13 int main(){
14     x = sym_input();
15     y = sym_input();
16     testme(x, y);
17     return 0;
18 }
这段代码中的testme()有三条执行路径。 符号执行的目的,就是在给定的时间预算内,生成一组输入,并通过这些输入尽可能多的探索执行路径
  • 执行路径(execution path):一个true和false的序列seq={p0,p1...,pn}。其中,如果是一个条件语句,那么pi=true则表示条件语句的取值为:true,否则取false;
  • 执行树(execution tree):一个程序的所有执行路径则可表征成一颗执行树。
下图是样例代码的执行树:

符号执行通过维护 符号状态 路径约束 ,以便在运行过程中传递信息
  • 符号状态(symbolic state):符号执行维护一个 符号状态 σ,将变量映射到符号表达式;
  • 符号路径约束(symbolic path constraint)符号路径约束PC,它是符号表达式上无量词的一阶公式;
  • 在执行开始时,将符号状态σ初始化为一个空映射,将符号路径约束PC初始化为true;
  • 在符号执行过程中,符号状态σ 和 符号路径约束PC都会更新;
  • 在沿着程序执行路径的符号执行结束时, 使用约束求解器对符号路径约束PC进行求解,以生成具体的输入值。如果程序在这些具体的输入值上执行,它将采用与符号执行完全相同的路径并以相同的方式终止。
  
对于样例代码,具体过程如下
  • 初始化:初始化符号状态σ为空,符号路径约束PC为true;
  • 每个赋值v=e处,符号执行都通过将v映射到 σ(e)来更新σ ,该映射是通过对当前符号状态求值,而获得的符号表达式。 例如:
        a) main()函数的前两行(第14-15行)的符号执行导致σ= {x -> x0,y -> y0},其中x0,y0是两个初始不受约束的符号值;
        b)  在执行第6行之后,σ = {x -> 0,y -> y0,z -> 2y0}。
  • 对于每个条件语句:if(e) then S1 else S2。
        a) 在第7行之后,分别创建了两个符号执行实例,分别具有路径约束x0 = 2y0和x0 ≠ 2y0;
        b)在第8行之后,分别创建两个具有路径约束的符号执行实例(x0 = 2y0)∧(x0 > y0 + 10)和(x0 = 2y0)∧(x0 ≤ y0 + 10);
        c)“then”分支: PC被更新为PC ∧ σ(e);
        d)“else”分支: 生成一个新的PC', PC'被初始化为:PC∧¬ σ(e);   ∧¬表示false
        e)如果分支的状态σ的PC可满足,则符号执行沿着分支继续,否则路径终止。
           例如:
  1. 如果一个符号执行实例碰到了exit或error时,当前符号执行实例就会被终止,并利用一个现成的约束求解器来生成一个可满足当前路径约束的赋值。 例如: 三条路径按照约束求解后,分别得到我们期望的三组输入:{x=0, y=1},{x=2, y=1}和{x=30, y=15}。
  2. 若代码中包含循环或递归结构,且它们的终止条件是符号化的,则可能导致有无穷多条路径。在实践过程中,需要对路径搜索设置一个限制,例如timeout,限制路径数量,循环迭代次数或探测深度。
经典的符号执行有一个关键的 缺点 ,若符合执行路径的符号路径约束无法使用约束求解器进行有效的求解,则无法生成输入。

三、现代符号执行技术

经典的符号执行,过度依赖符号执行的约束求解能力,这就限制了传统符号执行的能力发挥。
如果能加入具体值进行分析,将大大简化分析过程,降低分析的难度和提升效率;但分析过程中,仍不可避免的还是需要将各种条件表达式,进行符号化抽象后变成约束条件参与执行。将程序语句转换为符号约束的精度,对符号执行所达到的覆盖率以及约束求解的可伸缩性会产生重大影响。
所以如何做好混合具体(Concrete)执行和符号(Symbolic)执行的能力的平衡,就成为现代符号执行的关键点。

混合执行测试(Concolic testing)和执行生成测试(Execution-Generated Testing (EGT))这两种现代符号执行的代表都是基于这个思想发展而来的。

3.1、混合执行测试

下面以混合执行测试(Concolic testing)为例说明下现代符号执行的主要过程。
与经典的符号执行不同,由于混合执行在整个执行过程中,需要维护程序的具体状态,因此其输入需要初始具体值。 
混合执行测试从一个给定的输入或随机输入开始执行程序,沿着执行的条件语句在输入上收集符号约束,然后使用约束求解推断先前输入的变化,以便引导程序接下来的执行该走向哪一个执行路径。重复此过程,直到探索了所有执行路径,或者满足用户定义的覆盖标准、时间设置到期为止。
  
混合执行测试会同时维护两个状态:
  • 具体状态:映射所有有具体值的变量;
  • 符号状态:仅映射没有具体值的变量。
对于样例代码,执行过程如下
  • 混合执行会生成一些随机的输入值,比如{x=22, y=7},然后符号化和具体化地一起来执行程序。
  • 依据{x=22, y=7},程序在第7行,这个具体的执行会走向else分支;符号执行沿着执行路径会生成x ≠ 2y0的路径约束;
  • 混合测试将路径约束中的连接(x ≠ 2y0)取反,生成一个新的约束x0=2y0,并求解得到测试输入{x=2, y=1}。这个新的输入会强制让程序执行then路径。
  • 依据{x=2, y=1},程序在第8行执行else分支。混合测试会沿着具体执行来进行符号执行,并生成路径约束(x0 = 2y0)∧(x0 ≤ y0 + 10);
  • 混合测试将路径约束中的连接((x0 ≤ y0 + 10))取反,会生成一个新约束(x0 = 2y0)∧(x0 > y0 + 10)的测试,求解得到测试输入{x=30, y=15}。在这个输入下程序走到ERROR语句。
  • 混合测试报告所有被探索的执行路径,并终止测试输入的生成。
比较混合执行测试和传统的符号执行,不难发现由于具体值的引入,简化了约束求解的难度。

3.2、执行生成测试

执行生成测试也融合了具体执行与符号执行的软件测试技术,由斯坦福大学 Cristian等提出并在 EXE中实现。
 
执行生成测试与混合测试最大的不同点在于将符号执行与具体执行混合的方式不同。执行生成测试的混合是在一次程序执行中,对符号变量无关的代码段使用具体执行,而对符号变量有关的代码段进行符号执行,使用符号执行引导测试过程,为每条路径生成一个测试用例,并进行一次执行。
 
与混合测试相比,执行生成测试的优势是能更加系统且高效地得到所有的路径信息以及对应的测试用例,避免重复性搜索过程;其缺点是内存空间耗费较大,一种解决思路是可以使用多线程的方式代替分支存储,实现对多个分支的同时搜索和测试用例的生成。
 
执行生成测试的核心思想是通过程序代码自动地生成潜在的高度复杂的测试用例,在用符号输入执行程序的过程中,在分支处将false路径的状态信息记录下来,判断为true的分支继续执行。记录其约束信息,通过求解这些约束信息得到该路径的测试用例,该分析过程就是执行生成测试。
 
对于样例代码,执行过程如下
  • 设置初始状态,将x、y设置为符号变量。
  • 在第一个条件分支即第7行if(x=2y)处分叉执行,将true分支上的约束条件置为x==2y,false分支上的约束条件为 x!=2y。选择其中的true分支继续执行,false分支以栈的形式克隆存储。
  • 在第二个条件分支即第8行if(x>y+10)处分叉执行,将true分支上的约束设置为x==2y && x>y+10,false分支上的约束为x==2y && x<=y+10。选择其中的true分支继续执行,false分支以栈的形式克隆存储。
  • true分支直接报错ERROR(第9行),求解符号约束x==2y && x>y+10,得到第一个测试用例。
  • true分支执行结束,从克隆存储中依次取出分支记录,第一个取出的约束条件为x==2y && x<=y+10,求解得到第二个测试用例。
  • 依次从克隆备份中取出分支记录,并求解得到测试用例,直至分支记录栈中为空,得到针对所有路径的测试用例。

3.3、选择性符号执行

受路径爆炸与约束求解问题的制约,符号执行不适用于程序规模较大或逻辑复杂的情况。选择性符号执行可以解决这类问题。
选择性符号执行也是具体执行与符号执行混合的一种分析技术,依据特定的分析,决定符号执行与具体执行的切换使用。在选择性符号执行中,用户可以制定一个完整系统中的任意感兴趣额的部分进行符号执行分析,可以是应用程序、库文件、系统内核和设备驱动程序。选择性符号执行在符号执行和具体执行间无缝地来回转换,并透明地转换符号状态和具体状态。选择性符号执行极大地提高了符号执行在实际应用中对大型软件分析测试的可用性,且不再需要对这些环境进行模拟建模。
选择性符号执行的核心是符号执行和具体执行的交互处理,即在具体执行转入符号执行区域及符号执行转入具体执行时的处理。

四、挑战与解决方案

符号执行仍存在路径爆炸(代码规模、复杂度)、约束求解(计算算法)、内存模型(工具设计)等挑战。

4.1、路径爆炸(Path Explosion)

因为在符号执行的分析过程中,在每个分支节点,符号执行都会衍生出两个符号执行实例,程序分支路径的数量与程序分支的数量呈指数级增长关系。
以下图的代码为例,代码中共有3个分支判断语句和1个循环语句,3个分支判断语句,根据x,y,z值的不同,将会产生8条不同的程序路径;而对于循环来说,当a取最大值时,该循环将会产生231条路径。
 
符号执行在过程处理中默认已经过滤了以下两种路径:
  • 不依赖于符号输入的路径
  • 对于当前的路径约束,不可解的路径。
但是,尽管符号执行已经做了这些过滤,路径爆炸依旧是符号执行的最大挑战。路径爆炸不是符号执行特有的挑战,是整个程序分析都需要考虑的最大的问题。
   
解决路径爆炸的方案,可以从以下两个角度来考虑:
  • 减少路径总数(优先的考虑最有希望的路径, 路径合并,剪枝);
  • 相似的路径不再分析(函数摘要,缓存);
依据这个思路业界提出了两种解决方案:
  • 启发式(Heuristic): 大多数启发式方法侧重于实现较高的语句和分支覆盖率。
        a)特别有效的方法是使用静态控制流图(CFG)来指导探索,向最接近的路径或优先选择先前执行次数最少的语句;
        b)在每个可行的符号分支,随机选择要探索的一侧; 或者将符号检验与随机检验进行交错进行;
        c)采用先验知识,探索以往容易出错的函数;目前也有研究通过AI的方式得到这些推荐的分析路径;
  • 利用完善的程序分析技术(Sound program analysis techniques): 这种方法主要是使用程序分析和软件验证中的各种思想,以合理的方式降低路径探索的复杂性。
        a)静态地合并路径,然后再求解;
        b)通过函数摘要,缓存或重用已经计算过的信息用于后续的计算中;
        c)通过剪枝,去除无关的变量对路径的求解的影响;

4.2、约束求解(Constraint Solving)

  • 减少不相关的约束(Irrelevant constraint elimination) 符号执行中的绝大多数查询是为了确定某个分支的可行性,一种有效的优化方法是从路径条件中删除与当前分支的结果无关的那些约束。
  • 增量求解(incremental solving) 符号执行期间生成的约束集的一个重要特征是,它们根据来自程序源代码的一组固定的静态分支来表示。因此,许多路径具有相似的约束集,因此可以采用相似的解决方案。
        a)通过重用先前类似查询的结果,来提高约束求解的速度;
        b)通过约束集的超集,减少无解的情况出现; 我们目前常用的符号执行的工具KLEE,在设计中都采用了着两种方式。

4.3、内存建模(Memory Modeling)

在符号执行中我们将变量映射到了一个内存模型,来表示这个变量的类型、值或者值域。这个对变量的抽象模式对程序语句转化成符号约束的精度和对符号执行的覆盖率有着很大的影响。太过精确,往往容易陷入复杂的计算,而不能得到具体的解;太过笼统,又会造成漏报。所以精度和可扩展性之间是需要权衡的。
目前这个权衡的主要参考依据是:
  1. 具体分析问题的性质;
  2. 采用的约束求解器的限制;

四、符号执行工具

语言
符号执行器
链接
备注信息
LLVM
KLEE
https://klee.github.io/
Cadar et al., 2006
LLVM
Cloud9
http://cloud9.epfl.ch/
Bucur et al., 2011,基于KLEE的并行符号执行
LLVM
Kite
http://www.cs.ubc.ca/labs/isd/Projects/Kite/
do Val, 2014, 基于KLEE
Java
JPF-Symbc
https://github.com/SymbolicPathFinder/jpf-symbc
2008, 用于测试NASA的软件
Java
jayhorn
http://jayhorn.github.io/jayhorn/
基于soot,支持Z3, 2016
Java
JDart
https://github.com/psycopaths/jdart
Luckow et al., 2016
Python
PyExZ3
https://github.com/thomasjball/PyExZ3
Ball and Daniel,2015
JavaScript
Jalangi
https://github.com/Samsung/jalangi2
Sen et al., 2013
Binaries
angr
http://angr.io/
Shoshitaishvili et al., 2015, python框架
目前符号执行,在实际的应用中还主要用于与fuzz结合使用,用于缩小fuzz的取值范围。由于符号执行的主要瓶颈--约束求解的性能和局限性,并未在静态分析的商业工具中,大规模的使用。但我们有理由相信,在不久的将来随着并行技术、计算性能的提升、以及求解器的优化,符号执行能够在静态分析中发挥越来越大的作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/113284.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ Qt 学习(一):Qt 入门

Qt6 安装教程 0. 基础知识 0.1 qmake 和 cmake 对比 qmake&#xff1a;qt 独有的代码构建工具cmake&#xff1a;C 通用的代码构建工具&#xff0c;绝大部分 C 开源项目都使用 cmake 管理代码qt 项目&#xff0c;没有特殊要求&#xff0c;使用 qmake 即可 0.2 Qt 3 个窗口类的…

MATLAB野外观测站生态气象数据处理分析实践应用

1.基于MATLAB语言 2.以实践案例为主&#xff0c;提供所有代码 3.原理与操作结合 4.布置作业&#xff0c;答疑与拓展 示意图&#xff1a; 以野外观测站高频时序生态气象数据为例&#xff0c;基于MATLAB开展上机操作&#xff1a; 1.不同生态气象要素文件的数据读写与批处理实现 …

微信小程序自定义弹窗阻止滑动冒泡catchtouchmove之后弹窗内部内容无法滑动

自定义弹窗 如图所示&#xff1a; 自定义弹窗内部有带滚动条的盒子区域 问题&#xff1a; 在盒子上滑动&#xff0c;页面如果超出一屏的话&#xff0c;也会跟着一起上下滚动 解决方案&#xff1a;给自定义弹窗 添加 catchtouchmove 事件&#xff0c;阻止冒泡即可 网上不少…

Linux 安装 Redis7.x

Linux 安装 Redis7.x 下载redis7检查linux版本检查是否有 gcc什么是 gcc查看 gcc 是否有安装 安装 redis7查看默认安装目录启动服务连接服务服务关闭Redis的删除卸载Redis数据类型 下载redis7 下载地址&#xff1a;https://download.redis.io/releases/ 检查linux版本 [root…

Oracle JDK 和OpenJDK两者有什么异同点

Oracle JDK 和 OpenJDK 是两种不同版本的 Java Development Kit&#xff08;Java 开发工具包&#xff09;&#xff0c;它们都提供了用于开发 Java 程序的一系列工具和库。以下是它们之间的一些主要异同点&#xff1a; 相同点&#xff1a; 功能&#xff1a;在大多数情况下&…

【C++入门 三】学习C++缺省参数 | 函数重载 | 引用

C入门 三 1.缺省参数1.1 缺省参数概念1.2 缺省参数分类 2. 函数重载2.1 函数重载概念2.2 C支持函数重载的原理--名字修饰(name Mangling) 3.引用3.1引用概念3.2引用特性3.3 常引用3.4 使用场景1. 做参数2. 做返回值 3.5 传值、传引用效率比较3.6引用和指针的区别 4.引用和指针的…

2023最新ChatGPT商业运营系统源码+支持GPT4/支持ai绘画+支持Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

Linux进程基础

文章目录 1.进程概念2.进程描述3.进程操作&#xff08;一&#xff09;3.1.进程查看3.2.进程获取3.3.进程终止3.4.进程创建 4.进程状态4.1.进程状态理论4.1.1.粗略理解4.1.2.深入理解 4.2.进程状态实现4.2.1.运行状态和浅度/深度睡眠4.2.2.暂停状态和停止并跟踪状态4.2.3.终止状…

19.4 Boost Asio 远程命令执行

命令执行机制的实现与原生套接字通信一致&#xff0c;仅仅只是在调用时采用了Boost通用接口&#xff0c;在服务端中我们通过封装实现一个run_command函数&#xff0c;该函数用于发送一个字符串命令&#xff0c;并循环等待接收客户端返回的字符串&#xff0c;当接收到结束标志go…

工作中的小tips:如何快速提取图片或者pdf上的文字,进行编辑?

工作中经常会碰到需要的材料是图片或者不能拷贝的pdf之类的情况&#xff0c;那么有没有办法快速从上面提取文字呢&#xff1f; 最近发现一个很好用的网站&#xff0c;百度翻译。首先说明一下&#xff0c;接下来的方法比较适合短一点的文字&#xff0c;像是大篇幅的那种不太适合…

Linux学习第30天:Linux 自带的 LED 灯驱动实验:驱动开发思维方式的转变势在必行

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 学习嵌入式Linux驱动开发整整30天了。今天简单做一个小结。因为之前的主要工作是做ARM的裸机开发&#xff0c;所以接触Linux以后感觉很多东西都变了。不仅仅包括…

如何选择安全又可靠的文件数据同步软件?

数据实时同步价值体现在它能够确保数据在多个设备或系统之间实时更新和保持一致。这种技术可以应用于许多领域&#xff0c;如电子商务、社交媒体、金融服务等。在这些领域中&#xff0c;数据实时同步可以带来很多好处&#xff0c;如提高工作效率、减少数据不一致、提高用户体验…

【Verilog 教程】7.3 Verilog 串行 FIR 滤波器设计

串行 FIR 滤波器设计 设计说明 设计参数不变&#xff0c;与并行 FIR 滤波器参数一致。即&#xff0c;输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号&#xff0c;经过 FIR 滤波器后&#xff0c;高频信号 7.5MHz 被滤除&#xff0c;只保留 250KMHz 的信号。 输入频率&#x…

uniapp 省市区三级联动选择器

还有半个小时下班&#xff0c;总想着发点光亮照耀他人。IT技术这东西&#xff0c;尤其是UI方面的东西&#xff0c;于用户体验至关重要&#xff0c;想想最近使用uni-data-picker的丑陋页面&#xff0c;自己重构了这个功能&#xff0c;新加实现&#xff0c;效果图如下&#xff0c…

使用 Curl 和 DomCrawler 下载抖音视频链接并存储到指定文件夹

项目需求 假设我们需要从抖音平台上下载一些特定的视频&#xff0c;以便进行分析、编辑或其他用途。为了实现这个目标&#xff0c;我们需要编写一个爬虫程序来获取抖音视频的链接&#xff0c;并将其保存到本地文件夹中。 目标分析 在开始编写爬虫之前&#xff0c;我们需要了…

【Linux】配置JDKTomcat开发环境及MySQL安装和后端项目部署

目录 一、jdk安装配置 1. 传入资源 2. 解压 3. 配置 二、Tomcat安装 1. 解压开启 2. 开放端口 三、MySQL安装 1. 解压安装 2. 登入配置 四、后端部署 1. 数据库 2. 导入.war包 3. 修改端口 4.开启访问 一、jdk安装配置 打开虚拟机 Centos 登入账号&#xff…

MySQL -- 内置函数

MySQL – 内置函数 文章目录 MySQL -- 内置函数一、日期函数1.current_date()获取年月日2.current_time()获取时分秒3.current_timestamp() / now()获得时间戳4.date_add()在日期的基础上加日期5.date_sub()在日期的基础上减去日期6. datediff()计算两个日期之间相差多少天7.案…

inquirer.js——交互式命令行用户界面

一、什么是inquirer.js 1、inquirer.js是一个开源的交互式命令行用户界面&#xff08;CLI&#xff09;库&#xff0c;可以让你轻松地与用户进行交互&#xff0c;获取用户输入并做出相应的处理。它的主要功能是提供了一系列常用的命令行交互界面组件&#xff0c;例如input、con…

【Redis】高并发分布式结构服务器

文章目录 服务端高并发分布式结构名词基本概念评价指标1.单机架构缺点 2.应用数据分离架构应用服务集群架构读写分离/主从分离架构引入缓存-冷热分离架构分库分表&#xff08;垂直分库&#xff09;业务拆分⸺微服务 总结 服务端高并发分布式结构 名词基本概念 应⽤&#xff0…

Docker的安装、基础命令与项目部署

文章目录 前言一、docker安装与MySQL部署1.Linux环境下docker的安装&#xff08;1&#xff09;基于CentOS7&#xff08;2&#xff09;基于Ubuntu 二、docker基础1.常见命令&#xff08;1&#xff09;快速创建一个mysql容器&#xff08;MySQL得一键安装&#xff09;。&#xff0…
最新文章