soot-oss / soot

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

JLookupSwitchStmt.toString java.lang.StackOverflowError #2010

Open HP-Allen opened 10 months ago

HP-Allen commented 10 months ago

JLookupSwitchStmt contains endless loop, therefore it triggered SOE.

com.androidesk_317.zip

gradle:

implementation 'org.soot-oss:soot:4.4.1'
implementation 'de.upb.cs.swt:heros:1.1.0'
implementation 'org.slf4j:slf4j-simple:2.0.7'
implementation 'org.slf4j:slf4j-api:2.0.7'

java code:

        G.reset();
        Options.v().set_prepend_classpath(true);
        Options.v().set_allow_phantom_refs(true);
        Options.v().set_output_format(Options.output_format_jimple);
        Options.v().set_process_dir(Collections.singletonList("com.androidesk_317.apk"));
        Options.v().set_whole_program(true);
        Options.v().set_src_prec(Options.src_prec_apk);
        Options.v().set_app(true);
        Options.v().set_process_multiple_dex(true);
        Options.v().set_android_jars("F:\\android-platforms-master\\platforms");

        Scene.v().loadNecessaryClasses();

        List<SootMethod> entryPoints = new ArrayList<>();

        for (SootClass sc : Scene.v().getApplicationClasses()) {
            entryPoints.addAll(sc.getMethods());
        }
        Scene.v().setEntryPoints(entryPoints);

        PackManager.v().runPacks();

        SootMethod sootMethod = Scene.v().getMethod("<com.bytedance.msdk.adapter.ks.KsDrawAdapter: void loadAd(android.content.Context,java.util.Map)>");
        for (Unit unit: sootMethod.retrieveActiveBody().getUnits()){
            unit.toString();
        }

debug information:

Exception in thread "main" java.lang.StackOverflowError
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:179)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:91)
    at java.base/java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:112)
    at java.base/java.lang.StringBuilder.<init>(StringBuilder.java:131)
    at soot.jimple.internal.JLookupSwitchStmt.toString(JLookupSwitchStmt.java:81)
    at java.base/java.lang.String.valueOf(String.java:4218)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
    at soot.jimple.internal.JLookupSwitchStmt.toString(JLookupSwitchStmt.java:90)
    at java.base/java.lang.String.valueOf(String.java:4218)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
    at soot.jimple.internal.JLookupSwitchStmt.toString(JLookupSwitchStmt.java:90)
    at java.base/java.lang.String.valueOf(String.java:4218)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
    at soot.jimple.internal.JLookupSwitchStmt.toString(JLookupSwitchStmt.java:90)
    at java.base/java.lang.String.valueOf(String.java:4218)
......

unitChain: image endless loop: image

I found that the SOE was triggered when a case of JLookupSwitchStmt is goto another JLookupSwitchStmt. Therefore, I added an if statement, when the unit that a case goto is instanceof JLookupSwitchStmt, I decided the key value of JLookupSwitchStmt as the String value.

modified code in soot.jimple.internal.JLookupSwitchStmt.toString

@Override
    public String toString() {
        final char endOfLine = ' ';
        StringBuilder buf = new StringBuilder(Jimple.LOOKUPSWITCH + "(");

        buf.append(keyBox.getValue().toString()).append(')').append(endOfLine);
        buf.append('{').append(endOfLine);

        for (ListIterator<IntConstant> it = lookupValues.listIterator(); it.hasNext(); ) {

            IntConstant c = it.next();
            buf.append("    " + Jimple.CASE + " ").append(c).append(": " + Jimple.GOTO + " ");
            Unit target = getTarget(it.previousIndex());
            if (target instanceof JLookupSwitchStmt) {
                // modification from here ******************************************************************
                StringBuilder targetStringBuilder = new StringBuilder();
                targetStringBuilder.append(Jimple.LOOKUPSWITCH + "(").append(((JLookupSwitchStmt) target).getKeyBox().getValue().toString()).append(')').append(endOfLine);
                buf.append(target == this ? "self" : targetStringBuilder.toString()).append(';').append(endOfLine);
            }else {
                buf.append(target == this ? "self" : target).append(';').append(endOfLine);
            }
                // modification to here ******************************************************************
        }
        {
            buf.append("    " + Jimple.DEFAULT + ": " + Jimple.GOTO + " ");
            Unit target = getDefaultTarget();
            buf.append(target == this ? "self" : target).append(';').append(endOfLine);
        }
        buf.append('}');

        return buf.toString();
    }

After modification: image