【问题标题】:How do I use ASM to spoof a HelloWorld.scala? Loaded to JVM but not found?如何使用 ASM 来欺骗 HelloWorld.scala?加载到 JVM 但找不到?
【发布时间】:2012-12-21 13:16:31
【问题描述】:

我使用自定义类加载器将 ASM 与 java 结合使用,但在 scala 中执行相同操作时遇到了麻烦。首选的方法是什么?

HelloScala.scala 编译成 两个 类(HelloScala.class HelloScala$.class)。我需要欺骗两者的字节码吗?

我的代码似乎只填充了一个HelloScala$.class,但没有公共构造函数或方法。我可以使用 Reflection API 并使用 Constructor 来获取访问权限,但有两个问题:

  1. 忽略HelloScala.class,我是否错过了任何有价值的东西?
  2. 这是危险的还是有异味的?

“正确”的方式可能是在HelloScala 中调用公共的、静态的main,但我得到这个错误:

[Loaded HelloScala from __JVM_DefineClass__]
[Loaded scala.ScalaObject from file:/home/julianpeeters/asm-scala-example/lib/scala-library-2.9.1.jar]
[Loaded HelloScala$ from __JVM_DefineClass__]
[Loaded sun.reflect.NativeMethodAccessorImpl from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
[Loaded sun.reflect.DelegatingMethodAccessorImpl from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
[Loaded java.lang.reflect.InvocationTargetException from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at HelloScalaDump.main(HelloScalaDump.java:41)
Caused by: java.lang.NoClassDefFoundError: HelloScala$
    at HelloScala.main(Unknown Source)
    ... 5 more
Caused by: java.lang.ClassNotFoundException: HelloScala$
    at java.lang.ClassLoader.findClass(ClassLoader.java:373)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    ... 6 more

HelloScala$ 似乎正在加载,为什么找不到呢?

谢谢!

【问题讨论】:

  • “假设您不想在项目目录中有多个无用的文件...” -- 不,我不介意多个文件。我的问题实际上是我没有代表这些类的 any .java 或 .class 文件,因此没有任何东西可以放入 jar 中。相反,我试图在运行时动态定义类(基于仅在运行时知道的数据)。

标签: java scala classloader java-bytecode-asm


【解决方案1】:

Scala 使用许多技巧将其语义映射到 JVM。因此,您会在字节码级别看到很多意想不到的事情。我认为您必须接受它并深入了解 scala 编译器如何使用 Java 结构。

一个类由它的名称和加载该类的类加载器(调用define方法的加载器)来标识。你确定加载 HelloScala 的加载器实际上也加载了 HelloScala$ 吗?

【讨论】:

  • "你确定加载 HelloScala 的加载器实际上也加载了 HelloScala$ 吗?"
  • “你确定加载 HelloScala 的加载器实际上也加载了 HelloScala$ 吗?” -- 我有两个不同的 DynamicClassLoader 类实例。两个类似乎都已加载(请参阅答案中错误消息的前 3 行)。类是否需要由同一个实例加载?
  • 使用DynamicClassLoader 的相同实例加载两个类工作,直到某一点......然后无法从scala-library 找到scalaObject,我意识到我不能扩展,我必须获取并覆盖 ContextClassLoader 的方法。感谢您让我指出正确的方向。
【解决方案2】:

这对我有用,在每个类的“转储”文件中调用 dump() 方法以使用上下文的 ClassLoader 而不是自定义类加载器加载类(因此被欺骗的类可以访问与其余类相同的类路径项目):

import java.lang.reflect.*;

public class DumpLoader {

  public static void main(String[] args) throws Exception {
     Class<?> c$ = loadClass("HelloScala$", HelloScala$Dump.dump()); //First load the "anonymous" class
     Class<?> c = loadClass("HelloScala", HelloScalaDump.dump());   //Then load the "real" class
     try {
       Method mainMethod = c.getMethod("main", String[].class);  //Get the main method of the "real" class
       mainMethod.invoke(null, (Object) new String[]{});        //and invoke it to run the spoofed program
     } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
     }
  }

  private static Class loadClass(String className, byte[] b) {
    //override classDefine (as it is protected) and define the class.
    Class<?> clazz = null;
    try {
     // ClassLoader loader = ClassLoader.getSystemClassLoader();
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Class<?> cls = Class.forName("java.lang.ClassLoader");
      Method method = cls.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });

      // protected method invocaton
      method.setAccessible(true);
      try {
        Object[] args = new Object[] { className, b, new Integer(0), new Integer(b.length)};
        clazz = (Class) method.invoke(loader, args);
      } finally {
        method.setAccessible(false);
      }
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
    return clazz;
  }

}

【讨论】:

    猜你喜欢
    • 2013-05-03
    • 1970-01-01
    • 2021-07-13
    • 2013-06-21
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    相关资源
    最近更新 更多