问题:
soot如何接受java文件,并且将其解析出来?
这里主要说明两种解析方式,通过调用soot接口的方式,以及以类似于命令行的方式向soot传递参数的方式。
两种方式本质上是相同的,看读者更容易接受哪一种。
1.首先我构建了一个测试类:
public class TestMain { public static void main(String[] args) { C(1); } public static void A(){ System.out.println("inside A"); } public static void B(){ System.out.println("inside B"); } public static void C(int i ){ if(i > 1){ A(); }else{ B(); } } }
2.接下来我要用soot来识别出这个java类。
public class TestFileInput { public static final String path = "test/javaTest"; public static void main(String args[]) { initial(path); SootClass appclass = Scene.v().loadClassAndSupport("TestMain");//若无法找到,则生成一个。 System.out.println("the main class is :" + appclass.getName()); //获取类中的相关的方法 Iterator<SootMethod> methodIt = appclass.getMethods().iterator(); while(methodIt.hasNext()){ System.out.println("the function member is : " + methodIt.next().getName()); } } private static void initial(String apkPath) { soot.G.reset(); Options.v().set_allow_phantom_refs(true); Options.v().set_prepend_classpath(true); Options.v().set_validate(true); Options.v().set_output_format(Options.output_format_jimple); Options.v().set_src_prec(Options.src_prec_java); Options.v().set_process_dir(Collections.singletonList(apkPath));//路径应为文件夹 Options.v().set_keep_line_number(true); //Options.v().set_whole_program(true); Options.v().set_no_bodies_for_excluded(true); Options.v().set_app(true); // Scene.v().setMainClass(appclass); // how to make it work ? Scene.v().addBasicClass("java.io.PrintStream", SootClass.SIGNATURES); Scene.v().addBasicClass("java.lang.System", SootClass.SIGNATURES); Scene.v().addBasicClass("java.lang.Thread", SootClass.SIGNATURES); Scene.v().loadNecessaryClasses(); } }
3.结果如下:
the main class is :TestMain
the function member is : main
the function member is : A
the function member is : B
the function member is : C
the function member is : <init>
这次我们通过构建查看call graph(函数调用关系图)相关的一些内容。
1.待检测的类如下:
package testers; public class CallGraphs { public static void main(String[] args) { doStuff(); } public static void doStuff() { new A().foo(); } } class A { public void foo() { bar(); } public void bar() { } }
2.通过soot解析上面这个类的call graph.
代码如下:
soot.Main.main(args) 相当于命令行处理。main会将传递的数组进行解析,对于命令解析成soot可以识别的东西。
public class CallGraphExample { public static void main(String[] args) { List<String> argsList = new ArrayList<String>(Arrays.asList(args)); //相当于传入命令行参数。cmd上操作命令。 argsList.addAll(Arrays.asList(new String[]{ "-w", // "-v", "-process-path", "test/testCallGraph", "-main-class", "testers.CallGraphs",//main-class "testers.CallGraphs",//argument classes "testers.A"// })); PackManager.v().getPack("wjtp").add(new Transform("wjtp.myTrans", new SceneTransformer() { @Override protected void internalTransform(String phaseName, Map options) { CHATransformer.v().transform(); SootClass a = Scene.v().getSootClass("testers.A"); SootMethod src = Scene.v().getMainClass().getMethodByName("doStuff"); CallGraph cg = Scene.v().getCallGraph(); Iterator<MethodOrMethodContext> targets = new Targets(cg.edgesOutOf(src)); while (targets.hasNext()) { SootMethod tgt = (SootMethod)targets.next(); System.out.println(src + " may call " + tgt);//这里说的是可能,并不是一定就正确。 } } })); args = argsList.toArray(new String[0]); soot.Main.main(args); } }
分析的结果
<testers.CallGraphs: void doStuff()> may call <java.lang.Object: void <clinit>()> <testers.CallGraphs: void doStuff()> may call <testers.A: void foo()> <testers.CallGraphs: void doStuff()> may call <testers.A: void <init>()>
soot.G.reset(); Options.v().set_allow_phantom_refs(true); Options.v().set_prepend_classpath(true); Options.v().set_validate(true); Options.v().set_output_format(Options.output_format_jimple);//1.输出的形式 Options.v().set_output_dir("sootOutput"); //2.输出的文件目录 Options.v().set_src_prec(Options.src_prec_java); Options.v().set_process_dir(Collections.singletonList(apkPath)); Options.v().set_whole_program(true); Options.v().set_no_bodies_for_excluded(true); Scene.v().addBasicClass("java.io.PrintStream", SootClass.SIGNATURES); Scene.v().addBasicClass("java.lang.System", SootClass.SIGNATURES); Scene.v().addBasicClass("java.lang.Thread", SootClass.SIGNATURES); Scene.v().loadNecessaryClasses(); PackManager.v().writeOutput(); //关键:启动输出。(不运行此语句不会进行输出)