美文网首页
soot与插装

soot与插装

作者: 呼噜毛_ | 来源:发表于2019-04-06 11:48 被阅读0次

Static analysis指在不对program进行运行的情况下,对其行为进行分析。对于Java有两大开源的static analysis 框架,Soot和WALA。Soot支持对Andoird 代码分析。

soot是java优化框架,提供4种中间代码来分析和转换字节码。

Baf:精简的字节码表示,操作简单 Jimple:适用于优化的3-address中间表示 Shimple:Jimple的SSA变体 Grimple:适用于反编译和代码检查的Jimple汇总版本。

使用:

1.命令行使用 (1) 处理单个文件 soot可以处理三种类型的文件:java源代码(。java文件),java字节码(.class文件),Jimple源代码(.jimple文件)

Jimple是soot中最主要的中间表示,三地址代码基本上是一种Java的简化版本,只需要大约15种不同的指令

java -jar soot.jar A B

其中,A B叫做应用类。如果只运行该命令,可能报错,因为soot有自己的classpath,它只会从该路径的jar文件或目录加载文件。所有要用-cp指出路径。 但运行之后还可能会报错,因为soot需要知道类型信息,它需要为局部变量重构类型,那么它要知道你 要处理的文件的完整类层次。以下方法可以解决。 a.添加相关的jar文件到classpath,比如说JDK的rt.jar。

b.使用-pp选项。-pp表示prepend path,它表示Soot自动将以下内容添加到类路径中(按此顺序):当前环境的CLASSPATH变量值;{JAVA_HOME}/lib/rt.jar;如果使用-w(whole-program mode),添加{JAVA_HOME}/lib/jce.jar。

(2)处理整个文件夹

java -jar soot.jar -process-dir 文件名

如果要处理jar文件,也是使用-process-dir 选项,后跟jar文件路径。同时可以使用-d选项,对soot的输出重定向。 (3)处理确定类型的文件 假设你有个文件夹下放了A.java和A.class文件,并且你之前运行过soot,soot会自行加载A.class中A的定义。可能这并不是你想要的,那么可以使用-src-prec选项指定你想要处理的文件类型。-src-prec有4个值可供使用:

c或class(默认)only-class:只使用class文件作为soot的源。J或jimplejava比如: -src-prec java 只加载A.java

2.编写java程序使用 soot的java api文档:https://soot-build.cs.uni-paderborn.de/public/origin/develop/soot/soot-develop/jdoc/ 如果我们想要编写一个java程序来访问一个Class中的所有Field和Methods,那么用java语言编写使用soot API,应该怎么做呢? 首先要指定classpath,然后像在命令行里添加选项一样对选项进行设置(比如对-process-dir设置)。其次将你想要的应用类加载到soot环境中Scene。然后对soot环境中的每个class进行遍历,再对每个class中的每个method方法访问。 假如我要对Employee.java文件中的字段和方法进行访问。

Employee.java:

import java.util.Date;import java.util.GregorianCalendar;import java.util.Objects;

public class Employee {    private String name;      private double salary;      private Date hireDay;

publicEmployee(Stringn,doubles,intyear,intmonth,intday)

  {

name=n;

salary=s;

GregorianCalendarcalendar=newGregorianCalendar(year,month-1,day);

hireDay=calendar.getTime();

  }

publicStringgetName()

  {

returnname;

  }

publicdoublegetSalary()

  {

returnsalary;

  }

publicDategetHireDay()

  {

returnhireDay;

  }

publicvoidraiseSalary(doublebyPercent)

  {

doubleraise=salary*byPercent/100;

salary+=raise;

  }

publicbooleanequals(ObjectotherObject)

  {

// a quick test to see if the objects are identical

if(this==otherObject)returntrue;

// must return false if the explicit parameter is null

if(otherObject==null)returnfalse;

// if the classes don't match, they can't be equal

if(getClass()!=otherObject.getClass())returnfalse;

// now we know otherObject is a non-null Employee

Employeeother=(Employee)otherObject;

// test whether the fields have identical values

returnObjects.equals(name,other.name)&&salary==other.salary&&Objects.equals(hireDay,other.hireDay);

  }

publicinthashCode()

  {

returnObjects.hash(name,salary,hireDay);

  }

publicStringtoString()

  {

returngetClass().getName()+"[name="+name+",salary="+salary+",hireDay="+hireDay

+"]";

  }

helloSoot.java:

import java.io.File;import java.util.LinkedHashSet;import java.util.Set;import java.util.*;

import soot.Scene;import soot.SootClass;import soot.SootMethod;import soot.SourceLocator;import soot.options.Options;

public class helloSoot {    private String apiPath = "/home/myw/name";

publicvoidgetClassUnderDir() {

apiClasses=newLinkedHashSet<String>();

for(StringclzName:SourceLocator.v().getClassesUnder(apiPath)) {

System.out.printf("api class: %s\n",clzName);

//加载要处理的类设置为应用类,并加载到soot环境Scene中  

Scene.v().loadClass(clzName,SootClass.BODIES).setApplicationClass();

   }

}

publicvoidgetMethods() {

for(SootClassclz:Scene.v().getApplicationClasses()) {

System.out.println(clz.getName());

if(clz.getMethods().size()==0){System.out.println("do not have methods!!!!!");}

else{

System.out.println("method num:"+clz.getMethods().size());

for(SootMethodme:clz.getMethods()) {

System.out.println(me.toString());

if(me.hasActiveBody()){

System.out.println(me.getActiveBody().toString());

               }

           }

       }

   }

}

privatestaticvoidsetOptions() {

soot.options.Options.v().set_keep_line_number(true);

soot.options.Options.v().set_whole_program(true);

// LWG

soot.options.Options.v().setPhaseOption("jb","use-original-names:true");

soot.options.Options.v().setPhaseOption("cg","verbose:false");

soot.options.Options.v().setPhaseOption("cg","trim-clinit:true");

//soot.options.Options.v().setPhaseOption("jb.tr", "ignore-wrong-staticness:true");

soot.options.Options.v().set_src_prec(Options.src_prec_java);

soot.options.Options.v().set_prepend_classpath(true);

// don't optimize the program

soot.options.Options.v().setPhaseOption("wjop","enabled:false");

// allow for the absence of some classes

//soot.options.Options.v().set_allow_phantom_refs(true);

}

privatestaticvoidsetSootClassPath() {

StringBuffercp=newStringBuffer();

cp.append(".");

cp.append(File.pathSeparator+"/home/myw/name");

cp.append(File.pathSeparator+"/usr/lib/jvm/jdk1.7.0_79/jre/lib/rt.jar"+File.pathSeparator+"/usr/lib/jvm/jdk1.7.0_79/jre/lib/jce.jar");

System.setProperty("soot.class.path",cp.toString());

}

publicstaticvoidmain(String[]args) {

setSootClassPath();//设置classpath

setOptions();//设置soot的选项

helloSoots=newhelloSoot();

s.getClassUnderDir();

s.getMethods();

}

Baf - 基于栈的bytecode

在bytecode中对不同保留类型,如int和float,的同一操作(如add),有不同的指令。这是因为在计算机中整形和浮点型的表达方式是不一样的,在底层实现时无法让两个操作符分属于这两种不同类型,也就是需要不同的指令对应不同的数据类型的操作。我们做分析时不用在意它到底调用的什么类型的指令,不对int还是float做细致区分,只要知道它是个数且知道是对这数的什么样的操作就行了。Baf因此用于在bytecode层面上的分析。

Jimple - typed, 3-addresses, statement based。

Jimple是Soot的核心,是四种IR中最重要的。Soot能直接创建Jimple码,也可由Java sourcecode或者bytecode转化翻译而来。bytecode会被翻译成untyped Jimple,再通过type inference 方法对局部变量加上类型。翻译的重要一步是对表达式作线性化使得每个statement只能最多refernce 3个局部变量或者常量(没懂。。)。相对于bytecode的200多种指令,Jimple只有15条,分别对应着核心指令的 NopStmt, IdentityStmt, AssignStmt;函数内控制流指令的IfStmt, GotoStt, TableSwitchStmt和LookUpSwitchStmt,函数间控制流的InvoeStmt, ReturnStmt, ReturnVoidStmt, 监视器指令EnterMonitorStmt和ExitMonitorStmt,最后处理异常ThrowStmt和退出的RetStmt。

用:

java -cp soot-trunk.jar soot.Main -f J Foo

读入sootOutput文件夹中的Foo.Jimple。其所对应的Java 源码为,

相关文章

网友评论

      本文标题:soot与插装

      本文链接:https://www.haomeiwen.com/subject/oofliqtx.html