Java 如何使用ASM欺骗HelloWorld.scala?已加载到JVM但未找到?
我使用自定义类加载器将ASM与java结合使用,但在scala中做同样的事情有困难。首选的方法是什么 一个Java 如何使用ASM欺骗HelloWorld.scala?已加载到JVM但未找到?,java,scala,classloader,java-bytecode-asm,Java,Scala,Classloader,Java Bytecode Asm,我使用自定义类加载器将ASM与java结合使用,但在scala中做同样的事情有困难。首选的方法是什么 一个HelloScala.scala编译成两个类(HelloScala.class和HelloScala$.class)。我是否需要为这两种代码伪造字节码 我的代码似乎只塞进了一个HelloScala$.class,但没有公共构造函数或方法。我可以使用反射API和构造函数来访问,但有两个问题: 通过忽略HelloScala.class,我是否遗漏了任何有价值的东西 这是危险的还是难闻的 “正确”
HelloScala.scala
编译成两个类(HelloScala.class
和HelloScala$.class
)。我是否需要为这两种代码伪造字节码
我的代码似乎只塞进了一个HelloScala$.class,但没有公共构造函数或方法。我可以使用反射API和构造函数来访问,但有两个问题:
HelloScala.class
,我是否遗漏了任何有价值的东西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$
,为什么找不到它
谢谢 Scala使用许多技巧将其语义映射到JVM。因此,您将在字节码级别看到许多意想不到的事情。我认为您必须了解scala编译器如何使用Java结构
类由其名称和加载该类的类加载器(调用define方法的加载器)标识。您确定加载HelloScala的加载程序实际上也加载了HelloScala$吗?Scala使用了很多技巧将其语义映射到JVM。因此,您将在字节码级别看到许多意想不到的事情。我认为您必须了解scala编译器如何使用Java结构
类由其名称和加载该类的类加载器(调用define方法的加载器)标识。你确定加载HelloScala的加载程序实际上也加载了HelloScala$吗?这对我来说很有效,在每个类的“dump”文件中调用
dump()
方法来加载带有上下文的类加载程序而不是自定义类加载程序的类(因此,伪造的类可以访问与项目其余部分相同的类路径):
import java.lang.reflect.*;
公共类转储加载程序{
公共静态void main(字符串[]args)引发异常{
类c$=loadClass(“HelloScala$”,HelloScala$Dump.Dump());//首先加载“匿名”类
类c=loadClass(“HelloScala”,HelloScalDump.dump());//然后加载“real”类
试一试{
Method mainMethod=c.getMethod(“main”,String[].class);//获取“real”类的main方法
invoke(null,(Object)新字符串[]{});//并调用它来运行伪造的程序
}捕获(例外e){
e、 printStackTrace();
系统出口(1);
}
}
私有静态类loadClass(字符串类名,字节[]b){
//重写classDefine(因为它是受保护的)并定义类。
类clazz=null;
试一试{
//ClassLoader=ClassLoader.getSystemClassLoader();
ClassLoader=Thread.currentThread().getContextClassLoader();
Class cls=Class.forName(“java.lang.ClassLoader”);
方法Method=cls.getDeclaredMethod(“defineClass”,新类[]{String.Class,字节[].Class,int.Class,int.Class});
//受保护的方法invocaton
方法setAccessible(true);
试一试{
Object[]args=new Object[]{className,b,新整数(0),新整数(b.length)};
clazz=(类)方法.invoke(装入器,参数);
}最后{
方法.setAccessible(false);
}
}捕获(例外e){
e、 printStackTrace();
系统出口(1);
}
回击声;
}
}
这对我来说很有效,在每个类的“dump”文件中调用dump()
方法来加载带有上下文类加载器的类,而不是自定义类加载器的类(因此受欺骗的类可以访问与项目其余部分相同的类路径):
import java.lang.reflect.*;
公共类转储加载程序{
公共静态void main(字符串[]args)引发异常{
类c$=loadClass(“HelloScala$”,HelloScala$Dump.Dump());//首先加载“匿名”类
类c=loadClass(“HelloScala”,HelloScalDump.dump());//然后加载“real”类
试一试{
Method mainMethod=c.getMethod(“main”,String[].class);//获取“real”类的main方法
invoke(null,(Object)新字符串[]{});//并调用它来运行伪造的程序
}捕获(例外e){
e、 printStackTrace();
系统出口(1);
}
}
私有静态类loadClass(字符串类名,字节[]b){
//重写classDefine(因为它是受保护的)并定义类。
类clazz=null;
试一试{
//ClassLoader=ClassLoader.getSystemClassLoader();
ClassLoader=Thread.currentThread().getContextClassLoader();
Class cls=Class.forName(“java.lang.ClassLoader”);
方法Method=cls.getDeclaredMethod(“defineClass”,新类[]{String.Class,字节[].Class,int.Class,int.Class});
//受保护的方法invocaton
方法setAccessible(true);
试一试{
Object[]args=new Object[]{className,b,新整数(0),新整数(b.length)};
clazz=(类)方法.invoke(装入器,参数);
}最后{
方法.setAccessible(false);
}
}捕获(例外e){
e、 printStackTrace();
系统出口(1);
}
回击声;
}
}
“您确定加载HelloScala的加载程序也加载了HelloScala$吗?”“您确定加载HelloScala的加载程序也加载了HelloScala$吗?”--我有两个不同的DynamicClassLoader类实例。这两个类似乎都已加载(请参见答案中错误消息的前3行)。类是否需要由同一实例加载?使用DynamicClassLoader
的同一实例加载两个类在某种程度上是有效的。。。然后从scala库中找不到scalaObject
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;
}
}