soot-oss / soot

Soot - A Java optimization framework
GNU Lesser General Public License v2.1
2.85k stars 706 forks source link

Options.v().set_exclude does not work when create callgraph #1245

Open newthis opened 4 years ago

newthis commented 4 years ago

I set a series to ignore when creating the call graph, however, the source node of the call graph still contains these packages.

Below is the detailed configuration:

G.v().resetSpark(); G.reset(); List processDirs = new ArrayList(); processDirs.add(“C:/test_soot/”); Options.v().set_process_dir(processDirs); Options.v().set_soot_classpath("C:/java/jdk1.8.0_131/jre/lib/jce.jar;C:/java/jdk1.8.0_131/jre/lib/rt.jar;"); Options.v().set_prepend_classpath(true); List excludedList = new ArrayList();

String ignored ="*sun.awt.;java.;javax.print;java.net.;sun.misc.;java.lang.;java.util.;java.awt.;javax.swing.;sun.awt.;sun.swing.;org.netbeans.;com.sun.;org.openide.;com.ibm.crypto.;com.ibm.security.*;org.apache.xerces.***";

String [] ssts = ignored.split(";"); for(String unit:ssts){ excludedList.add(unit); }

Options.v().set_exclude(excludedList); Options.v().set_allow_phantom_refs(true); Options.v().set_verbose(true); Options.v().set_whole_program(true);

Options.v().set_keep_line_number(true); Options.v().set_throw_analysis(Options.throw_analysis_unit); Options.v().set_debug(true); Options.v().set_debug_resolver(true); Options.v().set_output_format(Options.output_format_none); Options.v().setPhaseOption("cg.spark", "on,vta:true"); Options.v().set_no_bodies_for_excluded(true);

newthis commented 4 years ago
result
MrZbb commented 2 years ago

@newthis I have the same problem,set_exclude not work

NiceAsiv commented 5 months ago

i'm get into same situation cry

ForgottenField commented 4 months ago

@NiceAsiv It seems that the reason why the poster failed is that the wildcard is not added to the excluded package name. Please check whether you have added after the name of the package you want to exclude. For example, the string "sun.awt.*" instead of "sun.awt." should be passed to the API "Options.v().set_exclude()".

NiceAsiv commented 4 months ago

@ForgottenField Hi! Thank you for your response. Actually, I have already tried the approach you suggested. However, the call graph output of my test class still includes Java classes. Here's my test code and Soot configuration:

Test Code:

import lombok.Setter;

@Setter
public class ICFG {
    String inputFilePath;
    private static int graphType = 1;

    public void test1() {
        System.out.println("now in test1");
        test2();
    }

    public void test2() {
        System.out.println("now in test2");
        switch (graphType) {
            case 1:
                test3();
                break;
            case 2:
                System.out.println("graphType is 2");
                break;
            default:
                System.out.println("graphType is not 1 or 2");
        }
    }

    public void test3() {
        System.out.println("now in test3");
        if (graphType == 1) {
            System.out.println("graphType is 1");
        } else {
            System.out.println("graphType is not 1");
        }
    }
}

class Test4 {
    public void test4() {
        System.out.println("now in test4");
        ICFG icfg = new ICFG();
        icfg.test3();
        System.out.println("test4");
        icfg.test1();
    }
}

class Vulnerable {
    public void vulnerable() {
        System.out.println("--------------------");
        System.out.println("now in vulnerable");
        System.out.println("Start running the first test case");
        Test4 test4 = new Test4();
        test4.test4();
        System.out.println("End running the first test case");
        System.out.println("--------------------");
        System.out.println("Start running the second test case");
        ICFG icfg = new ICFG();
        icfg.test1();
        System.out.println("End running the second test case");
        System.out.println("--------------------");
    }

    public static void main(String[] args) {
        Vulnerable vulnerable = new Vulnerable();
        vulnerable.vulnerable();
    }
}

Soot Configuration:

import TestCaseDroid.utils.FileUtils;
import TestCaseDroid.utils.SootUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import soot.*;
import soot.jimple.toolkits.callgraph.CHATransformer;
import soot.options.Options;

import java.io.File;
import java.util.Collections;

@Setter
@Getter
@Slf4j
public class SootConfig {
    /**
     * javaPath collects all dependency libraries in the project.
     * jreDir is the path to rt.jar.
     * sootClassPath combines javaPath and jreDir to form the analysis environment.
     */
    private static String userDir = System.getProperty("user.dir");
    private static final String javaPath = userDir + File.separator + "target" + File.separator + "classes";
    private static final String jreDir = System.getProperty("java.home") + "/lib/rt.jar";

    private String callGraphAlgorithm = "CHA";

    public void setupSoot(String className, Boolean constructCallGraph) {
        G.reset();
        String sootClassPath = javaPath + File.pathSeparator + jreDir;
        Options.v().set_soot_classpath(sootClassPath);
        Options.v().set_whole_program(true);
        Options.v().set_allow_phantom_refs(true);
        excludeJDKLibrary();

        SootClass appClass = Scene.v().loadClassAndSupport(className);
        appClass.setApplicationClass();
        Scene.v().loadNecessaryClasses();

        commonSetup(constructCallGraph);
    }

    private void commonSetup(Boolean constructCallGraph) {
        Options.v().set_keep_line_number(true);
        Options.v().set_output_format(Options.output_format_jimple);
        Options.v().set_verbose(true);
        Options.v().setPhaseOption("jb", "use-original-names:true");

        if (constructCallGraph) {
            switch (this.callGraphAlgorithm) {
                case "CHA":
                    Options.v().setPhaseOption("cg.cha", "on");
                    CHATransformer.v().transform();
                    break;
                case "Spark":
                    Options.v().setPhaseOption("cg.spark", "enabled:true");
                    Options.v().setPhaseOption("cg.spark", "verbose:true");
                    Options.v().setPhaseOption("cg.spark", "on-fly-cg:true");
                    break;
                case "VTA":
                    Options.v().setPhaseOption("cg.spark", "on");
                    Options.v().setPhaseOption("cg.spark", "vta:true");
                    break;
                case "RTA":
                    Options.v().setPhaseOption("cg.spark", "on");
                    Options.v().setPhaseOption("cg.spark",

 "rta:true");
                    Options.v().setPhaseOption("cg.spark", "on-fly-cg:false");
                    break;
                default:
                    throw new RuntimeException("Unknown call graph algorithm: " + this.callGraphAlgorithm);
            }
        }
        PackManager.v().runPacks();
    }

    private static void excludeJDKLibrary() {
        Options.v().set_exclude(Collections.singletonList("java.io.*"));
        Options.v().set_exclude(Collections.singletonList("java.lang.*"));
        Options.v().set_exclude(Collections.singletonList("sun.awt.*"));
        Options.v().set_no_bodies_for_excluded(true);
        Options.v().set_allow_phantom_refs(true);
    }
}

I have set exclusions for Java classes, but they still appear in the call graph. Could you please suggest any adjustments or something I might be missing?

StevenArzt commented 3 months ago

Your method excludeJDKLibrary overwrites the exclusion list every time. In the end, you only set sun.awt.* as excluded, but nothing else. You need to pass a single list that contains all exclusions.

NiceAsiv commented 3 months ago

Hello! Professor Arzt,

Thank you for your guidance. Following your advice, I modified the excludeJDKLibrary function as follows to test its effects:

private static void excludeJDKLibrary()
{
    // Exclude JDK classes
    // Options.v().set_exclude(SootUtils.excludeClassesList);
    Options.v().set_exclude(Collections.singletonList("java.lang.*"));
    // Options.v().set_exclude(Collections.singletonList("sun.*"));
    // This option must be disabled for a sound call graph
    Options.v().set_no_bodies_for_excluded(true);
    Options.v().set_allow_phantom_refs(true);
}

Despite these changes, the output of the call graph still includes functions from java.lang, as shown below:

Entry method: <TestCaseDroid.test.Vulnerable: void main(java.lang.String[])>
<TestCaseDroid.test.Vulnerable: void main(java.lang.String[])> may call <java.lang.Object: void <clinit>()>
<java.lang.Object: void <clinit>()> may call <java.lang.Object: void registerNatives()>
<TestCaseDroid.test.Vulnerable: void main(java.lang.String[])> may call <TestCaseDroid.test.Vulnerable: void vulnerable()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <java.lang.System: void <clinit>()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <java.io.PrintStream: void println(java.lang.String)>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <TestCaseDroid.test.ICFG: void test1()>
<TestCaseDroid.test.ICFG: void test1()> may call <java.lang.System: void <clinit>()>
<TestCaseDroid.test.ICFG: void test1()> may call <TestCaseDroid.test.ICFG: void test2()>
<TestCaseDroid.test.ICFG: void test2()> may call <java.lang.System: void <clinit>()>
<TestCaseDroid.test.ICFG: void test2()> may call <java.io.PrintStream: void println(java.lang.String)>
<TestCaseDroid.test.ICFG: void test2()> may call <TestCaseDroid.test.ICFG: void test3()>
<TestCaseDroid.test.ICFG: void test3()> may call <java.lang.System: void <clinit>()>
<TestCaseDroid.test.ICFG: void test3()> may call <java.io.PrintStream: void println(java.lang.String)>
<TestCaseDroid.test.ICFG: void test3()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.ICFG: void test3()> may call <TestCaseDroid.test.ICFG: void <clinit>()>
<TestCaseDroid.test.ICFG: void <clinit>()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.ICFG: void test2()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.ICFG: void test2()> may call <TestCaseDroid.test.ICFG: void <clinit>()>
<TestCaseDroid.test.ICFG: void test1()> may call <java.io.PrintStream: void println(java.lang.String)>
<TestCaseDroid.test.ICFG: void test1()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <TestCaseDroid.test.ICFG: void <init>()>
<TestCaseDroid.test.ICFG: void <init>()> may call <java.lang.Object: void <init>()>
<java.lang.Object: void <init>()> may call <java.lang.Object: void finalize()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <TestCaseDroid.test.Test4: void test4()>
<TestCaseDroid.test.Test4: void test4()> may call <java.lang.System: void <clinit>()>
<TestCaseDroid.test.Test4: void test4()> may call <java.io.PrintStream: void println(java.lang.String)>
<TestCaseDroid.test.Test4: void test4()> may call <TestCaseDroid.test.ICFG: void test1()>
<TestCaseDroid.test.Test4: void test4()> may call <TestCaseDroid.test.ICFG: void test3()>
<TestCaseDroid.test.Test4: void test4()> may call <TestCaseDroid.test.ICFG: void <init>()>
<TestCaseDroid.test.Test4: void test4()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.Test4: void test4()> may call <TestCaseDroid.test.ICFG: void <clinit>()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <TestCaseDroid.test.Test4: void <init>()>
<TestCaseDroid.test.Test4: void <init>()> may call <java.lang.Object: void <init>()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <java.lang.Object: void <clinit>()>
<TestCaseDroid.test.Vulnerable: void vulnerable()> may call <TestCaseDroid.test.ICFG: void <clinit>()>
<TestCaseDroid.test.Vulnerable: void main(java.lang.String[])> may call <TestCaseDroid.test.Vulnerable: void <init>()>
<TestCaseDroid.test.Vulnerable: void <init>()> may call <java.lang.Object: void <init>()>
Total number of edges: 37

It appears that the exclusion of java.lang is not working as expected. Could you please provide any additional insights or suggestions to address this issue?

Thank you very much for your assistance.

Best regards

StevenArzt commented 3 months ago

The exclusion seems fine. On the left sise of your callgraph edges, you don't have java.lang.* classes aside from two special cases (they are needed for technical reasons). Exclusion only means that you won't see the method bodies of methods in excluded classes. Hence, you have callgraph edges into excluded methods, but the analysis stops there and you don't get any outgoing edges from these methods.

NiceAsiv commented 3 months ago

Hi Dr. Arzt,

Thanks so much for getting back to me on my issue! I really appreciate the effort you've put into developing Soot and the support you provided. Your explanation helped me understand the role of Options.v().set_exclude() perfectly.