符号执行
符号执行是什么
符号执行 (Symbolic Execution)是一种程序分析技术,它可以通过分析程序来得到让特定代码区域执行的输入。顾名思义,使用符号执行分析一个程序时,该程序会使用符号值作为输入,而非一般执行程序时使用的具体值。在达到目标代码时,分析器可以得到相应的路径约束,然后通过约束求解器来得到可以触发目标代码的具体值。
符号执行的优势
生成具体测试输入的能力是符号执行的主要优势之一:
从测试生成的角度来看,它允许创建高覆盖率的测试套件,而从bug查找的角度来看,它为开发人员提供了触发bug的具体输入,该输入可用于确认和调试打开的错误。
符号执行过程
在任何时候,符号执行引擎都维持一个状态(stmt,σ,π)。
stmt是下一个要评估的语句。目前,我们假设stmt可以是赋值,条件分支或跳转。
σ是一个符号存储,它将程序变量与具体值或符号值αi上的表达式相关联。
π表示路径约束,即,是表示由于在执行中为了达到stmt而采取的分支而对符号αi的一组假设的公式。在分析开始时,π=真。
下面是一个简单的符号执行的样例。
在沿着程序的执行路径的符号执行结 ...
linux 内核安全增强(一)— stack canary
一、背景知识 —— aarch64的函数栈
1.栈生长方向与push/pop操作
栈是一种运算受限的线性表, 入栈的一端为栈顶,另一端则为栈底, 其生长方向和操作顺序理论上没有限定.
在aarch64平台上,栈是向低地址方向增长的(STACK_GROWS_DOWNWARD)
栈的PUSH/POP通常要先移动SP:
PUSH操作为PRE_DEC,即 PUSH操作为 sp = sp -4; store;
POP操作为 POST_INC,即POP操作为 read; sp=sp+4;
2.返回地址的存储
x86平台是call指令时自动push函数返回地址到栈;
ret指令自动pop函数返回地址出栈;
这两步操作都是在callee执行前硬件自动完成的.
而在arm/aarch64平台发生函数调用时(blx),硬件负责将函数的返回地址设置到通用寄存器LR(/X30)中, callee中的代码负责将LR保存到栈中(需保存的寄存器参考AAPCS标准)
3.函数栈分配
在不考虑动态分配的情况下, 函数中使用的栈大小在编译阶段 ...
代码分析属性图 CPG
代码分析工具层出不穷,编译器本身也内置了大量的静态检查,但分析的数据源较为单一。而本文要介绍的,是集众之所长的代码分析属性图 CPG,在漏洞分析上很有帮助。
1、定义
代码属性图(code property graph,简称 CPG) 是一种数据结构,用来通过 DSL(domain-specific language) 查询语句来挖掘代码漏洞。
它的主要思想如下:
CPG 将多个程序表示(program representations)整合成一个
CPG 数据被存储在图数据库中
通过 DSL 在图数据库中遍历和查询 CPG 数据
2、用处
CPG 整合了 AST(abstract syntax trees)、CFG(control flow graphs)、PDG(program dependence graphs) 到一种数据结构当中。
这种综合的数据表示,使得我们在图遍历当中,可以优雅地组织漏洞扫描的模版。
可以用来分析缓冲区溢出、整型溢出、格式字符串漏洞、内存泄漏等。
2.1、局限性
1、纯静态分析,缺乏对运行时信息的组织(比如数据争用)
2、解决 ...
程序切片
软件漏洞主要由指针、数组、表达式运算、敏感 API 函数所在位置引入, 并称其为漏洞关注点。 如常见的数组越界、整数溢出、空指针、API 函数错误使用等类型漏洞, 均由以上 4 类漏洞关注点所致. 在程序代码中, 与漏洞关注点存在数据依赖或者控制依赖关系的语句集合构成一个可能存在漏洞的程序切片;反之, 其他语句被视为会干扰模型训练的漏洞无关语句. 不同于 Li 等人[19]构 造的文本切片, 本文提取程序依赖图的子图作为切片, 即选取上述 4 类漏洞关注点作为程序切片的基准点后, 保留与其存在数据及控制依赖关系的节点和边, 以生成程序依赖图子图. 具体来说, 生成代码切片可以分为 3 个步骤.
(1)漏洞关注点选取,通过遍历程序依赖图节点,选取符合4类漏洞关注点的代码元素,并记录节点作为切片基点;
具体地,
通过在标识符声明节点中匹配“[”字符来确定数组元素;
通过在标识符声明节点中匹配“*”字符来确定指针元素;
通过正则表达式规则来匹配表达式运算节点;
通过Li 等人[19]提供的敏感 API 列表进行敏感 API 节点匹配;
如图 2 中程序依赖图提取部分所示, 1 号 ...
【程序分析】数据依赖、控制依赖、程序依赖图PDG、系统依赖图SDG-CSDN博客
可达性
变量v的定义:对变量v的赋值语句成为变量的定义;
变量v的使用:在某个表达式中引用变量v的值;
当变量v被再次赋值时,上一次赋值对变量v的定义d就被kill掉了;
如果定义d到点p之间存在一条路径,且在路径中定义d没有被kill掉,则称d可以达到p
如下图所示,d可以通过path2到达u但是不能通过path1到达u,因为k这条语句kill掉了定义d。而因为d到u之间存在着没有被kill的路径path2,所以d可以到达u。
X = . 叫做精确定义,*p = . 叫做模糊定义,因为p可能指向X,一般考虑可达性只考虑精确定义对路径的kill。
数据依赖
两个句子存在数据依赖:一条语句中一个变量的定义,可以到达另一条语句中对该变量的使用。
在编译领域有不同类型的数据依赖,如果我们说s2依赖于s1,可以是:
s1 写内存 s2 读 (RAW)
s1 读内存 s2 写 (WAR)
s1 写内存 s2 写 (WAW)
s1 读内存 s2 读 (RAR)
在软件工程领域,主要关注RAW依赖,在源码或IR的 ...
软件漏洞分类
输入验证错误(Input Validation Error, IVE)
边界条件错误(Boundary condition error,BCE)
边界条件错误是指未能对用户输入数据的合法性进行有效检查导致输入到程序中的值无效。例如输入的数字大于或小于某个阈值,或者文本输入中的字符长度过长等,都会发生边界条件错误。
缓冲区溢出(Buffer overflow, BOF)
缓冲区溢出是指当数据量超过内存缓冲区的存储容量时,超出的数据会覆盖相邻的存储区域,造成程序正常堆栈的破坏,从而影响其他程序的正常运行。
访问验证错误(Access Validation Error, AVE)
这类漏洞的形成原因是由于程序的访问验证部分存在某些逻辑错误,使攻击者可以绕过访问控制进入系统。例如,一个对象的调用或其他操作在其访问域之外、一个对象接收了另一个未授权对象的输入、系统没有正确地进行授权操作等都会导致访问校验错误。
异常条件错误处理(Exceptional Condition Error Handling, ECHE)
这类漏洞是由于未能响应意外数据或条件而产 ...
代码混淆定义:
原代码 P 通过某种变换变成代码 P’,若 P 和 P’运行结果与过程行为保持一致,该种变换就称之为混淆变换。
具体来说,当混淆转换满足以下两种情况时,这种混淆变化称之为合法的转换:
(1)如果源程序 P 无法停止运行或报错结束运行,则变换后的程序 P’可以结束运行也可以继续运行。
(2)否则,目标程序 P’也结束运行并且输出与源程序相同的结果。
两个程序之间操作并不一定完全相同,且不一定有相同的效率。
实际上,混淆工具预先设定若干混淆规则,并使用其它更为复杂的代码取代源代码中符合条件的代码语句,虽然源代码语义并未改变但混淆后的程序运行过程中空间复杂度往往更高,执行时间也更长,甚至有可能改变系统环境等。
图 2.1 展示了混淆编译的整体流程,
首先混淆工具会对输入的源代码进行代码预处理得到程序控制流图 CFG、抽象语法树 AST 等信息,
然后对数据流、控制流等进行分析,并根据输入的混淆参数选择对应的混淆算法处理源代码,
最后输出混淆编译后的程序。
尽管混淆策略多种多样,但通常按 Collberg 提出的方法将其大致分为四类[16]:
布局混淆
数据流混淆
...
Basic terms and concepts
Vulnerability
Vulnerability
VUL,Vulnerability的缩写,泛指漏洞。漏洞是指计算机系统中存在可能被攻击者利用的弱点、缺陷或安全漏洞。这些漏洞允许未经授权的访问,如窃取敏感数据,或允许攻击者在目标计算机系统上执行任意操作,如安装恶意软件。此类漏洞可能表现在不同方面,包括软件代码、硬件组件、配置或设计。
CWE
CWE是社区开发的漏洞列表。它提供了一种标准化和结构化的方法来识别和分类这些漏洞,并为每个漏洞分配一个唯一的标识符。例如,CWE-119提到了臭名昭著的“缓冲区溢出”。遵循不同级别的概念抽象,CWE将漏洞组织在树状层次结构中,其中低级CWE ID与高级CWE ID相关联。例如,表示“越界写入”的CWE-787和表示“越界读取”的CWE-125都是属于CWE-119的较低级别类型。
POC
POC,Proof of Concept,中文意思是“概念证明”。这个短语会在漏洞报告中使用,漏洞报告中的POC则是一段说明或者一个攻击的样例,使得读者能够确认这个漏洞是真实存在的。
EXP
EXP,Ex ...
已经开发了各种方法来检测漏洞(Cui et al.,2022),包括静态、动态、一致性分析和模糊方法。正如我们将在相关工作部分进一步深入研究的那样,TrVD属于静态检测系列中基于学习的范式。在这种范式中,漏洞检测任务被公式化为一个分类问题。具体来说,在训练阶段,分类器 通过代码表示构建、特征提取和模型训练,从一组带有基本事实标签的训练样本中学习。在检测阶段,当出现一段可能看不见的源代码时, 执行代码表示构造和特征提取的相同过程。经过训练的分类器预测漏洞的存在,或者进一步精确定位特定的漏洞类型。
可用性
其他被广泛采用的代码表示包括CFG、PDG和各种基于图形的变体。这些表示更明确地描述了代码元素之间的控制或数据依赖关系,然而,当面对不可执行或不完整的代码片段时,很难精确推导出这些依赖关系。因此,它们可能并不总是适用于漏洞检测。按照约定,AST可以很容易地为任何代码片段构建,例如文件、函数或单个语句。
效率
与需要相对复杂和耗时的控制或依赖性分析的代码表示(例如CFG、PDG和代码小工具)相比,从代码构建AST要简单得多,重量轻,从而有助于提高整个检测方法的效率。
语义综合性
那些人工 ...