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.
分享到:
相关推荐
这篇博客"ASM函数监听实现(二)之打印注入函数的参数值"深入探讨了如何利用ASM库来监控并记录函数调用时的参数值,这对于调试、日志记录以及性能分析等场景非常有用。 首先,我们来看`asmAopClassAdapter.java`。...
本篇文章将深入探讨如何使用ASM库来实现函数监听,特别是如何在函数执行前拦截并改变其参数值。 首先,我们需要理解ASM库的基本用法。ASM提供了一套API,可以直接生成或修改字节码。在Java中,每个类都是以字节码...
ASM注入器工具是一种专门设计用于调试和远程注入CALL指令的实用程序。在IT行业中,ASM(Assembly Language)注入是高级编程技术的一种,它涉及到在运行时修改或插入汇编代码到另一个进程,以改变其行为或功能。这种...
ASM是一个低级别的库,可以直接操作Java字节码,提供了一种动态生成和修改类的方法。它通过ClassWriter、ClassReader、MethodVisitor等接口,允许开发者对字节码进行读取、修改和写入。ASM的核心在于它的事件驱动...
在本例中,我们探讨的是如何使用汇编(ASM)代码进行远程线程注入,实现“Hello World”级别的操作。汇编语言是计算机编程的底层语言,它直接对应于机器指令,提供了对硬件的直接控制。 首先,理解远程线程注入的...
在C++编程中,通过函数指针调用非静态成员函数是一种高级技巧,主要用于实现回调、动态绑定等场景。本文将详细探讨如何在Visual C++ 6.0 (VC6.0) 和Borland C++ Builder 6.0 (BCB6.0) 中实现这一功能。 #### 一、...
通过 grid 用户的 ADRCI 工具,可以实现对 ASM 和 SCAN 监听日志的轻松管理。 ASM 实例日志文件和监听日志文件都属于 ADR(Automatic Diagnostic Repository)的管理范围内。ADR 是 Oracle 数据库管理系统中的一种...
总的来说,ASM算法在OpenCV中的实现为研究人员和开发者提供了一个强大的工具,帮助他们在人脸识别、物体检测等领域实现高级的图像分析任务。通过深入理解和实践,我们可以充分利用ASM算法的潜力,开发出更高效、准确...
这个"cos.rar_32 bit cosine_cos_cos_asm_cos函数的实现_temperature"主题涉及到的是使用汇编语言实现32位浮点数的余弦函数计算。余弦函数在数学中广泛应用于各种科学和工程计算,如信号处理、物理模拟以及图像处理...
内联是一种优化技术,它将函数调用替换为函数体,减少了方法调用的开销,提升了执行效率。在R类中,内联常量字段可以减少对象创建,节省内存,同时由于字段直接写入到使用它的代码中,也减少了APK的大小。 Android...
代码注入器别名(ASM汇编CALL测试器)可测试游戏函数CALL,这个工具非常的好用,但是使用的时候请注入汇编书写和堆栈平衡否则游戏会崩溃。还有这个工具必须配合OD调试器使用,因为汇编代码是从OD里面分析出来 ,哈哈。
这种方法利用了Windows平台下的内存分配和汇编语言特性,通过创建一个特殊的结构体和辅助函数来实现成员函数到静态函数的转换。 #### 实现原理 为了实现这一目标,我们需要定义一个特殊的结构体`_...
几种函数调用的方式,关于函数调用的一些东西,选自 Hacker Disassembling Uncovered 里的一节 ,精简版..
ASM32提供了一种低级别的接口,可以直接与操作系统内核交互,从而实现对进程的精细操作。 首先,枚举进程的基本步骤包括: 1. **获取进程句柄**:使用`CreateToolhelp32Snapshot`函数创建一个快照,该快照包含了...
这通常可以通过手动选择一个初始点或者使用其他预处理方法来实现。 3. **迭代优化**: 初始化后,ASM算法会进入迭代过程。在每一步迭代中,算法会根据图像的灰度信息调整形状模型的参数,使得模型与图像的对应区域...
C32ASM作为一款专用于PE(Portable Executable)格式文件的静态反汇编工具,其强大的功能和易用性使其在软件开发、安全分析以及教学研究领域中有着广泛的应用。 首先,C32ASM的主要功能是静态反汇编。静态反汇编是...
驱动函数是实现硬件操作的软件接口,对于ASM330LHH来说,驱动函数主要包括初始化、配置传感器参数、读取数据和中断处理等部分。以下是一些关键步骤: 1. **初始化**:设置I²C或SPI接口,配置时钟,使能传感器电源...
C32asm 是一款非常不错的国产静态反编译工具! C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等多种实用...
【标题】"cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar" 提供的是一组用于Java编程的库,它们主要用于实现动态代理和字节码操作。 【描述】"cglib动态代理模式jar包 cglib-2.2.jar asm-tree.jar asm-...
自Oracle Database 10g起引入了ASM,并且被认为是数据库文件的最佳存储解决方案之一。ASM自动跨所有可用的存储设备分条数据库文件(包括数据文件、临时表空间文件、重做日志文件、闪回恢复区以及spfile),并且...