Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manupulating byte code generated from ASM

I want to generate byte code for a java class only with the public or protected fields, constructors, and methods.

I am trying with the below code, but I don't know is it the correct approach?

Client code:

String sourceFileName = file.getName();
ClassReader reader = new ClassReader(file.getContents());
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
reader.accept(adapter, 0);
byte[] content = writer.toByteArray();
// we can use content to print in .class file

Adapator code:

private class JavaStubClassAdapter extends ClassVisitor {
    private final String sourceFileName;

    /**
     * @param writer
     * @param sourceFileName
     */
    public JavaStubClassAdapter(ClassWriter writer, String sourceFileName) {
        super(Opcodes.ASM7, writer);
        this.sourceFileName = sourceFileName;
    }

    @Override
    public void visitSource(String source, String debug) {
        super.visitSource(this.sourceFileName, null);
    }

    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
        if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
            return super.visitField(access, name, descriptor, signature, value);
        }
        return null;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
            String[] exceptions) {
        if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
            return super.visitMethod(access, name, descriptor, signature, exceptions);
        }
        return null;
    }
}
like image 793
Shashwat Avatar asked Jun 19 '20 06:06

Shashwat


People also ask

What is bytecode manipulation?

Bytecode is the instruction set of the Java Virtual Machine (JVM), and all languages that run on the JVM must eventually compile down to bytecode. Bytecode is manipulated for a variety of reasons: Program analysis: find bugs in your application.

What is ASM bytecode?

ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify existing classes or to dynamically generate classes, directly in binary form.

How do you use ASM?

How do I start using ASM? If you want to use ASM to generate classes from scratch, write a Java source file that is representative of the classes you want to generate, compile it(*), and then run the ASMifier on the compiled class to see the Java source code that generates this class with ASM.

What does ASM stand for in Java?

ASM simply stands for ASMifier tool.


1 Answers

Below code work for me

Client code this method has org.eclipse.core.resources.IFile

        ClassReader reader = new ClassReader(file.getContents());
        if (!isAccessPermited(reader.getAccess())) {
            return new byte[0];
        }
        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
        reader.accept(adapter, 0);
        return writer.toByteArray();

Helper methods

    private static boolean isAccessPermited(final int access) {
        boolean isEnumAcc = (access & Opcodes.ACC_ENUM) == 0 ? false : true;
        boolean isPublicAcc = (access & Opcodes.ACC_PUBLIC) == 0 ? false : true;
        boolean  isProtectedAcc = (access & Opcodes.ACC_PROTECTED) == 0 ? false : true;
        if (isPublicAcc || isProtectedAcc || isEnumAcc) {
            return true;
        }
        return false;
    }

    private static boolean isFinalAccess(final int access) {
        return (access & Opcodes.ACC_FINAL) != 0;
    }

Adapator code

    private static class JavaStubClassAdapter extends ClassVisitor {
        private final String sourceFileName;

        /**
         * @param writer
         *            ClassVisitor
         * @param sourceFileName
         *            String
         */
        public JavaStubClassAdapter(ClassVisitor writer, String sourceFileName) {
            super(Opcodes.ASM7, writer);
            this.sourceFileName = sourceFileName;
        }

        @Override
        public void visitSource(String source, String debug) {
            super.visitSource(this.sourceFileName, null);
        }

        @Override
        public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
            if (isAccessPermited(access)) {
                switch (descriptor) {
                case "Ljava/lang/String;":  //$NON-NLS-1$
                    if (isFinalAccess(access)) {
                        return super.visitField(access, name, descriptor, signature, "");
                    }
                    return super.visitField(access, name, descriptor, signature, null);
                case "Z":                   //$NON-NLS-1$
                    return super.visitField(access, name, descriptor, signature, Boolean.FALSE);
                case "C":                   //$NON-NLS-1$
                case "B":                   //$NON-NLS-1$
                case "S":                   //$NON-NLS-1$
                case "I":                   //$NON-NLS-1$
                case "J":                   //$NON-NLS-1$
                case "D":                   //$NON-NLS-1$
                case "F":                   //$NON-NLS-1$
                    if (isFinalAccess(access)) {
                        return super.visitField(access, name, descriptor, signature, Integer.valueOf(0));
                    }
                    return super.visitField(access, name, descriptor, signature, null);
                case "Ljava/lang/Object":   //$NON-NLS-1$
                    return super.visitField(access, name, descriptor, signature, null);

                default:
                    return super.visitField(access, name, descriptor, signature, null);
                }
            }
            return null;
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
                String[] exceptions) {
            if (isAccessPermited(access)) {
                MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
                return new JavaClassEmptyMethodVistor(mv, Type.getReturnType(descriptor));
            }
            return null;
        }

        @Override
        public void visitInnerClass(String name, String outerName, String innerName, int access) {
            if (isAccessPermited(access)) {
                super.visitInnerClass(name, outerName, innerName, access);
            }
        }
    }
    
    private static class JavaClassEmptyMethodVistor extends MethodVisitor {
        private final MethodVisitor visitor;

        private final Type returnType;

        public JavaClassEmptyMethodVistor(MethodVisitor methodVisitor, Type type) {
            super(Opcodes.ASM7, methodVisitor);
            this.visitor = methodVisitor;
            this.returnType = type;
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
            // Do nothing
        }

        @Override
        public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
            // Do nothing
        }

        @Override
        public void visitInsn(int opcode) {
            if (returnType == Type.INT_TYPE || returnType == Type.FLOAT_TYPE
                    || returnType == Type.LONG_TYPE || returnType == Type.DOUBLE_TYPE
                    || returnType == Type.CHAR_TYPE || returnType == Type.BYTE_TYPE ) {
                visitor.visitIntInsn(Opcodes.BIPUSH, 0);
                visitor.visitInsn(Opcodes.IRETURN);
            } else if (returnType == Type.BOOLEAN_TYPE) {
                visitor.visitInsn(Opcodes.ICONST_0);
                visitor.visitInsn(Opcodes.IRETURN);
            } else if (returnType == Type.VOID_TYPE) {
                visitor.visitInsn(Opcodes.RETURN);
            } else {
                visitor.visitInsn(Opcodes.ACONST_NULL);
                visitor.visitInsn(Opcodes.ARETURN);
            }
        }

        @Override
        public void visitIincInsn(int var, int increment) {
            // Do nothing
        }

        @Override
        public void visitLineNumber(int line, Label start) {
            // Do nothing
        }

        @Override
        public void visitLabel(Label label) {
            // Do nothing
        }

        @Override
        public void visitTypeInsn(int opcode, String type) {
            // Do nothing
        }

        @Override
        public void visitJumpInsn(int opcode, Label label) {
            // Do nothing
        }

        @Override
        public void visitLdcInsn(Object value) {
            // Do nothing
        }

        @Override
        public void visitVarInsn(int opcode, int var) {
            // Do nothing
        }

        @Override
        public void visitMaxs(int maxStack, int maxLocals) {
            visitor.visitMaxs(0, 0);
        }

        @Override
        public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
            // Do nothing
        }

        @Override
        public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
            // Do nothing
        }

        @Override
        public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
            // Do nothing
        }

        @Override
        public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
            // Do nothing
        }
    }
like image 104
Shashwat Avatar answered Oct 23 '22 10:10

Shashwat