当前位置: 首页 > 工具软件 > Soot > 使用案例 >

Soot入门(1): 安装与生成Jimple文件

夏立果
2023-12-01

Soot入门(1): 安装与生成Jimple文件

这学期选修了程序分析课,作业是基于soot进行一些java程序的静态分析,发现目前不管国内国外对于soot的教程都不太多,要么不太清晰要么太老,打算一边学习一遍记下笔记,方便未来入坑的铁子们少踩坑

0: JAVA配置

建议使用JDK1.8/1.7,版本过高的JDK似乎与soot存在不兼容问题
这一步很简单网上教程很多,主要在于设置$JAVA_HOME

Mac

我的是 MacBook Air (M1 2020): MacOS Monterey version 12.3.1
设置方法很简单

# 修改 .zshrc
sudo vim .zshrc

# 在 .zshrc文件中加上以下这行, 版本号可能不同,请自行修改
export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home"
# 也有可能是这个路径, 自行check
export JAVA_HOME="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home"

# 保存 source一下
source ~/.zshrc

然后测试下是否OK

java -version
# java version "1.8.0_321"
# Java(TM) SE Runtime Environment (build 1.8.0_321-b07)
# Java HotSpot(TM) 64-Bit Server VM (build 25.321-b07, mixed mode)

javac -version
# javac 1.8.0_321

echo $JAVA_HOME
# /Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home

Windows

我没有在win上进行配置,我的舍友在win11上按照这篇指南配置成功

Linux

应该和Mac类似, 路径可能有所不同自行确认

1: 安装soot

命令行使用

首先下载soot的jar包,选择v4.3.0/下的soot-4.3.0-jar-with-dependencies.jar, 其他文件按自己需要下载
为了方便我把下载下来的jar重命名为了soot.jar并放在了/Applications目录下, 并且像上面设置JAVA_HOME一样设置了SOOT_HOME="/Applications/soot.jar"
接着检验下是否安装成功

java -cp $SOOT_HOME soot.Main -h
# General Options:
# -coffi                        Use the good old Coffi front end for parsing
#                               Java bytecode (instead of using ASM).
# -jasmin-backend               Use the Jasmin back end for generating Java
#                               bytecode (instead of using ASM).
# -h, -help                     Display help and exit
# ...

IntelliJ IDEA使用

Maven方式导入

在项目下pom.xml文件中加入以下

<dependency>
    <groupId>org.soot-oss</groupId>
    <artifactId>soot</artifactId>
    <version>4.3.0</version>
    <scope>compile</scope>
</dependency>

直接导入 soot.jar

进入File -> Project Structure -> Modules,右侧Module SDK下面的+ -> 1 JARs or Directories,找到你下的soot.jar即可

2: 生成Jimple

Jimple是soot提供的四种IR(中间表示)之一,这里暂时不多做介绍

命令行方式生成

输入java -cp $SOOT_HOME soot.Main -cp . -pp -f J com.Foo:

  • -cp $SOOT_HOME: 指定soot class path
  • -cp .: 指定所要分析的项目的path
  • -pp: 指定soot去自动搜索java的path, 主要是rt.jarjce.jar, soot会去$JAVA_HOME下找,所以必须先设置好
  • -f J: 指定输出文件类型, J就是jimple
  • com.Foo: 你要分析的class的名字
    然后就得到.jimple文件啦

代码方式生成

会比较复杂一些,主要关注setupSoot(...)函数,其他的部分可以暂时不理解

package com;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.*;
import soot.options.Options;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;

public class DemoSoot {
    // 省略了一些无关紧要的...

    private final static Logger logger = LoggerFactory.getLogger("LVA Logger");

    // 主要关注这里
    public static void setupSoot(String className) {
        // Soot class path
        // "./"是我的项目根目录, "src/main/java"下存着当前com.DemoSoote, "src/test/java"下存着我要分析的类Foo
        String classesDirMain = "./src/main/java"; 
        String classesDirTest = "./src/test/java";
        String jceDir = System.getProperty("java.home") + "/lib/jce.jar";
        String jrtDir = System.getProperty("java.home") + "/lib/rt.jar";
        String path = jrtDir + File.pathSeparator + jceDir;
        path += File.pathSeparator + classesDirMain + File.pathSeparator + classesDirTest;

        // Init Scene
        Scene.v().setSootClassPath(path);

        // Add necessary opts
        Options.v().set_process_dir(Collections.singletonList(classesDirMain));
        Options.v().set_process_dir(Collections.singletonList(classesDirTest));

        // Set Main class
        SootClass mainClass = Scene.v().loadClassAndSupport(className);
        Scene.v().setMainClass(mainClass);
    }

    public static void main(String[] args) throws IOException {
        // 确保你要分析的文件能够编译,不然会寄掉
        String mainClassName = "Foo";
        try {
            setupSoot(mainClassName);
        } catch (CompilationDeathException e) {
            logger.error(e.toString());
            return;
        }

        // 启动soot, 相当于命令行使用中的"soot.Main"
        soot.Main.main(args);
        logger.info("---------soot.Main.main()---------");

        // 获取 Foo
        SootClass mainClass = Scene.v().getMainClass();
        logger.info(String.format("Loading Class: %s ...", mainClass.getName()));

        // 获取 Foo中的main函数
        String methodSignature = "void main(java.lang.String[])";
        SootMethod mainMethod = mainClass.getMethod(methodSignature);
        logger.info(String.format("Loading Method: %s ...", mainMethod));

        // 通过获取的main函数生成jimpleBody
        Body jimpleBody = mainMethod.retrieveActiveBody();
        logger.info("Retrieving method body ...");

        //将jimple写入文件中, 自行设定你的"rootPath"
        String rootPath = "/Users/caohch1/Projects/ProgramAnalysis/HW1/jimples/";
        String filePath = rootPath + mainClass.getName() + "-" + mainMethod.getName() + ".jimple";
        FileWriter fileWriter = new FileWriter(filePath);
        try (BufferedWriter out = new BufferedWriter(fileWriter)) {
            out.write(jimpleBody.toString());
        } finally {
            logger.info(String.format("Writing %s ...", filePath));
        }
    }
}

还有一种更简单的方式,前提是正确配置了JAVA_HOME路径

    String classesDirMain = "./src/main/java/";
    String classesDirTest = "./src/test/java/";
    String classesDirCurr = "./";
    void setupSoot() {
        Options.v().set_prepend_classpath(true);
        Options.v().set_process_dir(Collections.singletonList(classesDirMain));
        Options.v().set_process_dir(Collections.singletonList(classesDirTest)); // 注意,会覆盖掉上一行
        Options.v().set_process_dir(Collections.singletonList(classesDirCurr));
    }

3: Next & Refs

之后会继续分享soot学习中的笔记,主要可能包括对API的使用和理解,但是我也是刚刚接触soot,有问题之处可以一起讨论,我的邮件: chc2267408610@gmail.com

同时分享几个主要的soot的教程,虽然都有些难啃或者过时

 类似资料: