Introduction:使用Soot作为命令行工具

原文地址:点击打开链接

获得Soot

   你可以从Soot官方下载页面下载最近发布的Soot版本,有许多不同的版本可供你选择,但通常你只需下载像下面这样形式的版本:

  •    soot-x.y.z.jar
   在这里,我们使用Soot 2.5.0 ,下载好之后我们先试一下:
$ java -cp soot-2.5.0.jar soot.Main

Soot version 2.5.0
Copyright (C) 1997-2010 Raja Vallee-Rai and others.
All rights reserved.
...
    Bleeding-edge version(前沿版本) (nightly build)

    你们中间那些勇敢的人可以下载 Technische University Darmstadt大学的Secure Software Engineering Group提供的nightly build版本的Soot。通常最新的nightly build版本的Soot是最稳定的,因为在发布之前我们对其代码进行了测试。但这有时候并不全对。从 The Soot webpage可以下载nightly build版本的Soot。

    Soot的命令行

   好了,现在我们应该怎么做呢?先看一下命令行选项:
$ java -cp soot-2.5.0.jar soot.Main --help

General Options:
  -coffi                       Use the good old Coffi front end for parsing 
                               Java bytecode (instead of using ASM). 
  -h -help                     Display help and exit 
  -pl -phase-list              Print list of available phases 
  -ph PHASE -phase-help PHASE  Print help for specified PHASE 
  -version                     Display version information and exit 
  -v -verbose                  Verbose mode 
 ...
     Soot的全部命令行选项从 这里可以找到,我们建议Soot的初学者看看这个文档。

    处理单一文件

 Soot通常可以处理许多类文件,这些类可以是下面这三种格式:
    1. Java源代码  即 Java文件
    2. Java字节码  即  类文件(class文件)
    3. Jimple 代码  即 jimple文件

   如果你还不大清楚,Jimple是Soot里最基本的中间表示(primary intermediate representation),它是一种三地址代码(three-address code),基本上是Java的简化版本,只需要约15种不同的表述(statements)。你可以使用Soot将 .java或 .class文件转换成 .jimple文件或者反过来。你甚至可以使用Soot从 .java文件生成 .jimple文件,然后使用普通的文本编辑器修改 .jimple文件,接着将修改后的 .jimple文件转换成 .class文件,手工优化你的程序。有点跑题了。。。
   使用Soot处理类文件A和B最基本的方法是将它们添加到命令行,使类A和B成为 application classes(译者注:application classes是Soot里描述的class的一种,总共三种:arguments class、application class、library class):
    
$ ls *.java
A.java  B.java
$ java -cp soot-2.5.0.jar soot.Main A B
Soot started on Thu Aug 21 08:26:41 GMT-05:00 2014
Exception in thread "main" java.lang.RuntimeException: couldn't find class: A (is your soot-class-path set properly?)</code>
 
 
运行之后,出现问题了,对了,忘了最重要的一点:Soot有它自己的类路径

Soot 的classpath

Soot有自己的类路径,并且只从这个类路径下的jar包或目录读取文件。默认情况下,这个路径是空的,因此在上面这个例子中Soot没有找到类A和类B,尽管它们是存在的。所以,我们添加当前目录 " .  "
$ java -cp soot-2.5.0.jar soot.Main -cp . A B
Soot started on Thu Aug 21 08:32:13 GMT-05:00 2014
Exception in thread "main" java.lang.RuntimeException: couldn't find class: java.lang.Object (is your soot-class-path set properly?)
    又出现问题了,很明显Soot现在能够找到类A和B了(至少它不在报错没找到类A和B),但报错的是缺失 java.lang.Object。
  为什么Soot如此关心 java.lang.Object呢?为了对你的程序做些有意义的事情,Soot需要类型信息,尤其需要对局部变量重新构造类型。为了达到这个目的,Soot需要知道你想要处理的类的完整类型继承关系。
     针对这个异常,有三种解决方法:
    1. 将 rt.jar 添加到你的classpath
    2. 添加 -pp 选项,此时假设你的 CLASSPATH 变量已经包含  rt.jar 或者 JAVA_HOME 已经被正确设置
    3.  使用 -allow-phantom-refs 选项(不推荐)

   第一种方法,将JDK的 rt.jar 添加到Soot的calsspath (不是JVM的classpath)。这个jar包包含 java.lang.Object
$ java -cp soot-2.5.0.jar soot.Main -cp .:/home/user/ebodde/bin/sun-jdk1.6.0_05/jre/lib/rt.jar A B
Soot started on Thu Aug 21 08:42:09 GMT-05:00 2014
Transforming B...
Transforming A...
Writing to sootOutput/B.class
Writing to sootOutput/A.class
Soot finished on Thu Aug 21 08:42:12 GMT-05:00 2014
Soot has run for 0 min. 3 sec.
  看起来成功了,Soot成功的处理了这两个 .java (译者注:即命令行里的A和B),并把 .class 结果文件放在 sootOutput文件夹里。注意到通常,Soot将会处理你在命令行里指定的所有类,同时还会处理这些命令行指定的类所引用到的类。
  要注意,一个普遍的问题可能会像下面一样:
$ java -cp soot-2.5.0.jar soot.Main -cp .:~/bin/sun-jdk1.6.0_05/jre/lib/rt.jar A B
Soot started on Thu Aug 21 08:43:43 GMT-05:00 2008
Exception in thread "main" java.lang.RuntimeException: couldn't find class: java.lang.Object (is your soot-class-path set properly?)
发生了什么事?你使用 “~” 因为这个符号指向你的home目录,但问题是通常shell会将 "~" 进行翻译(即指向home目录),但在这里不行。Soot把字符 “~” 作为它的命令行的选项故而它不能对其解释,将它翻译成指向你的home目录。 所以在 Soot的classpath里最好使用绝对或相对路径

   第二个方法是使用   -pp
$ java -cp soot-2.5.0.jar soot.Main -cp . -pp A B  Soot started on Thu Aug 21 08:47:42 GMT-05:00 2008
Transforming A...
Transforming B...
Writing to sootOutput/A.class
Writing to sootOutput/B.class
Soot finished on Thu Aug 21 08:47:46 GMT-05:00 2008
Soot has run for 0 min. 3 sec.
这比每次要添加classpath要简单多了,这也正是我们为什么要添加这个选项。 -pp 代表前置路径(prepend path)。这意味着Soot会自动添加下面这些东西到它的classpath(有序添加)
   1.  你当前的 CLASSPATH 变量的内容
   2.  ${JAVA_HOME}/lib/rt.jar
   3.  如果你是在整个程序范围内模式(whole-program mode)运行(即 -w 选项被启用),那么Soot会自动添加 ${JAVA_HOME}/lib/jce.jar

  第三个让Soot运行的方法是使用 -allow-phantom-refs 选项:
$ java -cp soot-2.5.0.jar soot.Main -allow-phantom-refs -cp . A B
Soot started on Thu Aug 21 08:52:35 GMT-05:00 2008
Warning: java.lang.Short is a phantom class!
Warning: java.lang.Class is a phantom class!
Warning: java.lang.Character is a phantom class!
...
Transforming B...
Transforming A...
Writing to sootOutput/B.class
Writing to sootOutput/A.class
Soot finished on Thu Aug 21 08:52:37 GMT-05:00 2008
Soot has run for 0 min. 1 sec.
这能干什么? 通常这个选项告诉Soot “我不想给你你没有的类,但是请给我一个最好的结果(在没有这些类的情况下)”,这种情况下Soot给每个它无法解析的类创建一个幻影类(phantom class),并告诉你。注意到这个方法用途有限,在许多情况下不会得到你想要的结果。只有在你知道自己在做什么的情况下使用这个选项。

  对于Windows用户要注意一点:Soot会正确对待驱动器号,但在Windows下的路径分隔符必须是一个反斜杠,而不是正斜杠。

处理整个目录

  你可以使用 Soot里的 -process-dir 选项处理  整个目录或jar文件

  
$ java -cp soot-2.5.0.jar soot.Main -cp . -pp -process-dir .
Soot started on Thu Aug 21 09:01:12 GMT-05:00 2014
Transforming A...
Transforming B...
Writing to sootOutput/A.class
Writing to sootOutput/B.class
Soot finished on Thu Aug 21 09:01:15 GMT-05:00 2014
Soot has run for 0 min. 3 sec.
处理jar文件的时候,使用同样的选项,但此时需要提供jar文件的路径而不是jar文件所在的目录。很不错不是吗?不过要注意:如果你对同一个文件夹再次执行(连续执行)相同的命令,你会遇到下面的问题:
$ java -cp soot-2.5.0.jar soot.Main -cp . -pp -process-dir .
Soot started on Thu Aug 21 09:02:29 GMT-05:00 2008
Exception in thread "main" java.lang.RuntimeException: Error: class A read in from a classfile in which sootOutput.A was expected.
  发生了什么? 就如我前面提到的,Soot把生成的 .class 文件放入sootOutput文件夹,这个文件夹位于 “.” 当前目录。因此Soot现在处理的是先前生成的文件,同时报错:名为“A”的类已经存在于 ./sootOutput/A ,这个类实际上是 sootOutput.A ,即在 sootOutput包里。因此, 当使用 -process-dir 选项时同时使用 -d 选项来重定向 soot 的输出文件夹:
$ java -cp soot-2.5.0.jar soot.Main -cp . -pp -process-dir . -d /tmp/sootout
Soot started on Thu Aug 21 09:06:29 GMT-05:00 2008
Transforming A...
Transforming B...
Writing to /tmp/sootout/A.class
Writing to /tmp/sootout/B.class
Soot finished on Thu Aug 21 09:06:32 GMT-05:00 2008
Soot has run for 0 min. 2 sec.
重定向的文件夹为 /tmp/sootout,这不是当前目录的子目录。

  处理特定文件(.class / .java/ ,jimple)

  假设你有一个目录,里面既包含 A.java 又包含 A.class,你像之前那样调用soot,这时Soot会从 A.class 文件读取A的定义,这可能不是你一直想要的。 -src-prec 选项告诉soot它应该优先处理哪种输入的类型。总共有四个选项:
  1. c 或者 class(默认):优先处理class文件
  2.   only-class :只处理class文件
  3.   J 或者 jimple :优先处理jimple文件
  4.   java :优先处理java文件
因此,在上面这个例子中,如果指定 -src-prec  java 那么会装载 A.java。

  应用程序类与库类(Application classes vs. library class)

  Soot实际处理的类称为 application class,这与 library classes恰好相反,soot不处理library class,只把他们用来类型解析。Application classes通常显示的指定在命令行里或者那些通过   -process-dir 命令指定的目录下的类。
  当你使用 -app 选项时,Soot也会处理由application class所引用的所有的类,然而,它不会处理JDK中的任何类,即那些位于  java.* 和  com.sun.* 包下的类,如果你希望包含这些类,那么可以使用特殊的  -i 选项,比如  -i java 。更多关于命令行选项的操作请看 Soot 命令行选项

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值