马豫宛的技术小窝 Java and Python Coder

soot简介,安装及使用

2018-05-08


前言

本文主要介绍Soot工具的概念及使用。soot官方文档: 官方文档

soot介绍

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

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

1.soot提供的输入输出格式

输入格式:

  • java(bytecode and source code up to Java 7)
  • android字节码
  • Jimple中间表示
  • Jasmin,低级中间表示
  • soot提供的分析功能

输出格式:

  • java 字节码
  • android字节码
  • Jimple
  • Jasmin

2.soot提供的分析功能

  • 调用图构造
  • 指针分析
  • Def/use chains
  • 模板驱动的程序内数据流分析
  • 模板驱动的程序间数据流分析,与heros结合
  • 结合FlowDroid的污染分析

安装

下载soot.jar

使用

soot的使用方法一般有两种:一 1.在命令行使用soot.

2.在java程序中使用soot。

命令行使用

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需要知道类型信息,它需要为局部变量重构类型,那么它要知道你要处理的文件的完整类层次。有三种方法可以解决。

1.添加相关的jar文件到classpath,比如说JDK的rt.jar。

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

  1. 使用-allow-phantom-refs。如果soot无解析类型,它会创建一个phantom类。这种方法非常有限,在很多情况下不会得到您需要的结果。

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或jimple
  • java

比如: -src-prec java 只加载A.java

4.应用类和库类

soot处理的类就叫做应用类,但库类恰恰相反,soot并不处理,只是用来类型分析。

5.指定输出类型

使用-f选项,指定你想要soot为你生成的文件类型,比如.jimple文件,.class文件,甚至.java文件。

6.阶段选项

soot支持不同细粒度的选项,允许您直接从命令行调整所有满足您的要求的分析和优化。这些命令选项的一般格式是-p PHASE OPT:VAL。

所有阶段选项的完整文档 例如,我们想要在soot执行过程中保留局部变量名。那么就在命令行里添加选项-p jb ues-original-names:true

编写java程序使用

soot的java api文档

如果我们想要编写一个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;

   public Employee(String n, double s, int year, int month, int day)
   {
      name = n;
      salary = s;
      GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
      hireDay = calendar.getTime();
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public Date getHireDay()
   {
      return hireDay;
   }

   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }

   public boolean equals(Object otherObject )
   {
      // a quick test to see if the objects are identical
      if (this == otherObject) return true;

      // must return false if the explicit parameter is null
      if (otherObject == null) return false;

      // if the classes don't match, they can't be equal
      if (getClass() != otherObject.getClass()) return false;

      // now we know otherObject is a non-null Employee
      Employee other = (Employee) otherObject;

      // test whether the fields have identical values
      return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
   }

   public int hashCode()
   {
      return Objects.hash(name, salary, hireDay); 
   }

   public String toString()
   {
      return getClass().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 = "";//应用类的路径
	private Set apiClasses;
	
	public void getClassUnderDir() {
	    apiClasses = new LinkedHashSet<String>();
	    for (String clzName: SourceLocator.v().getClassesUnder(apiPath)) {
	         System.out.printf("api class: %s\n", clzName);
	         //加载要处理的类设置为应用类,并加载到soot环境Scene中   
	         Scene.v().loadClass(clzName, SootClass.BODIES).setApplicationClass();
	    }
	}
	
	public void getMethods() {
		for (SootClass clz : 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(SootMethod me : clz.getMethods()) {
					System.out.println(me.toString());
					if (me.hasActiveBody()){
						System.out.println(me.getActiveBody().toString());
					}
				}
			}
			
		}
		
	}
		
	private static void setOptions() {
		 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);
		 
	}
	
	private static void setSootClassPath() {
		StringBuffer cp = new StringBuffer();
		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());
	}
	
	public static void main(String[] args) {
		setSootClassPath();//设置classpath
		setOptions();//设置soot的选项
		
		helloSoot s = new helloSoot();
		s.getClassUnderDir();
		s.getMethods();
	}
}


下一篇 常用linux命令

Comments

Content