soot插桩关键点总结(三)

一 插入字段

给某个SootClass插入字段,关键API为new SootField(String,Type,int);

//向sootclass添加静态Intent intent_for_ipc字段
SootField intent_for_ipc = new SootField("intent_for_ipc", intentSootClass.getType(),Modifier.STATIC);
sootclass.addField(intent_for_ipc);
注意:一般是在wjtp下给某个SootClass插入字段

二 构造方法

1. 构造没有参数的方法

SootMethod sm = new SootMethod("getIntent", Arrays.asList(new Type[]{}), RefType.v("java.lang.String"), Modifier.PUBLIC);

2. 构造对象为参数的方法

SootClass intentSootClass = Scene.v().getSootClass("android.content.Intent");
SootMethod sm = new SootMethod("getIntent", Arrays.asList(new Type[]{}), intentSootClass.getType(),Modifier.PUBLIC);

3. 构造数组为参数的方法

method=new SootMethod("main",Arrays.asList(newType[]{ArrayType.v(RefType.v("java.lang.String"), 1)}),VoidType.v(),Modifier.PUBLIC|Modifier.STATIC);

4. 构造多个参数的方法

SootMethod smmm = new SootMethod("mulPara",Arrays.asList(new Type[]{RefType.v("java.lang.String"),intentSootClass.getType()}),VoidType.v(), Modifier.PUBLIC);

三 字段赋值

在(一)中给出了向某个SootClass插入字段的关键代码,那么针对字段该如何赋值呢?下面给出非静态字段赋值与静态字段赋值的方法

1. 静态字段赋值

关键API位:Jimple.v().newStaticFieldRef(intent_for_ipc_makeRef())和Jimple.v().newAssignStmt()
//保存参数
Local arg = Jimple.v().newLocal("l0", intentSootClass.getType());
helperBody.getLocals().add(arg);
IdentityStmt para = Jimple.v().newIdentityStmt(arg, Jimple.v().newParameterRef(intentSootClass.getType(), 0));
helperBody.getUnits().add(para);
//将arg赋值给字段
helperBody.getUnits().add(Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(intent_for_ipc.makeRef()), arg));
helperBody.getUnits().add(Jimple.v().newReturnVoidStmt());

2. 非静态字段赋值

关键API为:Jimple.v().newInstanceFieldRef(Value, SootFieldRef),其中第一个参数为字段所在类的实例化对象

四 在确定位置插桩

在soot实现Android Apps插桩(一)的完整代码中有一段代码:
while(iter.hasNext()){
	final Unit unit = (Unit)iter.next();
			unit.apply(new AbstractStmtSwitch(){
				
				public void caseAssignStmt(AssignStmt stmt){
					...
						
					}

				
				public void caseInvokeStmt(InvokeStmt stmt){
					...
						}

					
				}

			}

 
 
这是一种在确定位置插桩的方法,其中,还有另外一种方法,如下:
PatchingChain<Unit> units = body.getUnits();
	for(Iterator iter = units.snapshotIterator();iter.hasNext();){
		Unit u = (Unit)iter.next();
		if(u instanceof InvokeStmt){
			String methodName = ((InvokeStmt) u).getInvokeExpr().getMethod().getName();
			System.out.println(methodName);
			if(methodName.equals("add")){
				Local local = Jimple.v().newLocal("lizhengqiao",RefType.v("java.lang.String"));
				body.getLocals().add(local);
				...
			}
				
		}
		//if(u instance IdentityStmt)
		//...
}
另:在Java中,可以采用另外一种插桩的方法:直接写一个需要插桩的Java代码,然后插桩调用该Java类中的方法即可。
经过我的测试:给某个确定的方法内插桩代码时,应该使用BodyTransformer,而插桩字段、方法则应该使用SceneTransformer;在向某个方法中插桩句子时,在使用SceneTransformer时,我没有成功;经过我的多次尝试,在Scene下插桩代码,很容易被soot优化掉,如:插桩一个local,但是没有对local进一步的操作,则会被soot优化掉,查看生成的代码中就没有该local,而在Body下插桩则不会出现这种情况。可能我的理解有误,有成功的希望能够分享一二。

你可能感兴趣的:(插桩,Soot)