AviatorScript之获取动态生成的字节码

在ASMCodeGenerator.class中的getResult方法,会获得bytes数组,最终会根据这个字节数组生成class类,想要知道AS生成的字节码文件,就需要拦截下这个bytes数组。
注意:在Aviator初始化instance时也会动态生成字节码,为了防止找到的bytes数组并不是我们自己的,应等其初始化完毕后,再打断点调试该方法。(低版本的Aviator初始化instance时不会生成字节码)


  /*
   * (non-Javadoc)
   *
   * @see com.googlecode.aviator.code.CodeGenerator#getResult()
   */
  @Override
  public Expression getResult(final boolean unboxObject) {
    end(unboxObject);
    //打断点调试这个方法,查看到bytes数组  
    byte[] bytes = this.classWriter.toByteArray();
    try {
      Class<?> defineClass =
          ClassDefiner.defineClass(this.className, Expression.class, bytes, this.classLoader);
      Constructor<?> constructor =
          defineClass.getConstructor(AviatorEvaluatorInstance.class, List.class, SymbolTable.class);
      ClassExpression exp = (ClassExpression) constructor.newInstance(this.instance,
          new ArrayList<String>(this.varTokens.keySet()), this.symbolTable);
      exp.setLambdaBootstraps(this.lambdaBootstraps);
      exp.setFuncsArgs(this.funcsArgs);
      return exp;
    } catch (ExpressionRuntimeException e) {
      throw e;
    } catch (Throwable e) {
      if (e.getCause() instanceof ExpressionRuntimeException) {
        throw (ExpressionRuntimeException) e.getCause();
      }
      throw new CompileExpressionErrorException("define class error", e);
    }
  }

找到调试中界面中的bytes数组,点击这个计算器模样的图标
在这里插入图片描述
在该界面编写代码将字节数组打印出来,点击Evaluate
在这里插入图片描述

代码如下:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
    if (i != 0) {
        sb.append(",");
    }
    sb.append(bytes[i]);
}
return sb.toString();

复制result中的结果
在这里插入图片描述

编写代码将字节数组输出为文件,文件的路径最好在该项目的resource目录下,然后将文件的后缀修改成.class文件,在idea中就可以查看该class文件的内容

/**
* 如果文件名已经存在,那么新创建的文件名就会添加 _2来区分,例如test.class, test_2.class
* @param dirPath 文件夹路径名
* @param fileName 文件名
* @param data 字节数组
*/
private static void exportByteArrayToFile(String dirPath, String fileName, byte[] data) {
    try {
        File dir = new File(dirPath);
        if(!dir.isDirectory()) {
            dir.mkdirs();
        }
        String pathName = dirPath + "\\" + fileName;
        File file = new File(pathName);
        if (!file.exists()) {
            System.out.println(pathName + "文件不存在,准备新建...");
            file.createNewFile();
        } else {
            try {
                int maxLoop = 9999;
                int reNameSuffixId = 2;
                String[] cc = fileName.split("\\.");
                do {
                    Long fileLen = file.length();
                    byte[] fileContent = new byte[fileLen.intValue()];
                    FileInputStream in = new FileInputStream(file);
                    in.read(fileContent);
                    in.close();
                    if(!Arrays.equals(fileContent, data)) {
                        fileName = cc[0] + "_" + reNameSuffixId + "." + cc[1];
                        pathName = dirPath + "\\" + fileName;
                        file = new File(pathName);
                        if (!file.exists()) {
                            System.out.println("准备创建新文件:" + pathName);
                            file.createNewFile();
                            break;
                        }
                    } else {
                        System.out.println("已存在相同文件");
                        break;
                    }
                    reNameSuffixId++;
                    maxLoop--;
                } while (maxLoop > 0);
            } catch (Exception e) {
                System.err.println("文件读取异常, path: " + pathName);
                e.printStackTrace();
            }
        }
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(data);
        fos.close();
    } catch (Exception e) {
        System.err.println("文件写出异常...");
        e.printStackTrace();
    }
}

之后可以通过反编译工具,将字节码生成Java文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值