Skip to content

General Usage of SootUp

This page walks you through the core data structures, as well as shows how to get started with SootUp.

The core datastructures

Before you get started with the SootUp library, it helps to learn about the following core data structures:

  • Project: defines the outlines of an analysis. SootUp users should first create a Project instance. It is the starting point for all operations. You can define multiple instances of Project at the same time and there are no information shared between them. All caches are always at the project level.

  • Language: represents the programming language of the analyzed code.

  • AnalysisInputLocation: points to the target code to be analyzed.

Soot Equivalent

It corresponds to the cp option, which specifies the classpath for Soot to find classes to be analyzed.

  • View: presents the code/classes under analysis.

Soot Equivalent

It corresponds to the Scene class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.

  • Scope: defines the scope of the View. By default, the View is created with all code found on the AnalysisInputLocation specified for the Project instance.

  • SootClass: represents a class loaded into the View.

  • SootMethod: represents a method of a class.

  • SootField: represents a field of a class.

  • Body: represents a method body in Jimpe.

  • StmtGraph: represents the control flow graph of a method body in Jimple statements.

Creating a Project

You can use bytecode analysis typically when you do not have access to the source code of the target program. Following example shows how to create project for analyzing Java bytecode.

Create a project to analyze Java bytecode

1
2
3
4
5
6
7
AnalysisInputLocation<JavaSootClass> inputLocation = 
        new JavaClassPathAnalysisInputLocation("path2Binary");

JavaLanguage language = new JavaLanguage(8);

Project project = 
        JavaProject.builder(language).addInputLocation(inputLocation).build();

If you have access to the source code, it is also possible to create a project for analyzing source code. Following example shows how to create project for analyzing Java source code.

Experimental

The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead.

Create a project to analyze Java source code

1
2
3
4
5
6
7
AnalysisInputLocation<JavaSootClass> inputLocation = 
        new JavaSourcePathAnalysisInputLocation("path2Source");

JavaLanguage language = new JavaLanguage(8);

Project project = 
        JavaProject.builder(language).addInputLocation(inputLocation).build();

If you have a Jimple file, you can create a project for analyzing jimple code directly. Following example shows how to create project for analyzing jimple code.

Create a project to analyze jimple code

1
2
3
4
5
6
Path pathToJimple = Paths.get("path2Jimple");

AnalysisInputLocation<JavaSootClass> inputLocation = 
        new JimpleAnalysisInputLocation(pathToJimple);

Project project = new JimpleProject(inputLocation);

Creating a View

To create an analysis view, you can call the createView() method on the project object:

1
JavaView view = project.createView();

By default, whenever a class is retrieved, it will be permanently stored in a cache. If you do not want retrieved classes to be stored indefinetly, you can instead provide a different CacheProvider to the created view. To for example use an LRUCache instead, which stores at most 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call:

1
JavaView view = project.createView(new LRUCacheProvider(50));

Retrieving a Class

Each class is identified with a unique signature adhering to Java identifier rules, therefore you first need to specify the class signature (ClassType) as shown below.

Let's say the following is the target program that we want to analyze:

Target Program

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package example;

public class HelloWorld {

  public HelloWorld() {

  }

  public static void main(String[] args) {
    HelloWorld hw = new HelloWorld();
    hw.hello();
  }

  public void hello() {

  }

}

Then, we could define the ClassType of the HelloWorld class as follows:

Defining a ClassType

1
2
ClassType classType = 
        project.getIdentifierFactory().getClassType("example.HelloWorld");

Once we have a ClassType that identifies the HelloWorld class, we can use it to retrieve the corresponding SootClass object from the view as shown below:

Retrieving a SootClass

1
2
SootClass<JavaSootClassSource> sootClass =
        (SootClass<JavaSootClassSource>) view.getClass(classType).get();

Retrieving a Method

Like the classes, methods also have an identifier which we call MethodSignature. For instance, we can define the method signature for identifying the main method of the HelloWorld class as follows:

Defining a MethodSignature

1
2
3
4
5
6
7
8
MethodSignature methodSignature =
    project
        .getIdentifierFactory()
        .getMethodSignature(
            "main", // method name
            classType,
            "void", // return type
            Collections.singletonList("java.lang.String[]")); // args

Once we have a MethodSignature that identifies the main method of the HelloWorld class, we can use it to retrieve the corresponding SootMethod object from the view as shown below:

Retrieving a SootMethod from the View

1
2
3
4
5
Optional<SootMethod> opt = view.getMethod(methodSignature);

if(opt.isPresent()){
  SootMethod method = opt.get();
}

Alternatively, we can also retrieve a SootMethod from SootClass that contains it.

Retrieving a SootMethod from a SootClass

1
2
3
4
5
Optional<? extends SootMethod> opt = sootClass.getMethod(methodSignature.getSubSignature());

if(opt.isPresent()){
  SootMethod method = opt.get();
}

Retrieving the Control-Flow Graph of a Method

Each SootMethod contains a Control-Flow Graph (CFG) which is represented via the StmtGraph. This structure is usually used for program analysis. You can retrieve the CFG of a SootMethod as follows:

Retrieving the CFG of a SootMethod

1
sootMethod.getBody().getStmts();

Access or Download all of the code used above

BasicSetup.java

SootUp vs Soot

Below we show a comparison of the code so far with the same functionality in sootup.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
AnalysisInputLocation<JavaSootClass> inputLocation =
new JavaClassPathAnalysisInputLocation("path2Binary");

JavaLanguage language = new JavaLanguage(8);

Project project =
    JavaProject.builder(language)
            .addInputLocation(inputLocation).build();

ClassType classType = 
        project.getIdentifierFactory().getClassType("HelloWorld");

MethodSignature methodSignature =
    project
        .getIdentifierFactory()
        .getMethodSignature(
            "main", classType, "void",
            Collections.singletonList("java.lang.String[]"));

View view = project.createView();

SootClass<JavaSootClassSource> sootClass =
    (SootClass<JavaSootClassSource>) view.getClass(classType).get();

SootMethod sootMethod = 
        sootClass.getMethod(methodSignature.getSubSignature()).get();

sootMethod.getBody().getStmts();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
G.reset();
String userdir = System.getProperty("user.dir");
String sootCp = 
        userdir 
        + File.separator 
        + "target" 
        + File.separator 
        + "test-classes"
        + File.pathSeparator + "lib"+File.separator+"rt.jar";

Options.v().set_soot_classpath(sootCp);
Options.v().set_whole_program(true);
Options.v().setPhaseOption("cg.cha", "on");
Options.v().setPhaseOption("cg", "all-reachable:true");
Options.v().set_no_bodies_for_excluded(true);
Options.v().set_allow_phantom_refs(true);
Options.v().setPhaseOption("jb", "use-original-names:true");
Options.v().set_prepend_classpath(false);

Scene.v().addBasicClass("java.lang.StringBuilder");
SootClass c = 
    Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);
if (c != null) {
    c.setApplicationClass();
}
Scene.v().loadNecessaryClasses();

SootMethod method;
for (SootClass c : Scene.v().getApplicationClasses()) {
    if(c.getName().equals("example.HelloWorld")){
        for (SootMethod m : c.getMethods()) {
            if (!m.hasActiveBody()) {
                continue;
            }
            if (m.getName().equals("entryPoint")) {
                method = m;
                break;
            }
        }
    }
}

method.getActiveBody().getUnits();