Java中动态加载字节码的那些方法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java中动态加载字节码的那些⽅法
持续补充 ...
URLCLassLoader
ClassLoader#loader(URL[])远程加载class
URLCLassLoader实际上是我们平时默认使⽤的AppClassLoader的⽗类,所以,我们解释URLClassLoader的⼯作过程实际上就是在解释默认的Java类加载器的⼯作流程。

java 对路径的处理:
URL未以斜杠 / 结尾,则认为是⼀个JAR⽂件,使⽤ JarLoader 来寻找类,即为在Jar包中寻找.class⽂件
URL以斜杠 / 结尾,且协议名是 file ,则使⽤ FileLoader 来寻找类,即为在本地⽂件系统中寻找.class⽂件
URL以斜杠 / 结尾,且协议名不是 file ,则使⽤最基础的 Loader 来寻找类
也就是协议不是file且以 / 结尾,会使⽤Loader寻找类,最常见的是http协议。

可以通过这种⽅法直接加载远端的class⽂件,所以如果我们控制了⽬标Java ClassLoader的基础路径为⼀个http服务器,即可RCE
CLassLoader#definClass 直接加载字节码
⽆论加载远程class还是本地class或者jar⽂件,调⽤过程都是下⾯三个⽅法:
loadClass 的作⽤是从已加载的类缓存、⽗加载器等位置寻找类(这⾥实际上是双亲委派机制),在前⾯没有找到的情况下,执⾏ findClass
findClass 的作⽤是根据基础URL指定的⽅式来加载类的字节码,就像上⼀节中说到的,可能会在本地⽂件系统、jar包或远程http服务器上读取字节码,然后交给defineClass defineClass 的作⽤是处理前⾯传⼊的字节码,将其处理成真正的Java类
核⼼在defineClass,决定了如何将⼀段字节流转变成⼀个Java类,Java默认的ClassLoader#defineClass是⼀个native⽅法,逻辑在JVM的C语⾔代码中。

我们⽆法直接外部调⽤这些⽅法来加载字节码,但是有⼀些库中包含了部分代码完成了这个过程,我们可以利⽤这些库达到⽬的。

加载⽅式⼀: TemplatesImpl
⾮常常⽤的Java反序列化利⽤链组成部分,poc:
public static void main(String[] args) throws Exception {
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] code = base64Decoder.decodeBuffer("");
TemplatesImpl obj = new TemplatesImpl();
Field f1 = obj.getClass().getDeclaredField("__bytecodes");
f1.setAccessible(true);
f1.set(obj, new byte[][]{code});
Field f2 = obj.getClass().getDeclaredField("__name");
f2.setAccessible(true);
f2.set(obj, "HelloTemplatesImpl");
Field f3 = obj.getClass().getDeclaredField("__tfactory");
f3.setAccessible(true);
f3.set(obj, new TransformerFactoryImpl());
obj.newTransformer();
}
注意:
设置了三个属性: _bytecodes 、 _name 和 _tfactory 。

_bytecodes 是由字节码组成的数组;
_name 可以是任意字符串,只要不为null即可;
_tfactory 需要是⼀个 TransformerFactoryImpl 对象,因为emplatesImpl#defineTransletClasses()⽅法⾥有调⽤到tfactory.getExternalExtensionsMap(),如果是null会出错。

另外,TemplatesImpl 中对加载的字节码是有⼀定要求的:这个字节码对应的类必须是 .apache.xalan.internal.xsltc.runtime.AbstractTranslet的⼦类。

因此需要构造⼀个特殊的类。

加载⽅式⼆: BCELClassLoader
在java 8u251前可⽤。

使⽤的是.apache.bcel.internal.util.ClassLoader;
// 原⽣字节码转BCEL
JavaClass cls = Repository.lookupClass(exp.class);
String code = Utility.encode(cls.getBytes(), true);
System.out.println(code);
// 加载
new ClassLoader().loadClass("exp").newInstance();
待补充...。

相关文档
最新文档