java-字节码
什么是字节码
其实仅仅指的是Java虚拟机执行使用的一类指令,通常被存储在.class文件中
更广义上来说,所有能恢复成一个类并在jvm虚拟机里加载的字节序列,都在我们的探讨范围内。
利用URLClassLoader加载远程class文件
ClassLoader:
是用来加载字节码文件最基础的方法,是一个加载器,告诉java虚拟机如何加载这个类,java默认的ClassLoader就是根据类名来加载类,,并且类名是类完整路径
,如java.lang.Runtime
。
URLClassLoader
URLClassLoader
实际上是我们平时默认使用的AppClassLoader
的父类,所以,URLClassLoader
=java类加载器的工作流程
正常情况下,Java会根据配置项sun.boot.class.path
和java.class.path
中列举到的基础路径(这些路径是经过处理后的java.net.URL
类)来寻找.class文件来加载,而这个基础路径有三种情况:
- URL未以斜杠
/
结尾,则认为是一个JAR文件,使用JarLoader
来寻找类,即为在Jar包中寻找.class文件 - URL以斜杠
/
结尾,且协议名是file
,则使用FileLoader
来寻找类,即为在本地文件系统中寻找.class文件 - URL以斜杠
/
结尾,且协议名不是file
,则使用最基础的Loader
来寻找类。
java的URL支持哪些协议
JAVA默认提供了对file,ftp,gopher,http,https,jar,mailto,netdoc协议的支持
Loader
寻找类
loader寻找类,最常见的情况就是http
协议。
import java.net.URL; |
利用ClassLoader#defineClass直接加载字节码
java加载远程class文件/本地class或jar文件
ClassLoader#loadClass
——> ClassLoader#findClass
——>ClassLoader#defineClass
其中:
Loadclass
的作用是从已加载的类缓存,父加载器等位置寻找类(双亲委派机制)findClass
的作用是根据基础URL指定的方式来加载类的字节码,可能会在本地文件系统、jar包、或远程http服务器上读取字节码,然后交给defineClass
defineClass
的作用是处理前面传入的字节码,将其处理为真正的java类
defineClass可以从byte[]还原出一个Class对象
使用defineClass
直接加载字节码
import java.lang.reflect.Method; |
使用TemplatesImpl加载字节码
TransletClassLoader
TransletClassLoader来自com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
其中重写了defineClass
方法
Class defineClass(final byte[] b) { |
在重写的这个方法中,由于其没有显式声明作用域,,所以其作用域为default,所以也就是说这里的defineClass
由其父类的protected类型变成了一个default类型的方法,可以被类外部调用。
而TransletClassLoader#defineClass()
向前追溯调用链为
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass() |
利用newTransformer()
构造poc:
public static void main(String[] args) throws Exception{ |
其中,setFieldValue
方法来设置私有属性,其中_bytecodes、_name和_tfactory._bytecodes是由字节码组成的数组;_name可以是任意字符串,只要不为null即可。
_tfactory需要是一个TransformerFactoryImpl
对象,因为TemplatesImpl#defineTransletClasses()
方法里有调用到\_tfactory.getExternalExtensionsMap()
如果是null会出错
TemplatesImpl
中对加载的字节码有一定要求即,这个字节码对应的类必须是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
的子类
所以,我们需要构造一个特殊的类
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; |
它继承了AbstractTranslet
类,并在构造函数里插入Hello的输出,将其编译成字节码,即可被TemplatesImpl
执行
利用BCEL ClassLoader加载字节码
package com.govuln; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.Repository; |