Skip to content

Latest commit

 

History

History
52 lines (42 loc) · 3.88 KB

File metadata and controls

52 lines (42 loc) · 3.88 KB

Groovy表达式字符串(GroovyConvert)

  • 类别:common 别名:— 优先级:未设置(null)
  • 作者:—
  • 依赖groovy(目标运行时具备 groovy.lang.GroovyShell 等可对字符串求值的 Groovy 组件;内嵌逻辑再借道 JDK 的 JS 引擎)

作用

「表达式转换」构件:把内层产出的 byte[] 字节码封装成一段 可直接求值的 Groovy 表达式字符串。表达式被 Groovy 求值时经 JDK 内置 JS 引擎 eval 一段 JS,用 sun.misc.Unsafe.defineAnonymousClass 加载字节码执行。是「字节码 → Groovy 表达式」的适配层,供以 Groovy 求值的上游 sink 消费。

链接标签

  • 入口 tagsGroovy_ExprExpression —— 声明产物是 Groovy / 通用表达式字符串,可被 nextTagsGroovy_Expr 的上游 sink(如 GroovyShellRef)承接。
  • 衔接 nextTagsBytecodeConvertTag —— 内层须为 BytecodeConvert 类构件,提供 byte[] 字节码。
  • excludes:无。

源码剖析

public static String template =
  "Class.forName(\"javax.script.ScriptEngineManager\").newInstance()" +
  ".getEngineByName(\"JavaScript\").eval(\"" + JsConvert.jsTemplate + "\")";

private String getObject(byte[] bytecode) {
    String bytecodeB64 = Base64.encodeBase64String(bytecode);
    return String.format(template, bytecodeB64);
}

逐段解释:

  • template 是一句 Groovy 表达式:Class.forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval(...)。与 Groovy2Convert 不同,这里 没有 @ASTTest 注解包裹——它需要被真正「求值/执行」而非仅编译,故用于 GroovyShell.evaluate 一类运行期注入点。
  • 借道 JDK 内置 JS 引擎(Nashorn/Rhino)执行内嵌 JS,JS 体直接复用 JsConvertJsConvert.jsTemplate(编译期字符串拼接),该 JS 用 Unsafe.defineAnonymousClass 从 Base64 字节码定义匿名类并实例化。整体是「Groovy 求值 → JS 引擎 → Unsafe 定义类」的跳板。
  • String.format(template, bytecodeB64) 唯一的 %s 来自 jsTemplatevar s='%s',填入 Base64 字节码。
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    return this.getObject((byte[]) chain.doCreate(context));
}

invoke 只做一件事:驱动内层拿 byte[],转成 Groovy 表达式字符串返回。头部 Could not load ... Base64 为缺依赖的正常反编译提示。

参数(@Param)

本类无 @Param。字节码由内层 BytecodeConvert 提供;template 与所用 JsConvert.jsTemplate 均为写死字段。

适用版本与原理要点

  • 因内嵌 JS 复用 JsConvert.jsTemplateUnsafe.defineAnonymousClass),受其版本约束:目标需可用 JS 引擎(JDK 8~14 的 Nashorn,JDK 15 起被移除),且 defineAnonymousClass 在高版本 JDK 受限。
  • Groovy2Convert 的关键区别:本类是「运行期求值」型(无 @ASTTest),Groovy2Convert 是「编译期触发」型。选用取决于上游 sink 是求值还是编译源码。
  • 在预设链「Groovy 脚本执行」中作为字节码→表达式的中间层,由 GroovyShellRef 求值触发。

所属预设链

关联