我想知道哪些类我不能通过使用字节码转换和java代理来拦截和操作。
Q1:我知道并非所有类都可以在加载时重新定义(更改,操作)以及以后。这些类包括非本机方法,但由硬连线本机实现(如某些Spring和System方法)取代。我想知道在加载后一个或两个进行加载和/或重新定义的字节代码操作的哪些类是不受限制的?
Q2:对于最近的JDK / JRE版本,这组不能改变的类型和方法是否已经改变了?
问题3:如果我通过改变默认的类加载器操作JVM(没有花哨的改变),我是否能够增加可重新定义的类型数量以及为什么和为什么?
[附加]
我做了很多研究,甚至自己经营了一个代理人,看看会发生什么。基本上有一些课程缺失。在类路径中加载所有JRE类之后,可以看到在代理机制启动之前加载了一些缺少的类。这通常是因为即使代理需要运行类,这些类也需要类....但是我想知道什么是一个永远无法改变的类,为什么这样以及可以攻击JVM会让你更进一步。
我尝试基本上进行JVM / Java操作,以便了解所有内容,并为我的工具带添加一些不错的监控工具。此外,我正在为我的大项目实施一个类重新加载解决方案。
答案 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_51
和1.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端类加载器上定义它们:
...
<强>抛出:强>
...
SecurityException - 如果尝试将此类添加到包含由除此类(未签名)之外的其他证书集签名的类的包,或者名称以“java。”开头。