Static analysis指在不對program進行運行的情況下,對其行爲進行分析。搞compiler的人用之於優化,搞安全的用於做taint analysis。對於Java有兩大開源的static analysis 框架,Soot和WALA,前者由McGill大學維護,後者是IBM。最新的Soot開始支持對Andoird 代碼分析,包括static taint analysis。
從這篇開始,我們將由淺入深的對Soot進行了解,使用,甚至擴展。在這裏默認讀者對static analysis理論(lattice, 不動點, may & must等),Java source code和bytecode語法有基本瞭解。將主要依據Soot 官網提供的資料作爲依據,特別是那本『生存手冊』(點擊打開鏈接)。
好了,現在我們開始。
Soot包括四種IR(中間碼-表示形式),分別代表了四種對Java Sourcode或者bytecode的不同程度的抽象。
Baf - 基於棧的bytecode
java -cp soot-trunk.jar soot.Main -f J Foo
讀入sootOutput文件夾中的Foo.Jimple。其所對應的Java 源碼爲,
public class Foo {
public static void main(String[] args) { Foo f = new Foo();
int a = 7;
int b = 14;
int x = (f.bar(21) + a) * b; }
public int bar(int n) { return n + 42; } }
Jimple爲public static void main(java.lang.String[]) { java.lang.String[] r0;
Foo $r1, r2;
int i0, i1, i2, $i3, $i4;
r0 := @parameter0: java.lang.String[]; $r1 = new Foo;
specialinvoke $r1.<Foo: void <init>()>(); r2 = $r1;
i0 = 7;
i1 = 14;
// InvokeStmt
$i3 = virtualinvoke r2.<Foo: int bar()>(21);
$i4 = $i3 + i0;
i2 = $i4 * i1;
return;
}
public int bar() { Foo r0;
int i0, $i1;
r0 := @this: Foo; // IdentityStmt
i0 := @parameter0: int; // IdentityStmt $i1 = i0 + 21; // AssignStmt
return \$i1; // ReturnStmt
}
可以看出Jimple是一種Java sourcecode和 bytecode的混合體。對於局部變量的聲明和賦值statement用的是Java,而控制流和函數調用採用的是bytecode。和反編譯Dalvik bytecode所得的smali類似,Jimple在每個method body前會把所有用到的局部變量和stack位置做出聲明(即Var -> Loc, 把變量映射到棧中的地址並在body中用地址替代變量名)。帶"$"的局部變量表示是stack中的位置而不是原java
code中真正聲明過的局部變量,表示在java中不出現而bytecode中少不了的隱含變量如this, 儲存中間結果的變量等。反之不帶的即與原java code中局部變量相對應。public static void main(java.lang.String[]) { java.lang.String[] r0;
Foo r2;
int i0, i1, i2;
r0 := @parameter0: java.lang.String[]; r2 = new Foo();
i0 = 7;
i1 = 14;
i2 = (r2.<Foo: int bar(int)>(21) + i0) * i1;
return; }
可以看到樹形表達式沒有被linerazation, 對象的初始化濃縮到new中,一些臨時局部變量被省去了。Grimp更適用於做available expr(表達expr簡潔)和反編譯(適合人讀)。
java -cp soot-2.5.0.jar soot.Main -cp . -pp A B
輸入的class有兩種 1. application class 即要被分析和翻譯的(在Soot裏叫transformation)class 2. Library class. 爲application class所引用,有助於分析但不會直接被分析的class。關於具體的命令就不再這裏敷述了。
Soot的執行過程被分成了好幾大步,每一大步被稱爲一個pack。第一步是把輸入的bytecode (.class)或者.java 文件或者.jimple 翻譯成Jimple code。再把生成的Jimple作爲剩下packs的輸入。"函數中分析(intra-procedure analysis)"執行流程示意如下:
首字母s, j, b, g分別代表四種不同的IR。b代表body 創建,o 表示優化,a表標註(生成屬性),t表示用戶定義的transformation, p即packs,其中jtp和stp用戶可能更有興趣,因爲任何用戶定義的transformation (如從分析中得出對信息的標籤)可以被插入到這倆packs中因而作爲Soot執行過程的一部分。
"函數間分析(inter-procedure analysis)"執行流程如下
運行函數間分析需要指明'-w',表示Whole-program mode (全程序模式)。在此模式下Soot包含3個額外的packs:cg(調用圖生成),wjtp (whole jtb)和wjap (whole jap)。用-W還會引入wjop做全程序優化。與intra-procedure analysis不同在於這裏得出的結果對每個application class都有效。
用
java soot.Main -pl
java soot.Main -ph PACK
OPT:VAl 來對pack進行設置,下面語句表示關閉所有用戶定義的函數內tansformation。
java soot.Main -p jtp enabled:false MyClass
Soot 所支持的靜態分析
Null pointer analysis (空指針分析):位於 jap pack中,包含兩部分, 空指針檢查和空指針着色。前者用於找到可能會觸發NullPointerException異常的指令,後者再對這些指令做出特殊顏色的標註(在Eclipse中)。command如下:
java soot.Main -xml-attributes -f J -p jap.npcolorer on MyClass
數組越界分析
位於jap pack下的jap.abc。使用命令如下
java soot.Main -xml-attributes -f J -p jap.abc on -p jap.abcadd-color-tags:true MyClass
Liveliss Analysis
命令如下 :
java soot.Main -xml-attributes -f J -p jap.lvtagger on MyClass
對Soot的擴展
在我們設計和實現了一個自己的分析後,要把它與Soot帶的分析相結合,這時就需要對Soot的Main class做修改。此處的擴展指的是在在保留其它Soot特性的同時,在Soot分析中加入我們自己設計的(中間)步驟。對於函數內分析我們加到jtp步驟中,函數間分析則加到wjtp。
public class MySootMainExtension {
public static void main(String[] args) { // Inject the analysis tagger into Soot PackManager.v().getPack("jtp").add(new
Transform("jpt.myanalysistagger", MyAnalysisTagger.instance()));
// Invoke soot.Main with arguments given
Main.main(args); }
}
對