0

I'm fighting with ASM since 5 days and I can't get with the solution to my problem. The requirement is to get all values passed as argumentsfrom a method call. I know that there are a lot of tools to accomplish this. I went for ASM (I don't know if I took the right decision)

For example, if I have these methods

     public void test2(String a, int b , String c, boolean ba, long d, String e){

      }
     public String giveMeAString(){
        return "oneString";
     }

     public String giveMeAnotherString(){
       return "anotherString";
     }

     public void test(){
         test2("firstParameter", 2907, giveMeAString(),true, 1992, giveMeAnotherString());
     }

I would like to save ["firstParameter",2907, "oneString", true, 1992, "anotherString"]

I have already read these topics:

How to get the return value in asm?

Java method parameters values in ASM

Tracing method invocation arguments in bytecode using ASM

get function arguments values using java asm for bytecode instrimentation

Which explain about putting the arguments to the local variables, but how can I access them?

How can I obtain the VALUES of that arguments? I don't understand how can I get that args to.. I dont know, print them for example. Any idea? Once they are in the stack, i dont understand how can copy the value to a variable.

Thank you !

Here is the code that I'm using:

    public static class ClassPrinterVisitor extends ClassVisitor {
    private String name;
    private String desc;
    private String signature;

    private Type[] paramTypes;
    private boolean isStatic;
    private String className;
    private String methodName;
    private String methodDesc;
    private String owner;
    private int access;

    public ClassPrinterVisitor(int api, ClassVisitor cv) {
        super(api, cv);
    }

    public ClassPrinterVisitor(int api) {
        super(api);
    }


    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
                                     String signature, String[] exceptions) {

        MethodVisitor oriMv = new MethodVisitor(Opcodes.ASM4) {
        };

        final MethodVisitor instMv2 = new MethodPrinterVisitor(access, desc, oriMv, Type.getArgumentTypes(desc), (access & Opcodes.ACC_STATIC) != 0, className,
                name, desc);
        return instMv2;
    }


    private class MethodPrinterVisitor extends MethodVisitor {

        List<Object> params = new ArrayList<>();
        List<Object> params2 = new ArrayList<>();

        private Type[] paramTypes;
        private boolean isStatic;
        private String className;
        private String methodName;
        private String methodDesc;

        public MethodPrinterVisitor(int api, MethodVisitor mv) {
            super(api, mv);
        }


        public MethodPrinterVisitor(int access, String desc, MethodVisitor mv, Type[] paramTypes, boolean isStatic, String classname,
                                    String methodname, String methoddesc) {
            super(Opcodes.ASM4, mv);
            this.paramTypes = paramTypes;
            this.isStatic = isStatic;
            this.className = classname;
            this.methodName = methodname;
            this.methodDesc = methoddesc;

        }


        @Override
        public void visitLdcInsn(Object var1) {
            if (var1 != null) {
                params.add(var1);
                super.visitLdcInsn(var1);
                System.out.printf("arg: %s %n", var1.toString());

            }

        }
        @Override
        public void visitInsn(int var1) {
            if(this.mv != null) {
                this.mv.visitInsn(var1);
            }

        }
        @Override
        public void visitIntInsn(int var1, int var2) {
            if(this.mv != null) {
                this.mv.visitIntInsn(var1, var2);
            }

        }
        @Override
        public void visitVarInsn(int var1, int var2) {
            if(this.mv != null) {
                this.mv.visitVarInsn(var1, var2);
            }

        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            Pattern pattern = Pattern.compile("[a-zA-Z0-9._]*");

            System.out.printf("---------------------------%n");
            System.out.printf("Class %s calls method %s from class %s%n", ClassPrinterVisitor.this.name, name, owner);
            System.out.printf("Desc: %s signature: %s%n", ClassPrinterVisitor.this.desc, ClassPrinterVisitor.this.signature);
            for (Object p : params) {
                Matcher matcher = pattern.matcher(p.toString());
                if (!p.toString().isEmpty() && !p.toString().startsWith(".") && matcher.matches()) {
                    System.out.printf("visitLdcInsn: %s %n", p);
                }
            }
            System.out.printf("---------------------------%n%n");
            params = new ArrayList<>();
        }

        @Override
        public void visitCode() {
            int paramLength = paramTypes.length;

            // Create array with length equal to number of parameters
            mv.visitIntInsn(Opcodes.BIPUSH, paramLength);
            mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
            mv.visitVarInsn(Opcodes.ASTORE, paramLength);

            // Fill the created array with method parameters
            int i = 0;
            for (Type tp : paramTypes) {
                mv.visitVarInsn(Opcodes.ALOAD, paramLength);
                mv.visitIntInsn(Opcodes.BIPUSH, i);

                if (tp.equals(Type.BOOLEAN_TYPE)) {
                    mv.visitVarInsn(Opcodes.ILOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
                } else if (tp.equals(Type.BYTE_TYPE)) {
                    mv.visitVarInsn(Opcodes.ILOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
                } else if (tp.equals(Type.CHAR_TYPE)) {
                    mv.visitVarInsn(Opcodes.ILOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
                } else if (tp.equals(Type.SHORT_TYPE)) {
                    mv.visitVarInsn(Opcodes.ILOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
                } else if (tp.equals(Type.INT_TYPE)) {
                    mv.visitVarInsn(Opcodes.ILOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
                } else if (tp.equals(Type.LONG_TYPE)) {
                    mv.visitVarInsn(Opcodes.LLOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
                    i++;
                } else if (tp.equals(Type.FLOAT_TYPE)) {
                    mv.visitVarInsn(Opcodes.FLOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
                } else if (tp.equals(Type.DOUBLE_TYPE)) {
                    mv.visitVarInsn(Opcodes.DLOAD, i);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
                    i++;
                } else
                    mv.visitVarInsn(Opcodes.ALOAD, i);

                mv.visitInsn(Opcodes.AASTORE);
                i++;
            }

            // Load id, class name and method name
            this.visitLdcInsn(new Integer(this.methodID));
            this.visitLdcInsn(this.className);
            this.visitLdcInsn(this.methodName);

            // Load the array of parameters that we created
            this.visitVarInsn(Opcodes.ALOAD, paramLength);


            mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, name, signature);
            super.visitCode();
        }


    }

}

2 Answers 2

1

You need to implement Data Flow Analysis, for your case it would be Backward Data Flow Analysis.

Have a look at ASM's SourceInterpreter, and this SO answer https://stackoverflow.com/a/48806265/573057

Due to Control Flow, there may be multiple possible values for a single argument. Due to external input, you may not be able to determine a value (although you may be able to determine things like nullness from the wider context).

Not that hard for the example given, with only constants or calls to methods on the same class yielding constants - but expanding to a general case is likely significant work. Might be worth taking a look a "checker" type frameworks that do static code analysis.

Sign up to request clarification or add additional context in comments.

Comments

-1

You can not ”get values passed as arguments on calls of some methods“ when visiting a method's bytecode using ASM, and I think you might have wrongly understand these references.

ASM is only a library for bytecode manipulation. During manipulation for a method, the number shown in the bytecode is only a local variable index (parameters and local variables), there is no way for you to get the VALUE that a variable references (if it is not constant).

The only possible to obtain the VALUEs of these local variable indexes is to execute the visited bytecode. A method's bytecode is statical and the values of these variable indexes references are UNKNOWN. When executing a method's bytecode, these indexes references some Objects, and the VM knows it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.