Soot学习-Overview
记录一些关于Soot的最基础的知识。
Soot IRs
Baf: 一种基于栈的,以Bytecode形式呈现的中间表达
Jimple: Java的简单(Simple,不包含嵌套关系,且只有15种语句),带类型,无栈信息的,基于三位址码(Three Address Code)的中间表达,可放在控制流图中。每个三位址码都可被分解为一个四元组 \((operate, exp1, exp2, result)\) 由于其包含三个变量,故被称为三地址码
Shimple: SSA (Static Single Assignment)版本的Jimple。在SSA中,变量的每次赋值均对应一个新的变量(版本),而每次使用的变量均为该变量到达该程序点时的版本。例如,对于
对于非SSA形式的编译器,需要通过数据流分析(到达-定义分析)来确定\(x\)选取哪个\(y\)值。SSA将其转化为1
2
3y := 1 // 多余的赋值
y := 2
x := y便省去了数据流分析的过程1
2
3y1 := 1
y2 := 2
x1 := y2 // x1来自于y2Grimp: 类似Jimple,不过表达式是聚合(aggregated)的
Dava: 用来反编译(Decompile)Java的结构化表达
Soot Structure
graph TD s["Scene(singleton)"] Root--> |"Scene.v()"|s --> |"getSootClass()"|SootClass SootClass --> |"getField()"|SootField SootField --> |"getSignature()"|SootField SootClass --> |"getMethod()"|SootMethod SootMethod --> |"getSignature()"|SootMethod SootMethod --> |"getActiveBody()"|JimpleBody
在<IR>Body
(如JimpleBody)中,代码语句(Statement)是用接口Unit
表示的。该接口对每种IR均有对应的实现。Unit
提供的API可用于向前或向后展开逐语句的分析(或插桩)。如
1 | public JMethod(SootMethod rawMethod) { |
Soot Phases
下图展示了Soot中不同pack(处理阶段)之间的工作方式。
1 | graph LR |
1 | graph TD |
jb(Jimple Body Creation)
首先,Soot对每个方法体(Method Body)应用jb
pack。诸如System.currentTimeMillis()
等原生方法没有body。jb
pack是固定的,与Jimple的创建有关,其无法被修改。
Whole-Program
接下来,Soot应用四个pack:
cg,即调用图(Call Graph)
wjtp,whole-jimple transformation pack
wjop,whole-jimple optimization pack
wjap,whole-jimple annotation pack
上述四个pack仅在指定-w(whole
program)时才会加入到Soot中,且均可以被修改。特别地,每步后均可插入自定义的额外分析(插桩)步骤。例如,下面的代码在wjtp后追加一个额外的SceneTransformers
:
1 | public static void main(String[] args) { |
Jimple Packs
类似地,对于每个方法体,Soot还提供了 + jtp,Jimple transformation
pack:
默认启用且为空。一般可将过程间分析逻辑(定义在一个继承自BodyTransformer
的自定义类中)置于此处。
jop,Jimple optimization pack: 对Jimple进行优化,默认关闭。可通过参数
-o
或-p jop enabled
开启。jap,Jimple annotation pack: 对Jimple进行属性注解。下面的代码片段中,插入的逻辑将为方法中的每条语句打印标签:
1 | public static void main(String[] args) { |
bb pack用于将(优化后和注解后的)Jimple体转换为Baf体,而tag pack用于聚合重复标签。
参考
- http://www.iro.umontreal.ca/~dufour/cours/ift6315/docs/soot-tutorial.pdf
- http://www.bodden.de/2008/11/26/soot-packs/