如何使用ASM在类文件中查找函数调用的名称?

时间:2018-05-22 12:25:26

标签: java bytecode java-bytecode-asm

这里我有一个简单的添加java程序

import java.util.Scanner;
public class Main {
    public static int add(int a, int b)
    {
        return a+b;
    }
    public static void main(String [] argv)
    {
        String a="Hello world";
    int b=499,c=599;
    int v= add(b,c);
    }
}

现在我正在使用一个操作程序来操作java程序的类文件。

package com.seriouscompany.program;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;

public class Manipulator {

    //!!Change this to the path to your application's path!!
    public static final File PROGRAM_APPLICATION_JAR = new File("C:\\Users\\jayarasr\\Desktop\\SeriousProgram.jar");    
    private static List<ClassNode> classNodes = new ArrayList<>();

    public static void main(String[] args) throws FileNotFoundException {
        PrintStream o = new PrintStream(new File("A.txt"));
        System.setOut(o);
        classNodes = load(PROGRAM_APPLICATION_JAR);

        for(ClassNode classNode : classNodes) {
            System.out.println("------------------");
            System.out.println("Class Node :"+classNode.name);
            for(Object methodNodeObj : classNode.methods) {
                MethodNode methodNode = (MethodNode)methodNodeObj;
                System.out.println("Method Node  :"+methodNode.name);
             //   if(methodNode.name.toString()=="main") {}
                for(AbstractInsnNode abstractInsnNode : methodNode.instructions.toArray()) {
                    System.out.println("Abstract : "+abstractInsnNode.getOpcode());
                     if(abstractInsnNode instanceof LdcInsnNode) {
                        LdcInsnNode ldcInsn = (LdcInsnNode)abstractInsnNode;
                        System.out.println("Value :"+ldcInsn.cst);
                    }
                }
            }
        }

        save(new File(PROGRAM_APPLICATION_JAR.getAbsolutePath().replace(".jar", "dumped.jar")), classNodes);
    }

    public static void save(File jar, final List<ClassNode> nodes) {
        try {
            try(final JarOutputStream output = new JarOutputStream(new FileOutputStream(jar))) {
                for(ClassNode element : nodes) {
                    ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
                    output.putNextEntry(new JarEntry(element.name.replaceAll("\\.", "/") + ".class"));
                    output.write(writer.toByteArray());
                    output.closeEntry();
                }
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public static List<ClassNode> load(File file) {
        try {
            JarFile jar = new JarFile(file);
            List<ClassNode> list = new ArrayList<>();
            Enumeration<JarEntry> enumeration = jar.entries();
            while(enumeration.hasMoreElements()) {
                JarEntry next = enumeration.nextElement();
                if(next.getName().endsWith(".class")) {
                    ClassReader reader = new ClassReader(jar.getInputStream(next));
                    ClassNode node = new ClassNode();
                    reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
                    list.add(node);
                }
            }
            jar.close();
            return list;
        } catch(IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

在这里,我可以打印类名,方法名和常量值。 现在我的查询是如何打印变量名称,称为函数名称(调用一个)(我只能找到操作码) 我阅读了ASM的文档,然后去了解这个, 请帮我找到上面提到的查询。

1 个答案:

答案 0 :(得分:0)

要掌握调用方法的名称,您必须检查MethodNodeInsn的属性,该属性定义任何被调用方法的所有者,方法名称和描述符。要掌握变量名称,您需要阅读local variable table什么是调试信息,这些信息不一定存在于所有类中。