From 3d938422302f17101472ae6754737c6dddfcf0f8 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 13 Sep 2024 19:52:54 +0200 Subject: [PATCH 01/10] subclasses of GraphBasedCallGraph can now access edges in the call graph, simplified the adaption of the export to dotFile and to String of potential subclasses --- .../sootup/callgraph/GraphBasedCallGraph.java | 156 +++++++++++++----- 1 file changed, 116 insertions(+), 40 deletions(-) diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java index bae6cf9ce6c..a6fcdb3aa9f 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java @@ -22,12 +22,13 @@ * #L% */ -import com.google.common.base.Preconditions; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -103,9 +104,15 @@ protected void addCall( || containsCall(call)) { return; } - Vertex source = vertexOf(sourceMethod); - Vertex target = vertexOf(targetMethod); - graph.addEdge(source, target, call); + Optional source = vertexOf(sourceMethod); + if (!source.isPresent()) { + return; + } + Optional target = vertexOf(targetMethod); + if (!target.isPresent()) { + return; + } + graph.addEdge(source.get(), target.get(), call); } @Nonnull @@ -117,31 +124,49 @@ public Set getMethodSignatures() { @Nonnull @Override public Set callTargetsFrom(@Nonnull MethodSignature sourceMethod) { - return graph.outgoingEdgesOf(vertexOf(sourceMethod)).stream() - .map(graph::getEdgeTarget) - .map(targetVertex -> targetVertex.methodSignature) - .collect(Collectors.toSet()); + Optional source = vertexOf(sourceMethod); + return source + .map( + vertex -> + graph.outgoingEdgesOf(vertex).stream() + .map(graph::getEdgeTarget) + .map(targetVertex -> targetVertex.methodSignature) + .collect(Collectors.toSet())) + .orElse(Collections.emptySet()); } @Nonnull @Override public Set callSourcesTo(@Nonnull MethodSignature targetMethod) { - return graph.incomingEdgesOf(vertexOf(targetMethod)).stream() - .map(graph::getEdgeSource) - .map(targetVertex -> targetVertex.methodSignature) - .collect(Collectors.toSet()); + Optional target = vertexOf(targetMethod); + return target + .map( + vertex -> + graph.incomingEdgesOf(vertex).stream() + .map(graph::getEdgeSource) + .map(targetVertex -> targetVertex.methodSignature) + .collect(Collectors.toSet())) + .orElse(Collections.emptySet()); } @Nonnull @Override public Set callsFrom(@Nonnull MethodSignature sourceMethod) { - return graph.outgoingEdgesOf(vertexOf(sourceMethod)); + Optional source = vertexOf(sourceMethod); + if (!source.isPresent()) { + return Collections.emptySet(); + } + return graph.outgoingEdgesOf(source.get()); } @Nonnull @Override public Set callsTo(@Nonnull MethodSignature targetMethod) { - return graph.incomingEdgesOf(vertexOf(targetMethod)); + Optional target = vertexOf(targetMethod); + if (!target.isPresent()) { + return Collections.emptySet(); + } + return graph.incomingEdgesOf(target.get()); } @Override @@ -212,21 +237,22 @@ public String exportAsDot() { edge -> { Vertex sourceVertex = graph.getEdgeSource(edge); Vertex targetVertex = graph.getEdgeTarget(edge); - dotFormatBuilder - .append("\t") - .append("\"") - .append(sourceVertex.methodSignature) - .append("\"") - .append(" -> ") - .append("\"") - .append(targetVertex.methodSignature) - .append("\"") - .append(";\n"); + dotFormatBuilder.append("\t").append(toDotEdge(edge)).append(";\n"); }); return "strict digraph ObjectGraph {\n" + dotFormatBuilder + "}"; } + protected String toDotEdge(CallGraph.Call edge) { + Vertex sourceVertex = graph.getEdgeSource(edge); + Vertex targetVertex = graph.getEdgeTarget(edge); + return "\"" + + sourceVertex.methodSignature + + "\" -> \"" + + targetVertex.methodSignature + + "\";\n"; + } + @SuppressWarnings("unchecked") // (graph.clone() preserves generic properties) @Nonnull @Override @@ -244,16 +270,46 @@ public CallGraphDifference diff(@Nonnull CallGraph callGraph) { } /** - * it returns the vertex of the graph that describes the given method signature in the call graph. + * it returns the optional of a vertex of the graph that describes the given method signature in + * the call graph. * * @param method the method signature searched in the call graph - * @return the vertex of the requested method signature. + * @return the vertex of the requested method signature in optional otherwise an empty optional. */ @Nonnull - protected Vertex vertexOf(@Nonnull MethodSignature method) { + protected Optional vertexOf(@Nonnull MethodSignature method) { Vertex methodVertex = signatureToVertex.get(method); - Preconditions.checkNotNull(methodVertex, "Node for " + method + " has not been added yet"); - return methodVertex; + if (methodVertex == null) { + return Optional.empty(); + } + return Optional.of(methodVertex); + } + + /** + * it returns the optional of an edge of the graph that is described by the given source, target, + * stmt in the call graph. + * + * @param source the signature of the source method + * @param target the signature of the target method + * @param invokableStmt the stmt causing the call + * @return the found edge in an optional or otherwise an empty optional + */ + @Nonnull + protected Optional edgeOf( + @Nonnull MethodSignature source, + @Nonnull MethodSignature target, + @Nonnull InvokableStmt invokableStmt) { + Optional sourceVertexOpt = vertexOf(source); + if (!sourceVertexOpt.isPresent()) { + return Optional.empty(); + } + Optional targetVertexOpt = vertexOf(target); + // returns empty optional if the target vertex or the call is not found + return targetVertexOpt.flatMap( + vertex -> + graph.getAllEdges(sourceVertexOpt.get(), vertex).stream() + .filter(call -> call.getInvokableStmt() == invokableStmt) + .findFirst()); } /** @@ -266,7 +322,8 @@ protected Vertex vertexOf(@Nonnull MethodSignature method) { */ @Override public String toString() { - StringBuilder stringBuilder = new StringBuilder("GraphBasedCallGraph(" + callCount() + ")"); + StringBuilder stringBuilder = + new StringBuilder(this.getClass().getSimpleName() + "(" + callCount() + ")"); Set signatures = signatureToVertex.keySet(); if (signatures.isEmpty()) { stringBuilder.append(" is empty"); @@ -280,24 +337,43 @@ public String toString() { .forEach( method -> { stringBuilder.append(method).append(":\n"); - callTargetsFrom(method).stream() + callsFrom(method).stream() .sorted( - Comparator.comparing((MethodSignature o) -> o.getDeclClassType().toString()) - .thenComparing(SootClassMemberSignature::getName) - .thenComparing(o -> o.getParameterTypes().toString())) - .forEach(m -> stringBuilder.append("\tto ").append(m).append("\n")); - callSourcesTo(method).stream() + Comparator.comparing( + (Call call) -> + call.getTargetMethodSignature().getDeclClassType().toString()) + .thenComparing(call -> call.getTargetMethodSignature().getName()) + .thenComparing( + call -> + call.getTargetMethodSignature().getParameterTypes().toString())) + .forEach( + c -> stringBuilder.append("\tto ").append(printCaller(c)).append("\n")); + callsTo(method).stream() .sorted( - Comparator.comparing((MethodSignature o) -> o.getDeclClassType().toString()) - .thenComparing(SootClassMemberSignature::getName) - .thenComparing(o -> o.getParameterTypes().toString())) - .forEach(m -> stringBuilder.append("\tfrom ").append(m).append("\n")); + Comparator.comparing( + (Call call) -> + call.getSourceMethodSignature().getDeclClassType().toString()) + .thenComparing(call -> call.getSourceMethodSignature().getName()) + .thenComparing( + call -> + call.getSourceMethodSignature().getParameterTypes().toString())) + .forEach( + call -> + stringBuilder.append("\tfrom ").append(printCallee(call)).append("\n")); stringBuilder.append("\n"); }); } return stringBuilder.toString(); } + protected String printCaller(CallGraph.Call call) { + return call.getSourceMethodSignature().toString(); + } + + protected String printCallee(CallGraph.Call call) { + return call.getTargetMethodSignature().toString(); + } + @Override @Nonnull public List getEntryMethods() { From f5234caf36438afffc53b0c7afb2fc033d15cd1e Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 13 Sep 2024 19:54:20 +0200 Subject: [PATCH 02/10] removed unnecessary call for vertexes --- .../src/main/java/sootup/callgraph/GraphBasedCallGraph.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java index a6fcdb3aa9f..4a6ae6b3f6b 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java @@ -235,8 +235,6 @@ public String exportAsDot() { })) .forEach( edge -> { - Vertex sourceVertex = graph.getEdgeSource(edge); - Vertex targetVertex = graph.getEdgeTarget(edge); dotFormatBuilder.append("\t").append(toDotEdge(edge)).append(";\n"); }); From 37e9c3454225e00876a18e1f16ff450b29975146 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 13 Sep 2024 19:55:40 +0200 Subject: [PATCH 03/10] removed warning --- .../src/main/java/sootup/callgraph/GraphBasedCallGraph.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java index 4a6ae6b3f6b..df83c951035 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java @@ -234,9 +234,7 @@ public String exportAsDot() { return edgeTarget.methodSignature.getParameterTypes().toString(); })) .forEach( - edge -> { - dotFormatBuilder.append("\t").append(toDotEdge(edge)).append(";\n"); - }); + edge -> dotFormatBuilder.append("\t").append(toDotEdge(edge)).append(";\n")); return "strict digraph ObjectGraph {\n" + dotFormatBuilder + "}"; } From e081b99f96a4c737adc82570195e738db1549769 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 11:42:25 +0200 Subject: [PATCH 04/10] removed deprecated Dex2Jar from the documentation --- docs/analysisinput.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/docs/analysisinput.md b/docs/analysisinput.md index 2aea18d6af0..bea7a10d855 100644 --- a/docs/analysisinput.md +++ b/docs/analysisinput.md @@ -117,42 +117,6 @@ JavaView view = new JavaView(inputLocation); ``` -### Android Bytecode with Dex2Jar -File-Extensions: `.apk` - -The `ApkAnalysisInputLocation` currently uses dex2jar internally - -```java -Path path = Paths.get("Banana.apk"); -AnalysisInputLocation inputLocation = new Dex2JarAnalysisInputLocation(path); -JavaView view = new JavaView(inputLocation); - -``` - -```java -public class Dex2JarAnalysisInputLocation extends ArchiveBasedAnalysisInputLocation { - - public Dex2JarAnalysisInputLocation(@Nonnull Path path, @Nullable SourceType srcType) { - super(path, srcType); - String jarPath = dex2jar(path); - this.path = Paths.get(jarPath); - } - - private String dex2jar(Path path) { - String apkPath = path.toAbsolutePath().toString(); - String outDir = "./tmp/"; - int start = apkPath.lastIndexOf(File.separator); - int end = apkPath.lastIndexOf(".apk"); - String outputFile = outDir + apkPath.substring(start + 1, end) + ".jar"; - Dex2jarCmd.main("-f", apkPath, "-o", outputFile); - return outputFile; - } -} -``` - -!!! info "A SootUp solution to directly generate Jimple is WIP!" - - ### Combining Multiple AnalysisInputLocations But what if I want to point to multiple AnalysisInputLocations? From d727b5993449f575e1a5efa945f9fd96f9ac2dc5 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 11:44:39 +0200 Subject: [PATCH 05/10] moved all version numbers to the parent pom --- pom.xml | 96 +++++++++++++++++++------ sootup.analysis.interprocedural/pom.xml | 1 - sootup.analysis.intraprocedural/pom.xml | 5 ++ sootup.apk.frontend/pom.xml | 11 ++- sootup.callgraph/pom.xml | 37 +++++----- sootup.java.bytecode.frontend/pom.xml | 9 --- sootup.jimple.frontend/pom.xml | 1 - sootup.qilin/pom.xml | 3 - sootup.report/pom.xml | 13 ---- 9 files changed, 106 insertions(+), 70 deletions(-) diff --git a/pom.xml b/pom.xml index 0c4692de33a..f0aec771b1a 100644 --- a/pom.xml +++ b/pom.xml @@ -86,20 +86,12 @@ UTF-8 3.2.5 0.8.4 - 2.0.5 - 2.0.5 - 32.0.1-jre - 3.12.0 - 2.11.0 - 5.10.2 - 1.7.3 - 1.7.3 1.6.13 3.2.1 3.1.1 2.8.2 3.1.0 - 3.0.1 + 3.0.1 true ${basedir}/target @@ -379,34 +371,76 @@ org.slf4j slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-simple - ${slf4j-simple.version} - true + 2.0.13 org.apache.commons commons-lang3 - ${apache-commons.version} + 3.14.0 commons-io commons-io - ${apache-commons-io.version} + 2.16.1 com.google.guava guava - ${guava.version} + 33.3.0-jre + + + org.jgrapht + jgrapht-core + 1.3.1 + + + de.upb.cs.swt + heros + 1.2.3 + + + org.ow2.asm + asm-util + 9.6 + + + org.ow2.asm + asm-commons + 9.7 + + + org.smali + dexlib2 + 2.5.2 + + + de.upb.cs.swt + axml + 2.1.3 + + + org.antlr + antlr4-runtime + 4.9.3 + + + commons-cli + commons-cli + 1.5.0 + + + + com.github.oshi + oshi-core + 6.4.0 + + org.junit.jupiter junit-jupiter-api - ${junit.version} + 5.10.2 test @@ -415,6 +449,18 @@ 2.0.13 test + + org.mockito + mockito-core + 4.0.0 + test + + + org.mockito + mockito-junit-jupiter + 5.12.0 + test + com.google.code.findbugs @@ -476,6 +522,16 @@ sootup.apk.frontend ${project.version} + + org.soot-oss + sootup.qilin + ${project.version} + + + org.soot-oss + sootup.tests + ${project.version} + diff --git a/sootup.analysis.interprocedural/pom.xml b/sootup.analysis.interprocedural/pom.xml index 94b1288bff1..3690f878233 100644 --- a/sootup.analysis.interprocedural/pom.xml +++ b/sootup.analysis.interprocedural/pom.xml @@ -39,7 +39,6 @@ de.upb.cs.swt heros - 1.2.3 diff --git a/sootup.analysis.intraprocedural/pom.xml b/sootup.analysis.intraprocedural/pom.xml index 565f130c4de..97f95c87ea0 100644 --- a/sootup.analysis.intraprocedural/pom.xml +++ b/sootup.analysis.intraprocedural/pom.xml @@ -32,5 +32,10 @@ junit-jupiter-api test + + org.slf4j + slf4j-simple + test + diff --git a/sootup.apk.frontend/pom.xml b/sootup.apk.frontend/pom.xml index 2de8ee940aa..7b719f6944f 100644 --- a/sootup.apk.frontend/pom.xml +++ b/sootup.apk.frontend/pom.xml @@ -22,33 +22,27 @@ org.soot-oss sootup.core - 1.3.1-SNAPSHOT org.soot-oss sootup.java.core - 1.3.1-SNAPSHOT org.smali dexlib2 - 2.5.2 de.upb.cs.swt axml - 2.1.3 org.mockito mockito-core - 4.0.0 test org.mockito mockito-junit-jupiter - 5.12.0 test @@ -57,6 +51,11 @@ 4.13.2 test + + org.slf4j + slf4j-simple + test + diff --git a/sootup.callgraph/pom.xml b/sootup.callgraph/pom.xml index 9813421c5b0..f884e723fe7 100644 --- a/sootup.callgraph/pom.xml +++ b/sootup.callgraph/pom.xml @@ -17,25 +17,9 @@ org.soot-oss sootup.core - - org.soot-oss - sootup.java.bytecode.frontend - test - - - org.soot-oss - sootup.java.sourcecode.frontend - test - - - org.soot-oss - sootup.jimple.frontend - test - org.jgrapht jgrapht-core - 1.3.1 com.google.code.findbugs @@ -57,7 +41,26 @@ org.junit.jupiter junit-jupiter-api - + + org.slf4j + slf4j-simple + test + + + org.soot-oss + sootup.java.bytecode.frontend + test + + + org.soot-oss + sootup.java.sourcecode.frontend + test + + + org.soot-oss + sootup.jimple.frontend + test + diff --git a/sootup.java.bytecode.frontend/pom.xml b/sootup.java.bytecode.frontend/pom.xml index 7de4966e2eb..28a25fbfb74 100644 --- a/sootup.java.bytecode.frontend/pom.xml +++ b/sootup.java.bytecode.frontend/pom.xml @@ -28,27 +28,18 @@ org.ow2.asm asm-util - 9.5 org.ow2.asm asm-commons - 9.5 - - - de.femtopedia.dex2jar - dex2jar - 2.4.16 com.google.code.findbugs jsr305 - 3.0.2 org.slf4j slf4j-api - ${slf4j.version} com.google.guava diff --git a/sootup.jimple.frontend/pom.xml b/sootup.jimple.frontend/pom.xml index ed8cb4639cf..10e3c7c3895 100644 --- a/sootup.jimple.frontend/pom.xml +++ b/sootup.jimple.frontend/pom.xml @@ -65,7 +65,6 @@ org.antlr antlr4-runtime - 4.9.3 diff --git a/sootup.qilin/pom.xml b/sootup.qilin/pom.xml index de300712c35..b0187e68411 100644 --- a/sootup.qilin/pom.xml +++ b/sootup.qilin/pom.xml @@ -34,19 +34,16 @@ commons-cli commons-cli - 1.5.0 com.github.oshi oshi-core - 6.4.0 de.upb.cs.swt heros - 1.2.3 junit diff --git a/sootup.report/pom.xml b/sootup.report/pom.xml index a44433723ff..355054218be 100644 --- a/sootup.report/pom.xml +++ b/sootup.report/pom.xml @@ -50,79 +50,66 @@ org.soot-oss sootup.core - ${project.version} compile org.soot-oss sootup.java.bytecode.frontend - ${project.version} compile org.soot-oss sootup.java.core - ${project.version} compile org.soot-oss sootup.java.sourcecode.frontend - ${project.version} compile org.soot-oss sootup.jimple.frontend - ${project.version} compile org.soot-oss sootup.callgraph - ${project.version} compile org.soot-oss sootup.analysis.interprocedural - ${project.version} compile org.soot-oss sootup.analysis.intraprocedural - ${project.version} compile org.soot-oss sootup.codepropertygraph - ${project.version} compile org.soot-oss sootup.interceptors - ${project.version} compile org.soot-oss sootup.apk.frontend - ${project.version} compile org.soot-oss sootup.qilin - ${project.version} compile org.soot-oss sootup.tests - ${project.version} compile From bf447ae80e1c825a286619efd989ca084c0665e1 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 11:47:17 +0200 Subject: [PATCH 06/10] changed optional to throwing exception in the internal graph handling of the call graph --- .../sootup/callgraph/GraphBasedCallGraph.java | 116 +++++++----------- .../sootup/callgraph/MutableCallGraph.java | 7 ++ 2 files changed, 53 insertions(+), 70 deletions(-) diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java index df83c951035..32c1dc485cc 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java @@ -23,12 +23,10 @@ */ import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -94,25 +92,20 @@ public void addCall( @Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod, @Nonnull InvokableStmt invokableStmt) { - addCall(sourceMethod, targetMethod, new Call(sourceMethod, targetMethod, invokableStmt)); + addCall(new Call(sourceMethod, targetMethod, invokableStmt)); } - protected void addCall( - @Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod, Call call) { - if (!call.getSourceMethodSignature().equals(sourceMethod) - || !call.getTargetMethodSignature().equals(targetMethod) - || containsCall(call)) { - return; - } - Optional source = vertexOf(sourceMethod); - if (!source.isPresent()) { - return; + @Override + public void addCall(@Nonnull Call call) { + if (!containsMethod(call.getSourceMethodSignature())) { + addMethod(call.getSourceMethodSignature()); } - Optional target = vertexOf(targetMethod); - if (!target.isPresent()) { - return; + Vertex source = vertexOf(call.getSourceMethodSignature()); + if (!containsMethod(call.getTargetMethodSignature())) { + addMethod(call.getTargetMethodSignature()); } - graph.addEdge(source.get(), target.get(), call); + Vertex target = vertexOf(call.getTargetMethodSignature()); + graph.addEdge(source, target, call); } @Nonnull @@ -124,49 +117,29 @@ public Set getMethodSignatures() { @Nonnull @Override public Set callTargetsFrom(@Nonnull MethodSignature sourceMethod) { - Optional source = vertexOf(sourceMethod); - return source - .map( - vertex -> - graph.outgoingEdgesOf(vertex).stream() - .map(graph::getEdgeTarget) - .map(targetVertex -> targetVertex.methodSignature) - .collect(Collectors.toSet())) - .orElse(Collections.emptySet()); + return callsFrom(sourceMethod).stream() + .map(Call::getTargetMethodSignature) + .collect(Collectors.toSet()); } @Nonnull @Override public Set callSourcesTo(@Nonnull MethodSignature targetMethod) { - Optional target = vertexOf(targetMethod); - return target - .map( - vertex -> - graph.incomingEdgesOf(vertex).stream() - .map(graph::getEdgeSource) - .map(targetVertex -> targetVertex.methodSignature) - .collect(Collectors.toSet())) - .orElse(Collections.emptySet()); + return callsTo(targetMethod).stream() + .map(Call::getSourceMethodSignature) + .collect(Collectors.toSet()); } @Nonnull @Override public Set callsFrom(@Nonnull MethodSignature sourceMethod) { - Optional source = vertexOf(sourceMethod); - if (!source.isPresent()) { - return Collections.emptySet(); - } - return graph.outgoingEdgesOf(source.get()); + return graph.outgoingEdgesOf(vertexOf(sourceMethod)); } @Nonnull @Override public Set callsTo(@Nonnull MethodSignature targetMethod) { - Optional target = vertexOf(targetMethod); - if (!target.isPresent()) { - return Collections.emptySet(); - } - return graph.incomingEdgesOf(target.get()); + return graph.incomingEdgesOf(vertexOf(targetMethod)); } @Override @@ -233,8 +206,7 @@ public String exportAsDot() { Vertex edgeTarget = graph.getEdgeTarget(call); return edgeTarget.methodSignature.getParameterTypes().toString(); })) - .forEach( - edge -> dotFormatBuilder.append("\t").append(toDotEdge(edge)).append(";\n")); + .forEach(edge -> dotFormatBuilder.append("\t").append(toDotEdge(edge)).append("\n")); return "strict digraph ObjectGraph {\n" + dotFormatBuilder + "}"; } @@ -242,11 +214,7 @@ public String exportAsDot() { protected String toDotEdge(CallGraph.Call edge) { Vertex sourceVertex = graph.getEdgeSource(edge); Vertex targetVertex = graph.getEdgeTarget(edge); - return "\"" - + sourceVertex.methodSignature - + "\" -> \"" - + targetVertex.methodSignature - + "\";\n"; + return "\"" + sourceVertex.methodSignature + "\" -> \"" + targetVertex.methodSignature + "\";"; } @SuppressWarnings("unchecked") // (graph.clone() preserves generic properties) @@ -266,24 +234,26 @@ public CallGraphDifference diff(@Nonnull CallGraph callGraph) { } /** - * it returns the optional of a vertex of the graph that describes the given method signature in - * the call graph. + * it returns the vertex of the graph that describes the given method signature in the call graph. + * It will throw an exception if the vertex is not found * * @param method the method signature searched in the call graph * @return the vertex of the requested method signature in optional otherwise an empty optional. + * @throws IllegalArgumentException if there is no vertex for the requested method signature */ @Nonnull - protected Optional vertexOf(@Nonnull MethodSignature method) { + protected Vertex vertexOf(@Nonnull MethodSignature method) { Vertex methodVertex = signatureToVertex.get(method); if (methodVertex == null) { - return Optional.empty(); + throw new IllegalArgumentException("Vertex of Method signature " + method + " not found"); } - return Optional.of(methodVertex); + return methodVertex; } /** - * it returns the optional of an edge of the graph that is described by the given source, target, - * stmt in the call graph. + * it returns the edge of the graph that is described by the given source, target, stmt in the + * call graph. It will throw an exception if the source or target is not contained in the call + * graph or if the edge could not be found. * * @param source the signature of the source method * @param target the signature of the target method @@ -291,21 +261,27 @@ protected Optional vertexOf(@Nonnull MethodSignature method) { * @return the found edge in an optional or otherwise an empty optional */ @Nonnull - protected Optional edgeOf( + protected CallGraph.Call edgeOf( @Nonnull MethodSignature source, @Nonnull MethodSignature target, @Nonnull InvokableStmt invokableStmt) { - Optional sourceVertexOpt = vertexOf(source); - if (!sourceVertexOpt.isPresent()) { - return Optional.empty(); - } - Optional targetVertexOpt = vertexOf(target); + Vertex sourceVertexOpt = vertexOf(source); + Vertex targetVertexOpt = vertexOf(target); // returns empty optional if the target vertex or the call is not found - return targetVertexOpt.flatMap( - vertex -> - graph.getAllEdges(sourceVertexOpt.get(), vertex).stream() - .filter(call -> call.getInvokableStmt() == invokableStmt) - .findFirst()); + + return graph.getAllEdges(sourceVertexOpt, targetVertexOpt).stream() + .filter(call -> call.getInvokableStmt() == invokableStmt) + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + "Edge of source:" + + source + + " target:" + + target + + " stmt:" + + invokableStmt + + " not found")); } /** diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/MutableCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/MutableCallGraph.java index 6df01fba4ca..708af3ad875 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/MutableCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/MutableCallGraph.java @@ -50,4 +50,11 @@ void addCall( @Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod, @Nonnull InvokableStmt invokableStmt); + + /** + * This method enables to add calls that are edges in the call graph. + * + * @param call this parameter defines the call that is transformed to the edge in the call graph. + */ + void addCall(@Nonnull Call call); } From e4ca2400318c90fcaba5007095927f543810a0a5 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 11:53:23 +0200 Subject: [PATCH 07/10] added adcall(call) in qilin --- .../java/qilin/core/builder/callgraph/OnFlyCallGraph.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java b/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java index 250c3a39891..e5b2765cb18 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java @@ -444,6 +444,11 @@ public void addCall( } } + @Override + public void addCall(@Nonnull Call call) { + addCall(call.getSourceMethodSignature(),call.getTargetMethodSignature(),call.getInvokableStmt()); + } + @Nonnull @Override public Set getMethodSignatures() { From 76b94c3280b7d6ea7813938375e7c7a870bbc123 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 12:04:23 +0200 Subject: [PATCH 08/10] fmt --- .../main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java b/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java index e5b2765cb18..cc2fca17469 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/callgraph/OnFlyCallGraph.java @@ -446,7 +446,8 @@ public void addCall( @Override public void addCall(@Nonnull Call call) { - addCall(call.getSourceMethodSignature(),call.getTargetMethodSignature(),call.getInvokableStmt()); + addCall( + call.getSourceMethodSignature(), call.getTargetMethodSignature(), call.getInvokableStmt()); } @Nonnull From 245d64b39186d4533e3b3ea344ce7b3a899e8ea3 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 12:21:14 +0200 Subject: [PATCH 09/10] added a slf4j-simple to all submodules as test logger --- sootup.analysis.interprocedural/pom.xml | 1 + sootup.codepropertygraph/pom.xml | 6 ++++++ sootup.core/pom.xml | 5 +++++ sootup.examples/pom.xml | 6 ++++++ sootup.java.bytecode.frontend/pom.xml | 6 ++++++ sootup.java.core/pom.xml | 6 ++++++ sootup.java.sourcecode.frontend/pom.xml | 6 ++++++ sootup.jimple.frontend/pom.xml | 7 +++++++ sootup.qilin/pom.xml | 5 +++++ sootup.tests/pom.xml | 6 ++++++ 10 files changed, 54 insertions(+) diff --git a/sootup.analysis.interprocedural/pom.xml b/sootup.analysis.interprocedural/pom.xml index 3690f878233..20cd077e070 100644 --- a/sootup.analysis.interprocedural/pom.xml +++ b/sootup.analysis.interprocedural/pom.xml @@ -30,6 +30,7 @@ org.junit.jupiter junit-jupiter-api + test org.slf4j diff --git a/sootup.codepropertygraph/pom.xml b/sootup.codepropertygraph/pom.xml index 71b1628ddaf..630cbeba22d 100644 --- a/sootup.codepropertygraph/pom.xml +++ b/sootup.codepropertygraph/pom.xml @@ -42,6 +42,12 @@ org.junit.jupiter junit-jupiter-api + test + + + org.slf4j + slf4j-simple + test diff --git a/sootup.core/pom.xml b/sootup.core/pom.xml index aceeddd6dd1..7ca5a0a7bce 100644 --- a/sootup.core/pom.xml +++ b/sootup.core/pom.xml @@ -47,5 +47,10 @@ junit-jupiter-api test + + org.slf4j + slf4j-simple + test + diff --git a/sootup.examples/pom.xml b/sootup.examples/pom.xml index 6644e6aa200..0dbf70588ec 100644 --- a/sootup.examples/pom.xml +++ b/sootup.examples/pom.xml @@ -43,6 +43,12 @@ org.junit.jupiter junit-jupiter-api + test + + + org.slf4j + slf4j-simple + test diff --git a/sootup.java.bytecode.frontend/pom.xml b/sootup.java.bytecode.frontend/pom.xml index 28a25fbfb74..366a5726399 100644 --- a/sootup.java.bytecode.frontend/pom.xml +++ b/sootup.java.bytecode.frontend/pom.xml @@ -52,11 +52,17 @@ org.junit.jupiter junit-jupiter-api + test org.apache.commons commons-lang3 + + org.slf4j + slf4j-simple + test + diff --git a/sootup.java.core/pom.xml b/sootup.java.core/pom.xml index 7073834405d..4917b9ea0a0 100644 --- a/sootup.java.core/pom.xml +++ b/sootup.java.core/pom.xml @@ -37,6 +37,12 @@ org.junit.jupiter junit-jupiter-api + test + + + org.slf4j + slf4j-simple + test diff --git a/sootup.java.sourcecode.frontend/pom.xml b/sootup.java.sourcecode.frontend/pom.xml index 196ebab3a97..022efe0cdf7 100644 --- a/sootup.java.sourcecode.frontend/pom.xml +++ b/sootup.java.sourcecode.frontend/pom.xml @@ -393,6 +393,12 @@ org.junit.jupiter junit-jupiter-api + test + + + org.slf4j + slf4j-simple + test diff --git a/sootup.jimple.frontend/pom.xml b/sootup.jimple.frontend/pom.xml index 10e3c7c3895..46bb0ccdce9 100644 --- a/sootup.jimple.frontend/pom.xml +++ b/sootup.jimple.frontend/pom.xml @@ -70,6 +70,7 @@ org.junit.jupiter junit-jupiter-api + test @@ -77,5 +78,11 @@ commons-io + + org.slf4j + slf4j-simple + test + + \ No newline at end of file diff --git a/sootup.qilin/pom.xml b/sootup.qilin/pom.xml index b0187e68411..8890168f23b 100644 --- a/sootup.qilin/pom.xml +++ b/sootup.qilin/pom.xml @@ -59,6 +59,11 @@ commons-io commons-io + + org.slf4j + slf4j-simple + test + diff --git a/sootup.tests/pom.xml b/sootup.tests/pom.xml index e67e39d9e93..90786aab42b 100644 --- a/sootup.tests/pom.xml +++ b/sootup.tests/pom.xml @@ -45,6 +45,12 @@ org.junit.jupiter junit-jupiter-api + test + + + org.slf4j + slf4j-simple + test From bb18799a0458add7029f8666bed2cdb4749f6bda Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Sep 2024 13:23:22 +0200 Subject: [PATCH 10/10] update doc --- docs/analysisinput.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/analysisinput.md b/docs/analysisinput.md index bea7a10d855..a7806a1883a 100644 --- a/docs/analysisinput.md +++ b/docs/analysisinput.md @@ -114,8 +114,41 @@ The `ApkAnalysisInputLocation` is the APK frontend written for Sootup Path path = Paths.get("Banana.apk"); AnalysisInputLocation inputLocation = new ApkAnalysisInputLocation(path, "", DexBodyInterceptors.Default.bodyInterceptors()); JavaView view = new JavaView(inputLocation); +``` +### Android Bytecode with Dex2Jar +File-Extensions: `.apk` + +If you prefer to use dex2jar as a base to transform android apps to jimple, you can add the code below to create your own analysis input location. +We used the dependency de.femtopedia.dex2jar:dex2jar:2.4.22 in the given example. +We recommend to use ApkAnalysisInputLocation + +```java +Path path = Paths.get("Banana.apk"); +AnalysisInputLocation inputLocation = new Dex2JarAnalysisInputLocation(path); +JavaView view = new JavaView(inputLocation); + ``` +```java +public class Dex2JarAnalysisInputLocation extends ArchiveBasedAnalysisInputLocation { + + public Dex2JarAnalysisInputLocation(@Nonnull Path path, @Nullable SourceType srcType) { + super(path, srcType); + String jarPath = dex2jar(path); + this.path = Paths.get(jarPath); + } + + private String dex2jar(Path path) { + String apkPath = path.toAbsolutePath().toString(); + String outDir = "./tmp/"; + int start = apkPath.lastIndexOf(File.separator); + int end = apkPath.lastIndexOf(".apk"); + String outputFile = outDir + apkPath.substring(start + 1, end) + ".jar"; + Dex2jarCmd.main("-f", apkPath, "-o", outputFile); + return outputFile; + } +} +``` ### Combining Multiple AnalysisInputLocations But what if I want to point to multiple AnalysisInputLocations?