Java:代理或MBean无法转换哪些类?

时间:2015-10-03 16:27:36

标签: java bytecode bytecode-manipulation

我想知道哪些类我不能通过使用字节码转换和java代理来拦截和操作。

Q1:我知道并非所有类都可以在加载时重新定义(更改,操作)以及以后。这些类包括非本机方法,但由硬连线本机实现(如某些Spring和System方法)取代。我想知道在加载后一个或两个进行加载和/或重新定义的字节代码操作的哪些类是不受限制的?

Q2:对于最近的JDK / JRE版本,这组不能改变的类型和方法是否已经改变了?

问题3:如果我通过改变默认的类加载器操作JVM(没有花哨的改变),我是否能够增加可重新定义的类型数量以及为什么和为什么?

[附加]

我做了很多研究,甚至自己经营了一个代理人,看看会发生什么。基本上有一些课程缺失。在类路径中加载所有JRE类之后,可以看到在代理机制启动之前加载了一些缺少的类。这通常是因为即使代理需要运行类,这些类也需要类....但是我想知道什么是一个永远无法改变的类,为什么这样以及可以攻击JVM会让你更进一步。

我尝试基本上进行JVM / Java操作,以便了解所有内容,并为我的工具带添加一些不错的监控工具。此外,我正在为我的大项目实施一个类重新加载解决方案。

1 个答案:

答案 0 :(得分:0)

好吧,我使用

做了一个简单的测试
public static void premain(String agentArgs, Instrumentation inst) {
  System.out.println(System.getProperty("java.version"));
  System.out.println(inst.isRedefineClassesSupported());
  int num=0;
  for(Class<?> clazz:inst.getAllLoadedClasses())
    if(!clazz.isArray() && !inst.isModifiableClass(clazz)) {
      System.out.println("not modifiable "+clazz);
      num++;
    }
  System.out.println((num==0? "all classes are": num+" classes are not")+" transformable");
}

1.7.0_511.8.0_60打印出来:

true
all classes are transformable

换句话说,你的第一个假设是错误的。关于哪些类可以在以后重新定义没有限制。当然,当你重新定义基本课程时,你必须要小心谨慎,以避免搞砸一切。

当您假设在java代理启动时,已经加载了无法进行加载时转换的类,这是正确的。请注意,您可以使用上面代码getAllLoadedClasses()中使用的相同方法来了解已加载的类。在我的设置中,它返回超过400个非数组类。

您可以做出的唯一安全假设是,确切地未指定确切的集合,否则,不可能更改JVM引导过程的实现。这将是一个非标准特征强加的严格限制......

操作系统类加载器不会改变任何东西,因为这些类不是由系统类加载器加载,而是由引导加载程序加载。这是类加载器,它表示为null,因为它不能由Java对象实例表示。

您可以通过以下方式验证:

public static void premain(String agentArgs, Instrumentation inst) {
  System.out.println(System.getProperty("java.version"));
  System.out.println(inst.isRedefineClassesSupported());
  int num=0;
  for(Class<?> clazz:inst.getAllLoadedClasses())
    if(clazz.getClassLoader()!=null) {
      System.out.println("already loaded "+clazz);
      num++;
    }
  System.out.println(num+" non-bootstrap class(es) loaded");
}

在我的设置中,它打印出来:

1.8.0_60
true
already loaded class ExperimentalAgent
1 non-bootstrap class(es) loaded

显示通过系统类加载器加载的唯一类是代理本身,所有其他已存在的类都由引导加载程序加载和定义。

当系统类加载器加载的类包含对核心类的引用时,它们通过询问系统类加载器来解析,但是,除了委托给它的父加载器以便以兼容的方式解析它们之外别无选择。否则,重新定义的类被认为是与引导加载程序中解析的类不同的类(即,当核类引用彼此时)。请注意,对于限定名称以java.开头的类,无论如何都会尝试在Java端类加载器上定义它们:

  

ClassLoader.defineClass

     

...

     

<强>抛出:
  ...
  SecurityException - 如果尝试将此类添加到包含由除此类(未签名)之外的其他证书集签名的类的包,或者名称以“java。”开头。