最新版Flowdroid的使用方法2023
本文参考于;https://blog.csdn.net/king_gun/article/details/77840917
在此感谢jacoryjin大佬
环境:
windows 11
Java version: 1.8.0_361 vendor: Oracle Corporation
Apache Maven 3.9.1
一、什么是 flowdroid
flowdroid是一个静态计算Android应用程序和Java程序中的数据流的工具和库,目前已经在学术界和工业界得到广泛的使用。
我们这一次使用flowdroid生成一个控制流图。
二、配置方法
最新版的flowdroid已经可以使用maven了,所以本次我们使用的是maven进行构建,这样会方便很多
这是我们全部的依赖,有了这些东西我们就可以直接构建项目了
1. 将项目依赖导入到pom.xml中
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
| <dependency> <groupId>de.fraunhofer.sit.sse.flowdroid</groupId> <artifactId>soot-infoflow</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>de.fraunhofer.sit.sse.flowdroid</groupId> <artifactId>soot-infoflow-summaries</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>de.fraunhofer.sit.sse.flowdroid</groupId> <artifactId>soot-infoflow-android</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>woodstox-core-asl</artifactId> <version>4.0.6</version> </dependency> <dependency> <groupId>it.uniroma1.dis.wsngroup.gexf4j</groupId> <artifactId>gexf4j</artifactId> <version>1.0.0</version> </dependency>
|
2.下载AndroidCallbacks.txt文件并放入到项目文件中
AndroidCallbacks.txt存在于flowdroid的源代码中
具体地址为:
https://github.com/secure-software-engineering/FlowDroid/blob/develop/soot-infoflow-android/AndroidCallbacks.txt
下载下来并放入到你的项目文件夹中就像下面这样

3.编写代码
这个文件名叫做CGGenerator.java
注意:需要更改三个变量,已经在java文件中标出来了
那个androidPlatformPath文件目录就是你下载的Android SDK目录中有个PlatformPath,把这个路径给放进去,就像我这样
D:/Environment/Android/Sdk/platforms
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| package org.example;
import java.util.HashMap; import java.util.Iterator; import java.util.Map;
import soot.MethodOrMethodContext; import soot.Scene; import soot.SootMethod; import soot.jimple.infoflow.android.SetupApplication; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Targets;
public class CGGenerator { public final static String androidPlatformPath = "你自己的Android sdk 目录"; public final static String appPath = "你要分析的apk的目录"; public final static String outputPath = "你的输出文件放置目录"; static Object ob = new Object();
private static Map<String,Boolean> visited = new HashMap<String,Boolean>(); private static CGExporter cge = new CGExporter();
public static void main(String[] args){ SetupApplication app = new SetupApplication(androidPlatformPath, appPath); soot.G.reset(); app.setCallbackFile(CGGenerator.class.getResource("/AndroidCallbacks.txt").getFile()); app.constructCallgraph();
SootMethod entryPoint = app.getDummyMainMethod(); CallGraph cg = Scene.v().getCallGraph(); visit(cg,entryPoint); cge.exportMIG("flowdroidCFG", outputPath); } private static void visit(CallGraph cg,SootMethod m){ String identifier = m.getSignature(); visited.put(identifier, true); cge.createNode(identifier); Iterator<MethodOrMethodContext> ptargets = new Targets(cg.edgesInto(m)); if(ptargets != null){ while(ptargets.hasNext()) { SootMethod p = (SootMethod) ptargets.next(); if(p == null){ System.out.println("p is null"); } if(!visited.containsKey(p.getSignature())){ visit(cg,p); } } } Iterator<MethodOrMethodContext> ctargets = new Targets(cg.edgesOutOf(m)); if(ctargets != null){ while(ctargets.hasNext()) { SootMethod c = (SootMethod) ctargets.next(); if(c == null){ System.out.println("c is null"); } cge.createNode(c.getSignature()); cge.linkNodeByID(identifier, c.getSignature()); if(!visited.containsKey(c.getSignature())){ visit(cg,c); } } } } }
|
这是CGExporter.java文件的内容
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package org.example;
import it.uniroma1.dis.wsngroup.gexf4j.core.EdgeType; import it.uniroma1.dis.wsngroup.gexf4j.core.Gexf; import it.uniroma1.dis.wsngroup.gexf4j.core.Graph; import it.uniroma1.dis.wsngroup.gexf4j.core.Mode; import it.uniroma1.dis.wsngroup.gexf4j.core.Node; import it.uniroma1.dis.wsngroup.gexf4j.core.data.Attribute; import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeClass; import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeList; import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeType; import it.uniroma1.dis.wsngroup.gexf4j.core.impl.GexfImpl; import it.uniroma1.dis.wsngroup.gexf4j.core.impl.StaxGraphWriter; import it.uniroma1.dis.wsngroup.gexf4j.core.impl.data.AttributeListImpl;
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.List;
public class CGExporter { private Gexf gexf; private Graph graph; private Attribute codeArray; private AttributeList attrList;
public CGExporter() { this.gexf = new GexfImpl(); this.graph = this.gexf.getGraph(); this.gexf.getMetadata().setCreator("liu3237").setDescription("App method invoke graph"); this.gexf.setVisualization(true); this.graph.setDefaultEdgeType(EdgeType.DIRECTED).setMode(Mode.STATIC); this.attrList = new AttributeListImpl(AttributeClass.NODE); this.graph.getAttributeLists().add(attrList); this.codeArray = this.attrList.createAttribute("0", AttributeType.STRING,"codeArray"); }
public void exportMIG(String graphName, String storeDir) { String outPath = storeDir + "/" + graphName + ".gexf"; StaxGraphWriter graphWriter = new StaxGraphWriter(); File f = new File(outPath); Writer out; try { out = new FileWriter(f, false); graphWriter.writeToStream(this.gexf, out, "UTF-8"); } catch (IOException e) { e.printStackTrace(); } }
public Node getNodeByID(String Id) { List<Node> nodes = this.graph.getNodes(); Node nodeFinded = null; for (Node node : nodes) { String nodeID = node.getId(); if (nodeID.equals(Id)) { nodeFinded = node; break; } } return nodeFinded; }
public void linkNodeByID(String sourceID, String targetID) { Node sourceNode = this.getNodeByID(sourceID); Node targetNode = this.getNodeByID(targetID); if (sourceNode.equals(targetNode)) { return; } if (!sourceNode.hasEdgeTo(targetID)) { String edgeID = sourceID + "-->" + targetID; sourceNode.connectTo(edgeID, "", EdgeType.DIRECTED, targetNode); } }
public void createNode(String m) { String id = m; String codes = ""; if (getNodeByID(id) != null) { return; } Node node = this.graph.createNode(id); node.setLabel(id).getAttributeValues().addValue(this.codeArray, codes); node.setSize(20); } }
|
三、结果分析
我们生成的文件是gexf文件,需要Gephi软件打开,这个也是github上的一个开源的软件
然后我们查看打开的文件
这就是他的一个节点的分析

四、结语
再次感谢jacoryjin大佬写的博客
感谢所有写博客分享知识的人