使用Flowdroid生成Android程序API调用序列

使用Flowdroid生成Android程序API调用序列

Flowdroid是一个开源项目,可以对Apk进行静态分析,提取API调用序列。源码地址为Flowdroid项目
安装过程按照这篇文章 Flowdroid安装进行就可以了。

下面的代码实现了对APK的批量提取。

package cqu.van;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;


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 GetAPI {
	//设置android的jar包目录  
	  public final static String androidPlatformPath = "C:\\Users\\van\\AppData\\Local\\Android\\Sdk\\platforms";  
	  //设置要分析的APK文件  
	  public final static String appDirPath = "F:\\Sample\\benapk";  
	  //设置结果输出的路径
	  
	  //public final static String AnaPath = "F:\\Sample\\malapi";  
	  
	  public final static String SenapiPath = "";
	  static Object ob = new Object();

	  private static Map<String,Boolean> visited = new HashMap<String,Boolean>();  
	  private static  Vector<String> file_vec =  new Vector<String>();
	  private static  Vector<String> sen_api =  new Vector<String>();
	 
	  
	  public static void getfile(){
		  File file = new File(appDirPath);
		  File[] tempList = file.listFiles();
		  for (int i = 0; i < tempList.length; i++) {
	            if (tempList[i].isFile()) {
	            	int lenname =tempList[i].getName().length();
	            	if(tempList[i].getName().substring(lenname-4).equals(".apk"))
	            	{
	            		file_vec.addElement(tempList[i].getName());
	            	}
	            	
	            }
		  }
		  
	  }

	  //apk路径,遍历模式(0只给出边,1给出所有路径),输出位置
	  public static void getapi(String appname,int mode,String AnaPath) {
		  SetupApplication app = new SetupApplication(androidPlatformPath,appDirPath+File.separator+appname);       
	      soot.G.reset();  
	      //构造调用图,但是不进行数据流分析
	      app.constructCallgraph();

	      //SootMethod 获取函数调用图
	      SootMethod entryPoint = app.getDummyMainMethod();
	      CallGraph cg = Scene.v().getCallGraph();
	      
	     // System.out.println(apppath.substring(0,apppath.length()-4)+".txt");
	      File oFile = new File(AnaPath+File.separator+appname.substring(0,appname.length()-4)+".txt");
	      //可视化函数调用图 
	      
	      switch (mode) {
		case 0:
			visit(cg,entryPoint,oFile,entryPoint.getSignature()); 
			break;
		case 1:
			visit1(cg,entryPoint,oFile,entryPoint.getSignature()); 
			break;
		
		default:
			break;
		}
	     
	    
	     
	  }
	  
	  private static void visit(CallGraph cg,SootMethod m,File oFile,String pString){  
	      //在soot中,函数的signature就是由该函数的类名,函数名,参数类型,以及返回值类型组成的字符串  
	      String identifier = m.getSignature();  
	      //记录是否已经处理过该点  
	      visited.put(identifier, true); 
	      //以函数的signature为label在图中添加该节点   
	      //获取该函数调用的函数  
	      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");  
	              }  
	              //将被调用的函数加入图中  
	        
	              //添加一条指向该被调函数的边  
	              //pString = pString+"-->"+ c.getSignature();
	              writerow(oFile,delpar(identifier)+"-->"+ delpar(c.getSignature()));
	              if(!visited.containsKey(c.getSignature())){  
	                  //递归  
	                  visit(cg,c,oFile,pString);  
	              } 
	              //writerow(oFile,pString);
	          }  
	      }  
	  }  
	  
	  
	  private static void visit1(CallGraph cg,SootMethod m,File oFile,String pString){  
	      //在soot中,函数的signature就是由该函数的类名,函数名,参数类型,以及返回值类型组成的字符串  
	      String identifier = m.getSignature();  
	      //记录是否已经处理过该点  
	      visited.put(identifier, true); 
	      //以函数的signature为label在图中添加该节点   
	      //获取该函数调用的函数  
	      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");  
	              }  
	              //将被调用的函数加入图中  
	        
	              //添加一条指向该被调函数的边  
	              pString = pString+"-->"+ c.getSignature();
	              //writerow(oFile,delpar(identifier)+"-->"+ delpar(c.getSignature()));
	              if(!visited.containsKey(c.getSignature())){  
	                  //递归  
	                  visit1(cg,c,oFile,pString);  
	              } 
	              writerow(oFile,pString);
	          }  
	      }  
	  }  
	  
	  
	  private static void visit2(CallGraph cg,SootMethod m,File oFile,String pString){  
	      //在soot中,函数的signature就是由该函数的类名,函数名,参数类型,以及返回值类型组成的字符串  
	      String identifier = m.getSignature();  
	      //记录是否已经处理过该点  
	      visited.put(identifier, true); 
	      //以函数的signature为label在图中添加该节点   
	      //获取该函数调用的函数  
	      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");  
	              }  
	              //将被调用的函数加入图中  

	              if(!visited.containsKey(c.getSignature())){  
	                  //递归  
	            	  writerow(oFile,delpar(c.getSignature()));
	                  visit2(cg,c,oFile,pString);  
	              } 
	          }  
	      }  
	  }  
	  

	  
	  
	  private static void writerow (File ofile, String s) {
		  FileWriter fw = null;
		  try {
			fw = new FileWriter(ofile,true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		  PrintWriter pw = new PrintWriter(fw);
		  pw.println(s);
		  pw.flush();
		  try {
			fw.flush();
			pw.close();
			fw.close();
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}
	  
	  
	  public static boolean judgesen(String api) 
	  {
		  return true;
	  }
	  public static String delpar(String s) 
	  {
		  int x = s.indexOf('(');
		  int y = s.indexOf(')');
		  String b = s.substring(0,x+1);
		  String e = s.substring(y,s.length());
		  s=b+e;
		  x = s.indexOf(':');
		  String r = s.substring(x+1,s.length()-1);
		  return r;
	  }
	  
	  public static String cutMethod(String s) 
		{
			 int x = s.indexOf(':');
			 String e = s.substring(x+1,s.length()-1);
			 return e;
		}
	  
	  public static void main(String[] args){
		 // System.out.print(delpar(""));
		  
		  File LOG = new File("F:\\Sample\\benapi\\log.txt");
		  getfile();
//		  for(int i=0;i
//		  {
//			  System.out.println(file_vec.elementAt(i));
//		  }
		  for(int i=0;i<file_vec.size();i++) 
		  {
			  try {
				  getapi(file_vec.elementAt(i),0,"F:\\Sample\\benapi");
				
			} catch (Exception e) {
				// TODO: handle exception
				writerow(LOG, file_vec.elementAt(i));
			}
			  
			  System.out.println(i);
			  //提取api序列
		  }
	  }
	  
	 
}

Flowdroid中使用的是CallGraph类来保存调用图信息,通过app.constructCallgraph();来构建函数调用图,我们所做的工作非常简单,就是从这个图中提取所需要的调用序列,通过DFS实现。得到的边信息或者调用序列信息存储在txt文件中。
为了能够批量处理APK,首先在getfile();函数中遍历了待处理的APK。

下图是提取的调用序列,API之间的调用用–>箭头表示

你可能感兴趣的:(APK静态分析,安卓,安全,android)