Javsssist用InsertAt()方法对语句插桩

基于上一篇的方法插桩,这一篇则是进一步的对每行的语句进行插桩。

对于存在分支的方法(例如if(){}else{}),对方法插桩的方法是不能够全部涉及到的。所以要对程序的每条语句进行插桩。

插入什么语句呢?可以插入包括以下的内容:

1‘  classname

2’  linenumber

此时需要用到javassist  api里的类CtMethod的方法insertAt(),对程序的每条语句进行插桩。

逻辑思想就是:读取class文件,对类的方法进行获取,读取每个类的行号范围,在每个行号前用insertAt()方法插入语句,输出行号和类名。

示例代码如下:

import java.io.IOException;
import javassist.*;

public class TriangleInsertAt {
	public static void main(String args[]) throws NotFoundException, CannotCompileException, IOException{
		//获取class文件
		CtClass clas=ClassPool.getDefault().get("Triangle");
		if(clas==null){
               //方法未找到
			System.out.println("classname "+clas+" not found");
		}else{
			//isTriangle方法的行号范围
                        //此处对Triangle四个方法分别进行语句插桩
			insertToLine(clas,"isTriangle",31,48);
			insertToLine(clas,"getType",55,77);
			insertToLine(clas,"diffOfBorders",83,85);
			insertToLine(clas,"getBorders",90,96);
			clas.writeFile();
		}
	}
	public static void insertToLine (CtClass ccl,String method,int i,int j) throws NotFoundException, CannotCompileException{
		//获取方法信息,如果方法不存在,则抛出异常
		CtMethod ctMethod = ccl.getDeclaredMethod(method);
		 //将旧的方法名称进行重新命名
        String nname = method + "$impl";
        ctMethod.setName(nname);
        //方法的副本
        CtMethod newCtMethod = CtNewMethod.copy(ctMethod, method, ccl, null);
        //用for循环语句插桩
      for(;i<j;i++){
		newCtMethod.insertAt(i,true,"System.out.println(\" classname "+ccl.getName()+" linenumber  \"+" + i +");");
	}
		ccl.addMethod(newCtMethod);
        System.out.println("run to here");
	}
    }

▲ 代码中插入输出语句的那行 

newCtMethod.insertAt(i,true,"System.out.println(\" classname "+ccl.getName()+" linenumber  \"+" + i +");");  这里需要注意引号的不同意义,\"   \"是双引号的转义字符,而加号也是有此处字符串相加的,也有System.out.println()里的输出之间的加号。 

这只是一个基于方法插桩的语句插桩,逻辑缜密上并不完善,待要解决的存有:

1‘  获取行号,需要借助于文件复制,在每循环一次readLine方法,就对linenumber执行+1,在此需要做出判断,该行是否为方法体,构造函数,main方法,注释,空行(此处的空行为代码里的空行,并不意味着null而是换行的“\n”),创建一个数组,对特殊行号进行标记,我目前的思想是构造二维数组,记录行号和该行的属性。(此处需用到IO流的文件读取和写入的方法,在判断时会用到contains()和startwith()方法等;

2’  根据上述的代码生成一个新的class文件,借助工具查看插桩后的java代码,会发现输出的行号并不是按顺序,而且有的行没有,有的行有两次输出。此为编译后生成的class文件的显示。

对此,需要进行缜密的插入判断,借助于第一条的建议进行判断性的插入。

3‘  整个程序中需要语句插桩的有main方法,构造函数,方法,此代码对前两者并没有插入,问题出在还借用了方法插桩的方法,对方法进行重命名,插入输出语句,然后将新的方法也写入到源文件中。而语句插桩并不需要重写方法,而是直接经过判断将输出语句写入到每行符合条件的代码前。输出的结果应该并没有整个程序的行数那么多,而且行数需递增型输出。

总结:

java基础重中之重,仅是一个简单的语句插桩就涉及到了文件复制,读取判断,提取字符串,迭代,Javassist API和JDK API都需要运用到很多方法。

将语句插桩进一步完善的思路:首先文件复制时,创建数组记录行数和出现方法和构造函数的特殊行数;其次读取class文件时,用到CtMethod类的insertAt方法进行选择性的插桩,注释,构造方法的那一行,以及类似“\n”," }","{"之类的字符串都要进行排除;之后运行需要进一步完善不足之处。

一个功能只能经过不断地完善才能尽量的减少bug和提升性能,没有十全十美之时。

时间: 2024-12-27 04:49:52

Javsssist用InsertAt()方法对语句插桩的相关文章

Javassist进行方法插桩

javassist官网 http://jboss-javassist.github.io/javassist/ javassist API网 http://jboss-javassist.github.io/javassist/html/index.html javassist参考博客 https://www.ibm.com/developerworks/cn/java/j-dyn0916/  Ⅰ插桩 自动用例生成(使用Randoop) 评价(对用例筛选冗余)>功能覆盖.语句覆盖(一般用后者)

zorka源码解读之通过beanshell进行插桩的流程

zorka中插桩流程概述 1.在SpyDefinition中配置插桩属性,将SpyDefinition实例提交给插桩引擎.2.SpyDefinition实例中包含了插桩探针probes,probe插入到方法中,对方法的执行进行监控.方法的插入阶段主要包括三个:开始阶段(entry),返回阶段(return),异常阶段(error).每个probe会根据其指定的阶段对方法插桩,捕获其中的数据,比如当前时间.方法参数.方法内部的变量等.probe捕获的数据会封装为SpyRecord实例(Symbol

介绍自己的一个Android插桩热修复框架项目QuickPatch

QuickPatch项目地址:https://gitee.com/egg90/QuickPatch 和 https://github.com/eggfly/QuickPatch 同步更新 类似于美团的Robust插桩热修复,但是代码可读性比较强,还在继续完善,todo list在项目README里 特性:基于函数插桩,兼容性好(Android版本升级不需要做修改),支持热更新无需重启app,参考了美团的Robust插桩热修复框架,精简了很多实现细节,代码可读性高 一句话原理 简单地讲,就是通过编

ASM字节码插桩

个人博客 http://www.milovetingting.cn ASM字节码插桩 前言 热修复的多Dex加载方案中,对于5.0以下的系统存在CLASS_ISPREVERIFIED的问题,而解决这个问题的一个方案是:通过ASM插桩,在类的构造方法里引入一个其它dex里的类,从而避免被打上CLASS_ISPREVERIFIED标签.热修复可以参考其它资料或者前面写的一篇文章.本文主要介绍ASM插桩,主要参考 https://juejin.im/post/5c6eaa066fb9a049fc042

关于smali插桩

????虽说是老生常谈的东西了,稍微记录一下. ????我觉得最重要的就是寄存器的问题了,如果需要额外的寄存器,要在smali函数的最前面将寄存器数量增加到需要的数量. ????在smali代码中,寄存器有两种表示方式,一种是v命名法,一种是p命名法.在v命名法中,从v0开始依次表示局部变量和参数.在p命名法中,从p0开始表示参数,从v0开始表示局部变量.以p命名法为例,在smali函数的开头,.locals n则表示可以使用v0到vn-1表示局部变量,因此如果插桩的时候需要额外的寄存器,则将.

Java连接MySQL数据库实现用户名密码的验证方法 Java语句中sql查询语句&#39;&#39; &quot;&quot;作用

//方法一,可以验证登录,但方法不实用.package com.swift; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class Logi

MySQL 大数据量快速插入方法和语句优化

MySQL大数据量快速插入方法和语句优化是本文我们主要要介绍的内容,接下来我们就来一一介绍,希望能够让您有所收获! INSERT语句的速度 插入一个记录需要的时间由下列因素组成,其中的数字表示大约比例: 连接:(3) 发送查询给服务器:(2) 分析查询:(2) 插入记录:(1x记录大小) 插入索引:(1x索引) 关闭:(1) 这不考虑打开表的初始开销,每个并发运行的查询打开. 表的大小以logN (B树)的速度减慢索引的插入. 加快插入的一些方法 如果同时从同一个客户端插入很多行,使用含多个VA

Smali插桩打日志

一.smali目录下新建crack.smali,内容如下: .class public Lcrack; .super Ljava/lang/Object; .source "crack.java" .method public static log1(Ljava/lang/String;)V #打印出info 1字符串 .locals 1 .prologue const-string v0, "crack_log_str" invoke-static {v0, p0

红米3 Flyme5.1.7.4插桩适配更新

ROM介绍: 1.基于xda论坛CM12.1 20160612版本适配. 2.更新最新Flyme源码至2016年7月4日. 3.修复本地音乐FC,视频FC,手机管家FC,频繁的随机重启. 4.精简部分无用自带,未添加任何推广. 5.暂无其他BUG. ROM下载地址: 链接: http://pan.baidu.com/s/1i5qCUrj 密码: wgbi 第三方刷机REC(TWRP 3.0.2): http://pan.baidu.com/s/1qXX1NCo ROOT单刷卡刷包(SuperSU