java字节码操作

你知道如何操作JAVA字节码文件吗,这里将介绍与操作Java字节码有关的基本知识和操作Java字节码的方法及Demo,首先我们来看一下AOP的概念,AOP是OOP的延续,是AspectOrientedProgramming的缩写,意思是面向方面编程。

如何操作JAVA字节码文件

  本文将介绍与操作Java字节码有关的基本知识和操作Java字节码的方法及Demo,谈到操作Java字节码,不能不谈到AOP(AspectOrientedProgramming),下面来简单介绍一下:

AOP简介

  AOP是OOP的延续,是AspectOrientedProgramming的缩写,意思是面向方面编程。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

   AOP的一个典型应用就是J2EE。J2EE应用系统只有部署在J2EE容器中才能运行,那么为什么划分为J2EE容器和J2EE应用系统?通过对 J2EE容器运行机制的分析,可以发现:实际上J2EE容器分离了一般应用系统的一些通用功能,例如事务机制、安全机制以及对象池或线程池等性能优化机 制。

  这些功能机制是每个应用系统几乎都需要的,因此可以从具体应用系统中分离出来,形成一个通用的框架平台,而且,这些功能机制的设计 开发有一定难度,同时运行的稳定性和快速性都非常重要,必须经过长时间调试和运行经验积累而成,因此,形成了专门的J2EE容器服务器产品,如 TomcatJBoss。

  简单了解AOP后,再来了解一下AOP底层技术:

AOP(AspectOrientedProgramming)底层技术比较

  从上面的图表中分析可以看到,对于一般的操作Java字节码要求(实际上是能够满足笔者100%的要求),综合考虑功能,性能,可用性,易用性,使用Java字节码框架来操作Java字节码是最佳的选择。

  下面来了解一下都有哪些开源操作JavaJava字节码的框架:

  Javassist;

  cglib;

  SERP;

  Packagegnu.bytecode;

  Cojen;

  Jdec;

  BCEL;

  ObjectWebASM;

  JClassLib;

  TroveClassFileAPI;

  Jiapi;

  ClassfileReader&Writer;

  JBET;

  Retroweaver;

  Jen;

  Soot

这里重点介绍一下ASM,因为下面将使用ASM框架进行Java字节码修改。

  ASM这个Java字节码操控框架能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,也可以在类被加载入 Java虚拟机之前动态改变类行为。Javaclass被存储在严格格式定义的.class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类 名称、方法、属性以及Java字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。下图对当前接触 常用的操作Java字节码框架进行了一个比较:

ASM的几个特性:

  1.JAVABased.

  ASM是基于JAVA的,即用JAVA实现的。

  2.Visitor模式.

  对于ASM来说,Javaclass被描述为一棵树;使用“Visitor”模式遍历整个二进制结构。

  3.复杂性低.易学易用.

  ASM提供了更为现代的编程模型,降低了操作Java字节码的复杂性,使用事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解Java类文件格式的所有细节:ASM框架提供了默认的“responsetaker”处理这一切。

  4.较高的性能

  对Java字节码进行操作的同时尽量减小的性能的损失(性能的损失是不可避免)。

  这里来介绍一下ASM组成及顺序图:

  Corepackage提供了一个读写、修改Javabytecode的API,并且为其它的package定义了依据。这个package对于生成Javabytecode、实现大多数的bytecode变换而言意义重大。

  Treepackage提供了Javabytecode的内存表示法。

  Analysispackage提供了基本的数据流分析和类型检查算法,它们将用于在treeoackage中存储Java方法bytecode。

  Commonspackage(包含在ASM2.0中)提供了一些常用的bytecode转换和用于简化bytecode生成的适配器。

  Utilpackage包含了一些帮助类和简单的bytecode验证器,它们将有助于开发或者测试。

  XMLpackage提供了一个用于在bytecode和XML之间进行转换的适配器,和一些允许使用XSLT定义bytecode转换的兼容SAX的适配器。

  顺序图:

***************************************************************************************

Demo

  这里我们来实现这样一个功能:在不能改变原代码功能的前提下,对于一个特定类的特定方法有没有被测试过,以HelloTaobao类中方法helloHeyun为例。

  类HelloTaobao:

  • publicclassHelloTaobao
  • {
  • publicvoidhelloHeyun()
  • {
  • System.out.println(“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”);
  • }
  • }

  主方法类:

  • publicclassMain
  • {
  • publicstaticvoidmain(String[]args)
  • {
  • HelloTaobaoht=newHelloTaobao();
  • ht.heyunHeyun();
  • }
  • }

  到这里,我们运行一下程序,会在Console输出字符串:“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”。

  下面我们来操作一下Java字节码文件HelloTaobao.class:

  1.想操作Java字节码的某一方法,需要继承ASM中的ClassAdapter和MethodAdapter

  2.定义类Generator来读入Java字节码文件HellTaobao,改造Java字节码文件,生成改造后的同名Java字节码文件HellTaobao,代码如下:

  • publicclassGenerator

  • {

  • publicstaticvoidmain(String[]args)throwsException

  • {

  • ClassReadercr=newClassReader(“HellTaobao”);

  • ClassWritercw=newClassWriter(ClassWriter.COMPUTE_MAXS);

  • ClassAdapterclassAdapter=newByteCodeClassHandler(cw);

  • cr.accept(classAdapter,ClassReader.SKIP_DEBUG);

  • byte[]data=cw.toByteArray();

  • Filefile=newFile(“HellTaobao.class”);

  • FileOutputStreamfout=newFileOutputStream(file);

  • fout.write(data);

  • fout.close();

  • }

  • }

3.ByteCodeClassHandler(自定义)类继承ClassAdapter(fromASM)

  4.ByteCodeClassHandler类中重写visitMethod,这个方法里去判断如果Java字节码文件HelloTaobao.class包含方法helloHeyun就调用ByteCodeMethodHandler类

  • publicclassByteCodeClassHandlerextendsClassAdapter

  • {

  • publicByteCodeClassHandler(ClassVisitorcv)

  • {

  • super(cv);

  • }

  • publicvoidvisit(intversion,intaccess,Stringname,Stringsignature,

  • StringsuperName,String[]interfaces)

  • {

  • super.visit(version,access,name,signature,superName,interfaces);

  • }

  • publicvoidvisitSource(Stringsource,Stringdebug)

  • {

  • super.visitSource(source,debug);

  • }

  • publicvoidvisitEnd()

  • {

  • }

  • @Override

  • publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,

  • Stringsignature,String[]exceptions)

  • {

  • MethodVisitormv=cv.visitMethod(access,name,desc,signature,

  • exceptions);

  • MethodVisitorwrappedMv=mv;

  • if(mv!=null)

  • {

  • //对于”helloHeyun”方法进行改造

  • if(name.equals(“helloHeyun”))

  • {

  • //使用自定义MethodVisitor,改写方法内容

  • wrappedMv=newByteCodeMethodHandler(mv);

  • }

  • }

  • returnwrappedMv;

  • }

  • }

  5.ByteCodeMethodHandler(自定义)继承MethodAdapter(fromASM),这里来做改造想要调用的自定义 方法,这里将调用类ControlByteCode(自定义)中的controlByteCodeByHeyun(自定义)方法

  • publicclassByteCodeMethodHandlerextendsMethodAdapter

  • {

  • publicByteCodeMethodHandler(MethodVisitormv)

  • {

  • super(mv);

  • }

  • publicvoidvisitCode()

  • {

  • visitMethodInsn(Opcodes.INVOKESTATIC,“ControlByteCode”,

  • “controlByteCodeByHeyun”,“()V”);

  • }

  • }

 6.ControlByteCode类的controlByteCodeByHeyun方法如下

  1. publicclassControlByteCode

  2. {

  3. publicstaticvoidcontrolByteCodeByHeyun()

  4. {

  5. System.out.println(“Thismethodhasalreadybeencovered.”);

  6. //TODOrealsecuritycheck

  7. }

  8. }

  7.这样,当运行完Generator类中main方法后,会生成一个和原Java字节码文件同名的文件(可以观察出,会比以前的文件大,当然也可以用MD5来确定是两个不同文件)。

  8.此时在运行主方法类Main,会发现在Console打印如下:

  1. Hello,ThisisHeyun’sinvestigationaboutcodecoverage!

  2. Thismethodhasalreadybeencovered.

  9.由此,可以看出,在原功能没有变化的前提下,通过改变Java字节码文件,我们实现了CodeCoverage的雏形。实际上,很多CodeCoverage工具(如Cobertura)都是运用此方法来实现Instrument(插装)的。

点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

限时发布!纯手打“RocketMQ笔记”

1JVM的内存区域布局java代码的执行步骤有三点java源码文件编译器字节码文件字节码文件JVM机器码机器码系统CPU执行JVM执行的字节码需要用类加载来载入;字节码文件可以来自本地文件,可以在网络上获取,也可以实时生成。就是说你可以跳过写java代码阶段,直接生成字节码交由JVM执行其中Jav

Java层逆向分析方法和技巧

本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言指正Java层逆向分析方法和技巧一、smali汇编1.Dalvik字节码java字节码、Dalvik字节码、机器码之间的关系?在Android上,Java代码首先经过编译器编译成

Python Challenge Level 18

初学Python,挑战一下流行的PythonChallenge,很不幸,卡在了18关~~被字符字节码之间的转换搞得焦头烂额,不过终于搞定了还是很happy的~~~主要的问题就是16进制形式的字符如何转成字节码(注意:不是encoding)如:\'89','50','4e','47','0d','0a','1a','0a','00

Java是如何实现跨平台的

一.Java是如何实现跨平台的1.我们编写的Java源码,编译后会生成一种.class文件,称为字节码文件2.Java虚拟机JVM就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。!(https:/

Java程序运行机制及开发环境

Java既是编译型语言,又是解释型语言java源文件首先需要通过javac编译生成后缀名为.class的字节码文件(与平台无关,只面向JVM),然后使用Java虚拟机将字节码解释成特定平台上的机器码运行。Java虚拟机JVM不同平台上的JVM不同,但是都提供了相同的接口。开发Java准备1.下