Flowdroid生成apk的控制流图

本文介绍了如何利用Flowdroid的最新版本2.10.0对Android应用进行静态数据流分析。通过Maven构建项目,设置必要的依赖,并提供AndroidCallbacks.txt文件。在Windows11环境下,详细步骤包括配置Android平台路径,分析APK文件,生成并导出控制流图,最后使用Gephi软件进行结果分析。
摘要由CSDN通过智能技术生成

最新版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中

		<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>
        <!-- https://mvnrepository.com/artifact/org.codehaus.woodstox/woodstox-core-asl -->
        <dependency>
            <groupId>org.codehaus.woodstox</groupId>
            <artifactId>woodstox-core-asl</artifactId>
            <version>4.0.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/it.uniroma1.dis.wsngroup.gexf4j/gexf4j -->
        <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

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 {
    //设置android的jar包目录
    public final static String androidPlatformPath = "你自己的Android sdk 目录";
    //设置要分析的APK文件
    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();
        //传入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", outputPath);
    }
    //可视化函数调用图的函数
    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.java文件的内容

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);
        //可以给每个节点设置一些属性,这里设置的属性名是 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);
    }
}

三、结果分析

我们生成的文件是gexf文件,需要Gephi软件打开,这个也是github上的一个开源的软件

然后我们查看打开的文件

这就是他的一个节点的分析
在这里插入图片描述

四、结语

再次感谢jacoryjin大佬写的博客

感谢所有写博客分享知识的人

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值