基于最新版soot-infoflow-android绘制android应用函数调用图
来源:互联网 发布:高性能网络编程 编辑:程序博客网 时间:2024/06/14 21:03
【问题】
最近在研究android应用函数调用图分析,准备基于soot做代码静态分析。
调用图过程中主要参考了Blog:http://blog.csdn.net/liu3237/article/details/48827523《使用FlowDroid生成Android应用程序的函数调用图》
新的soot-infoflow-android函数调用图获取使用constructCallgraph(),不再需要提供source和sink,老的函数不再适用,猜测老的版本是基于release1.5。详细参见:https://github.com/secure-software-engineering/soot-infoflow/issues/38
【解决方案】
1、根据steven的提示和阅读最新源码,了解只需要设置AndroidCallbacks,再调用constructCallgraph()即可;关键代码如下:
SetupApplication app = new SetupApplication(androidPlatformPath, appPath); //传入AndroidCallbacks文件app.setCallbackFile(CGGenerator.class.getResource("AndroidCallbacks.txt").getFile());app.constructCallgraph();
2、绘制调用图,主要参考《使用FlowDroid生成Android应用程序的函数调用图》,改动点在于获取调用函数的方式跟原来的不再一致;关键代码如下:
//SootMethod 获取函数调用图SootMethod entryPoint = app.getDummyMainMethod();CallGraph cg = Scene.v().getCallGraph();//可视化函数调用图 visit(cg,entryPoint); //导出函数调用图 cge.exportMIG("flowdroidCFG", "E:/");【代码工程】
工程基于当前最新的代码去构建
1、flowdroidcg依赖于gexf4j-1.0.0.jar、stax2-api-4.0.0.jar、woodstox-core-asl-4.4.0.jar、soot(依赖heros、jasmin)、soot-infoflow、soot-infoflow-android
soot等获取gihub最新develop分支:
- Jasmin: https://github.com/Sable/jasmin
- Heros: https://github.com/Sable/heros
- Soot: https://github.com/Sable/soot
- soot-infoflow: https://github.com/secure-software-engineering/soot-infoflow
- soot-infoflow-android: https://github.com/secure-software-engineering/soot-infoflow-android
2、AndroidCallbacks.txt可从soot-infoflow-android根目录拿到,依赖及工程结构如下:
CGGenerator.java
package flowdroidcg; 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 { //设置android的jar包目录 public final static String androidPlatformPath = "D:/Android/sdk/platforms"; //设置要分析的APK文件 public final static String appPath = "E:/enriched1.apk"; 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(); //传入AndroidCallbacks文件 app.setCallbackFile(CGGenerator.class.getResource("AndroidCallbacks.txt").getFile()); app.constructCallgraph(); //SootMethod 获取函数调用图 SootMethod entryPoint = app.getDummyMainMethod(); CallGraph cg = Scene.v().getCallGraph(); //可视化函数调用图 visit(cg,entryPoint); //导出函数调用图 cge.exportMIG("flowdroidCFG", "E:/"); } //可视化函数调用图的函数 private static void visit(CallGraph cg,SootMethod m){ //在soot中,函数的signature就是由该函数的类名,函数名,参数类型,以及返回值类型组成的字符串 String identifier = m.getSignature(); //记录是否已经处理过该点 visited.put(identifier, true); //以函数的signature为label在图中添加该节点 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
package flowdroidcg; 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); //可以给每个节点设置一些属性,这里设置的属性名是 codeArray,实际上后面没用到 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); } }【结果】
代码分析的apk是/soot-infoflow-android/testAPKs/enriched1.apk,结果图如下:
阅读全文
1 0
- 基于最新版soot-infoflow-android绘制android应用函数调用图
- 基于Soot的Android Apps检测
- Instrumenting Android Apps with Soot
- soot学习笔记-2.使用soot解析Android apk.
- Android 基于surfaceView绘制正弦曲线
- 利用Soot插装Android App
- 使用Soot在android程序中插装
- 利用soot插装Android App
- android 调用系统应用
- android调用系统应用
- android 调用系统应用
- android 调用系统应用
- android调用系统应用
- Android 调用系统应用
- android 调用系统应用
- android 调用系统应用
- android天气预报应用开发(三)---- 趋势图界面绘制
- Android Webkit内核应用层函数调用方法
- 51Nod
- Intellji oschina同步python工程后异常处理
- 网格走法种数
- g++编译运行
- mybaits查询时间段,传日期参数出现的问题
- 基于最新版soot-infoflow-android绘制android应用函数调用图
- 磁盘挂载信息:/etc/fstab
- 9.4训练日志
- matlab 绘图,设置label字体,插入公式
- GetSystemInfo函数实验
- C语言在用户模式使用NT函数
- 2127-树-堆结构练习——合并果子之哈夫曼树(优先队列实现)
- hexo+github搭建博客跳坑
- WebRTC协议栈视图结构