是否可以从java.*包中插入类
是否可以插入是否可以从java.*包中插入类,java,bytecode,instrumentation,java-bytecode-asm,Java,Bytecode,Instrumentation,Java Bytecode Asm,是否可以插入java.*包的类 我想替换java.awt.print.PrinterJob.printDialog(PrintRequestAttributeSet)的方法体,使其始终返回true 当使用java.*定义一个新类时,我得到了SecurityException:禁止的包名:java.awt.print。显然,之所以会发生这种情况,是因为我试图在包的名称中使用java.定义类 那么,有没有一种方法可以绕过这种安全检查,或者以不同的方式解决这个问题呢 另外,我还尝试重新定义java.a
java.*
包的类
我想替换java.awt.print.PrinterJob.printDialog(PrintRequestAttributeSet)
的方法体,使其始终返回true
当使用java.*
定义一个新类时,我得到了SecurityException:禁止的包名:java.awt.print
。显然,之所以会发生这种情况,是因为我试图在包的名称中使用java.
定义类
那么,有没有一种方法可以绕过这种安全检查,或者以不同的方式解决这个问题呢
另外,我还尝试重新定义java.awt.printerjob
系统属性,以便使用我自己的printerjob
实现。但我失败了,因为找不到我的班级。我没有找到实际的PrinterJob
类加载器来加载我的类
@Test public void testInstrumentationOfJavaClasses() throws Exception
{
// replace printDialog(attrs) so that it always returns true
String typeName = "java.awt.print.PrinterJob";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
MethodReplacer methodReplacer = new MethodReplacer(cw, "printDialog", "(Ljavax/print/attribute/PrintRequestAttributeSet;)Z");
ClassReader classReader = createClassReader(typeName);
classReader.accept(methodReplacer, ClassReader.EXPAND_FRAMES);
loadClass(cw.toByteArray(), typeName);
// the actual call of PrinterJob which as I expect to always return "true"
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(PRINTABLE);
PrintRequestAttributeSet printerSettings = new HashPrintRequestAttributeSet();
if (printJob.printDialog(printerSettings))
printJob.print(printerSettings);
}
public static class MethodReplacer extends ClassVisitor implements Opcodes
{
private final String methodName;
private final String methodDefenition;
public MethodReplacer(ClassVisitor classVisitor, String methodName, String methodDescr)
{
super(ASM5, classVisitor);
this.methodName = methodName;
this.methodDefenition = methodDescr;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
if (methodName.equals(name) && methodDefenition.equals(desc))
{
System.out.println("visitMethod(" + name + ")");
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, name, desc, null, new String[]{"java/awt/HeadlessException"});
mv.visitCode();
mv.visitInsn(ICONST_1);
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
return mv;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static Class loadClass(byte[] bytecode, String typeName) throws Exception
{
ClassLoader baseClassLoader = TestPrint.class.getClassLoader();
Class<?>[] types = new Class<?>[]{String.class, byte[].class, int.class, int.class};
Method m = ClassLoader.class.getDeclaredMethod("defineClass", types);
m.setAccessible(true);
Object[] args = new Object[]{null, bytecode, 0, bytecode.length};
Class definedClass = (Class<?>) m.invoke(baseClassLoader, args);
return definedClass;
}
@Test public void testInstrumentationOfJavaClasses()引发异常
{
//替换printDialog(attrs),使其始终返回true
字符串typeName=“java.awt.print.PrinterJob”;
ClassWriter cw=新的ClassWriter(ClassWriter.COMPUTE\u FRAMES);
MethodReplacer MethodReplacer=newMethodReplacer(cw,“printDialog”,“Ljavax/print/attribute/PrintRequestAttributeSet;)Z);
ClassReader ClassReader=createClassReader(typeName);
accept(methodReplacer、classReader.EXPAND_FRAMES);
loadClass(cw.toByteArray(),typeName);
//PrinterJob的实际调用,我希望它总是返回“true”
PrinterJob printJob=PrinterJob.getPrinterJob();
printJob.setPrintable(可打印);
PrintRequestAttributeSet printerSettings=新的HashPrintRequestAttributeSet();
if(printJob.printDialog(printerSettings))
printJob.print(打印机设置);
}
公共静态类MethodReplacer扩展类Visitor实现操作码
{
私有最终字符串methodName;
私有最终字符串方法定义;
public MethodReplacer(ClassVisitor ClassVisitor,String methodName,String methodDescr)
{
超级(ASM5,类访客);
this.methodName=methodName;
this.methoddefention=methodDescr;
}
@凌驾
public方法访问者访问方法(int访问、字符串名称、字符串描述、字符串签名、字符串[]异常)
{
if(methodName.equals(name)和&methoddefention.equals(desc))
{
System.out.println(“visitMethod(“+name+”));
MethodVisitor mv=cv.visitMethod(ACC_PUBLIC,name,desc,null,新字符串[]{“java/awt/HeadlessException”});
mv.visitCode();
mv.visitInsn(ICONST_1);
mv.visitInsn(IRETURN);
mv.visitmax(1,1);
mv.visitEnd();
返回mv;
}
返回super.visitMethod(访问、名称、描述、签名、异常);
}
}
私有静态类loadClass(字节[]字节码,字符串类型名)引发异常
{
ClassLoader baseClassLoader=TestPrint.class.getClassLoader();
类[]类型=新类[]{String.Class,byte[].Class,int.Class,int.Class};
方法m=ClassLoader.class.getDeclaredMethod(“defineClass”,类型);
m、 setAccessible(true);
Object[]args=新对象[]{null,字节码,0,字节码.length};
类definedClass=(类)m.invoke(baseClassLoader,args);
返回定义类;
}
请看一下。您可以通过不同的方式侵入java.*
命名空间:
java.*
前缀创建新类,将这些文件捆绑到jar中,并将这些类附加到引导类装入器中。这些类随后可从引导类加载器(即全局)获得ClassFileTransformer
。对于某些引导类,这允许在加载类之前更改类的字节码。设置代理时不需要这些类,这一点很重要。对于AWT类,这应该可以正常工作java.*
命名空间的类。即使在加载某些类之后,instrumentation API也允许对它们进行重新传输/重新定义我编写了一个名为的库,如果您不想手动编写Java代理,它将使这种工具的使用变得更容易。谢谢您的回答。我认为这个API会对我有所帮助。我会尝试一下并接受你的答案。或者在出现问题时寻求帮助=)我注册了ClassFileTransformer并成功地重新定义了PrinterJob.getPrinterJob,使其返回MyPrinterJob。正如您所说,在代理中重新定义PrinterJob之前,我无法使用它,因此我希望从主库(启动代理的库)加载MyPrinterJob类。我的ASM代码调用Class.forName(“My.print.MyPrinterJob”).newInstance(),但发生java.lang.ClassNotFoundException。可以访问main的项目类加载器吗?ClassFileTransformer允许访问插入指令的类的类加载器。Java代理始终由系统类加载器加载。如果我通过VirtualMachine.attach(pid).loadAgent(jarPath,“”)加载代理会怎么样?相同。它将由目标机器的系统类加载器执行。