1.目的:实现对函数执行监听,在函数调用前,后得到通知。考虑用asm来实现。
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下:
http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html
http://alvinqq.iteye.com/blog/940965
http://www.ibm.com/developerworks/cn/java/j-lo-asm30/
http://ayufox.iteye.com/blog/668917
3.代码:asmAopClassAdapter 该类对目标类进行操作。
public class asmAopClassAdapter extends ClassAdapter{
private String enhancedSuperName,enhancedName;
private String method;
private String startInfo,endInfo;
public asmAopClassAdapter(ClassVisitor cv,String methodName,String start,String end) {
//Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter,
// 负责改写后代码的输出
super(cv);
method = methodName;
startInfo = start;
endInfo = end;
}
// 重写 visitMethod,访问到 "method" 方法时,
// 给出自定义 MethodVisitor,实际改写方法内容
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
MethodVisitor wrappedMv = mv;
if (mv != null) {
if (name.equals(method)) {
wrappedMv = new asmAopMethodAdapter(mv,startInfo,endInfo);
} else if (name.equals("<init>")) {
wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
enhancedSuperName);
}
}
return wrappedMv;
}
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
enhancedName = name.replace("/", "$")+"$EnhancedByASM"; // 改变类命名
enhancedSuperName = name; // 改变父类
super.visit(version, access, enhancedName, signature,
enhancedSuperName, interfaces);
}
public String getEnhancedName() {
return enhancedName;
}
}
asmAopMethodAdapter 对目标类的方法做操作。
public class asmAopMethodAdapter extends MethodAdapter implements Opcodes{
private final static int EXCEPTION_STACK = 2 + 1;//max_stack至少需要能够容纳2个常量地址(监控方法使用)和1个exception地址
private Label try_catch_start,try_catch_end;
private String startInfo,endInfo;
public asmAopMethodAdapter(MethodVisitor mv,String start,String end) {
super(mv);
try_catch_start = new Label();
try_catch_end = new Label();
startInfo = start;
endInfo = end;
}
public void visitCode() {
mv.visitCode();
mv.visitLabel(try_catch_start);
mv.visitLdcInsn(startInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodStart", "(Ljava/lang/String;)V");
}
public void visitInsn(int opcode){
if(opcode >= IRETURN && opcode <= RETURN){
mv.visitLdcInsn(endInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodEnd", "(Ljava/lang/String;)V");
}
mv.visitInsn(opcode);
}
public void visitEnd() {
mv.visitLabel(try_catch_end);
mv.visitTryCatchBlock(try_catch_start, try_catch_end, try_catch_end, null);
mv.visitLdcInsn(endInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodEnd", "(Ljava/lang/String;)V");
mv.visitInsn(Opcodes.ATHROW);
mv.visitEnd();
}
public void visitMaxs(int maxStack,int maxLocals){
//保证max stack足够大
mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals);
}
}
ChangeToChildConstructorMethodAdapter该类生成目标类的子类。
public class ChangeToChildConstructorMethodAdapter extends MethodAdapter {
private String superClassName;
public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,
String superClassName) {
super(mv);
this.superClassName = superClassName;
}
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
// 调用父类的构造函数时
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
owner = superClassName;
}
super.visitMethodInsn(opcode, owner, name, desc);// 改写父类为 superClassName
}
}
asmAopGenerator 一个工具类,生成代理目标类的对象。
public class asmAopGenerator {
private AOPGeneratorClassLoader classLoader ;
public asmAopGenerator(){
classLoader = new AOPGeneratorClassLoader();
}
public Object proxy(Class c,String methodName,String startInfo,String endInfo) {
try{
if( c != null){
String classPach = c.toString().replace("/", ".");
ClassReader cr = new ClassReader(classPach.substring(6,classPach.length()));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
asmAopClassAdapter classAdapter = new asmAopClassAdapter(cw,methodName,startInfo,endInfo);
cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] data = cw.toByteArray();
Class obj = classLoader.defineClassFromClassFile(classAdapter.getEnhancedName(), data);
//TODO:隐藏BUG
return obj.newInstance();
}}catch(Exception e){
e.printStackTrace();
}
return null;
}
class AOPGeneratorClassLoader extends ClassLoader {
public Class defineClassFromClassFile(String className,
byte[] classFile) throws ClassFormatError {
return defineClass(className, classFile, 0,
classFile.length);
}
}
}
asmAopInvoker 函数注入类
public class asmAopInvoker {
public static void methodEnd(String evtID){
System.out.println(evtID);
}
public static void methodStart(String evtID){
System.out.println(evtID);
}
}
测试类
public class helloWorld {
public void sayHello(){
System.out.println("helloWorld....");
}
public static void main(String[]args){
asmAopGenerator aag = new asmAopGenerator();
helloWorld hw = (helloWorld) aag.proxy(helloWorld.class, "sayHello", "it's begin", "it's end");
hw.sayHello();
}
}
输出结果
it's begin
helloWorld....
it's end
4.目的基本达成。
5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。
6.环境 asm 3.3.1 jdk 1.6.
分享到:
相关推荐
NULL 博文链接:https://xkorey.iteye.com/blog/1667944
NULL 博文链接:https://xkorey.iteye.com/blog/1670257
几种函数调用的方式,关于函数调用的一些东西,选自 Hacker Disassembling Uncovered 里的一节 ,精简版..
远程线程注入asm代码.hello world级别 xxxxxxxxxxx
Android 无痕埋点框架 使用ASM插桩实现
C32asm 是一款非常不错的国产静态反编译工具! C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等多种实用...
查看ASM实例和SCAN监听日志文件 查看本地监听日志文件 Database日志文件
DLL函数动态调用工具1.0 使用Delphi + Asm编写,只要知道DLL中函数的名字和参数,就可以对任意Dll的函数进行调用。目前已经可以支持以下类型的参数和返回值:Boolean,Byte,Shortint,Word,Smallint,Longword,Integer,...
方便用于调试远程注入CALL的工具; 支持自行申请空间,进行参数写入; 支持代码搜索寻址;
ASM之方法Frame是一个复杂的数据结构,它是JVM运行时方法执行的基础。理解ASM之方法Frame的结构和工作原理,对于Java开发者来说非常重要,可以帮助他们更好地理解Java字节码的执行过程,并提高Java程序的性能和安全...
asm算法的opencv实现,中含有三个工具,分别可以从图片,摄像机中获得人脸识别特征点描述
支持简易数据资源管理功能 实现JPA基本数据库操作功能封装 实现基于ASM9,动态生成entity、repository、service、serviceImpl、controller相关.class 可根据库表,一键生成新增、修改删除、查询等接口 实现部分基于...
C32ASM静态反汇编工具
oracle不使用oracleasm的包配置ASM磁盘配置方法
C32asm 是一款非常不错的国产静态反编译工具! C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等多种实用...
用泰勒公式实现余弦函数的计算,使用汇编的方法,里面用到了32位的运算方法,灵活应用了定点运算的思想。
ASM模拟坏块 ASM里实现修改指定的Block
ASM算法实现对齐功能代码 经典算法asm,内部对齐部分代码,就是求解那个矩阵代码
C32Asm是一款非常不错的国产静态反编译工具! C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等多种实用...
C32asm 是一款非常不错的国产静态反编译工具! C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等...