Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以从java.*包中插入类_Java_Bytecode_Instrumentation_Java Bytecode Asm - Fatal编程技术网

是否可以从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,“”)加载代理会怎么样?相同。它将由目标机器的系统类加载器执行。