作者:Sanchuan Chen, Zhiqiang Lin, Yinqian Zhang. (The Ohio State University)
出处:USENIX 2021
背景
污点分析的性能损耗很大,其中一个原因是现有的污点分析是基于动态二进制插桩的。比如Pin这个动态二进制插桩工具它需要一个虚拟机然后在程序运行的时候把分析逻辑进行插桩,要进行反汇编、编译、重汇编这个过程。对程序进行动态二进制插桩开销很大,相比之下静态二进制插桩通过二进制重写技术把分析逻辑重写到程序里面,没有那么多的上下文切换,性能损耗相对较小。
Insight
作者想用静态二进制重写技术进行一个选择性的污点分析。静态二进制重写技术最近取得了很多进展,作者主要需要解决哪些指令需要做污点分析这个问题。作者在每个程序点对寄存器和存储单元的可能值进行推断,确定一个特定的内存地址或者寄存器是否含有污点。
如下图所示,作者使用VSA对符号内存地址和寄存器的值计算近似值,识别那些不会涉及污点内存和寄存器的指令,也就是在
I
u
I_u
Iu里的指令集。然后对不在
I
u
I_u
Iu里的指令打污点。相当于作者选择不去找I或者
I
t
I_t
It,因为CFG质量差、指针分析等等原因会导致VSA会有漏打补丁的情况。
相关知识补充
VSA(Value-set Analysis)
VSA是一种静态程序分析技术,它对于程序的各个程序点的数据可能的取值进行一个近似分析,然后用一个值集来表示内存地址的值和数值的集合。
VSA用一个抽象内存模型把地址空间分成多个不连续的内存区域。每个内存区域由以下四部分组成:
- 全局区域,存储未初始化和初始化的变量。
- 栈区域,每个函数有一个栈区域记录运行的时候的活动记录。
- 堆区域,每个malloc类型的函数申请的堆地址。
- 抽象地址,一个类似于变量的实体,从一个静态的已知地址到下一个静态已知的地址。
VSA里的一个抽象地址表示为一个内存区域和偏移对,可表示为
{
i
∣
r
g
n
i
→
{
o
1
i
,
o
2
i
,
.
.
.
,
o
n
i
}
}
\{i|rgn_i \rightarrow \{o_1^i,o_2^i,...,o_n^i\}\}
{i∣rgni→{o1i,o2i,...,oni}}。如果最多就一个栈一个堆区域,可以进一步简化为
(
g
l
o
b
a
l
→
O
g
,
s
t
a
c
k
→
O
s
,
h
e
a
p
→
O
h
)
(global \rightarrow O^g, stack \rightarrow O^s, heap \rightarrow O^h )
(global→Og,stack→Os,heap→Oh)。对于每一个内存区域它的内存偏移值表示为
S
[
l
,
u
]
S[l,u]
S[l,u],s是步长,l和u是下界和上界。
整个分析过程是在CFG上进行的,每个节点是一条指令,每条边代表一个控制流transfer,同时进行地址值和数值的跟踪。
方法设计和实现
- CFG 重建:给定一个二进制程序,首先反汇编然后构建它的CFG。对于库函数调用,作者会保存调用的目标然后用函数摘要来决定是否要进一步地对库函数进行插桩。如果遇到间接跳转,用执行向后切片,并使用VSA和类型信息来解析目标。
- 对于间接调用。使用TYPEARMOR和 τ C F I \tau CFI τCFI来恢复调用和被调用函数的参数的类型、数量等信息,根据这个信息来匹配调用和被调用的函数(这样做会导致over-approximation)。
- 对于间接跳转,首先用VSA解析间接跳转目标,如果能解析成功那就连接起来。如果不行,就看发起间接跳转的函数是否使用了全局变量等额外的数据引用。如果没有就把所有可能的基本块都作为可能的间接跳转的目标位置。如果有就把所有的函数入口地址作为跳转目标,就还是over-approximation。
- VSA:用VSA来识别那些没有涉及污点分析的指令。
- 污点指令识别:用VSA识别出 I u I_u Iu,剩下的指令就被认为是和污点相关的。
- 二进制重写:用静态二进制重写把污点分析逻辑插入到二进制程序中。