soot基础 -- 解析java文件

问题:

      soot如何接受java文件,并且将其解析出来?

      这里主要说明两种解析方式,通过调用soot接口的方式,以及以类似于命令行的方式向soot传递参数的方式。

两种方式本质上是相同的,看读者更容易接受哪一种。

一、通过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类。

  • 路径的设置十分重要,路径不正确可能导致无法识别。
  • Options是全局的参数设置,并且是只有一个(单例)。

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>

二、 以类似于命令行的方式向soot传递参数

       这次我们通过构建查看call graph(函数调用关系图)相关的一些内容。

1.待检测的类如下:

  • 该文件所在的路径: 项目 / test / testCallGraph / testers
  • Call graph的生成是必须得有入口函数(main)的。
  • 注意从main 开始追踪调用的结构。

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可以识别的东西。
  • 命令参数以类似于数组的方式传递给main().

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);
}
}


 

分析的结果

  • 只关注doStuff()所可能调用的方法。(这里说可能,是因为call graph的构造,并不是绝对的准确的事情

<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输出中间代码

  • Main.java】在Soot中有个Main.java类,这个类主要是负责解析命令行的,在这里面可以找到命令  与 程序类的方法 之间的对应关系(尤其注意Main中的run()方法)。
  • PackManager】PackMananger是负责进行阶段处理的,它控制着各种执行的运行,不启动则不会运行相应的阶段。(将类的加载类的分析运行相区别,见文章:soot -- 常见参数配置

                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(); //关键:启动输出。(不运行此语句不会进行输出)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鸳鸯锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值