解决从字节码的类名(Resolve class name from bytecode)

2019-09-02 14:59发布

是否有可能挖掘的字节码是从类的源代码构成的类的名字吗?

情况是这样的:我远程获取类的字节码从什么地方,没关系它从何而来。 为了有效地加载类类加载器我需要有类的名字,以及...对吧?

Answer 1:

如果你只需要类名,它可能更容易解析类的文件,开始自己的,而不是添加类代码操纵第三方库只是为了这个目的。 你只需要类和从字符串常量池,跳过访问标志,然后替换/带。 在类名。 如果你有一个字节数组,你可以调用此方法与new ByteArrayInputStream(byteArray)

public static String getClassName(InputStream is) throws Exception {
    DataInputStream dis = new DataInputStream(is);
    dis.readLong(); // skip header and class version
    int cpcnt = (dis.readShort()&0xffff)-1;
    int[] classes = new int[cpcnt];
    String[] strings = new String[cpcnt];
    for(int i=0; i<cpcnt; i++) {
        int t = dis.read();
        if(t==7) classes[i] = dis.readShort()&0xffff;
        else if(t==1) strings[i] = dis.readUTF();
        else if(t==5 || t==6) { dis.readLong(); i++; }
        else if(t==8) dis.readShort();
        else dis.readInt();
    }
    dis.readShort(); // skip access flags
    return strings[classes[(dis.readShort()&0xffff)-1]-1].replace('/', '.');
}


Answer 2:

最简单的方法可能是使用类似ASM :

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.commons.EmptyVisitor;

public class PrintClassName {
  public static void main(String[] args) throws IOException {
    class ClassNamePrinter extends EmptyVisitor {
      @Override
      public void visit(int version, int access, String name, String signature,
          String superName, String[] interfaces) {
        System.out.println("Class name: " + name);
      }
    }

    InputStream binary = new FileInputStream(args[0]);
    try {
      ClassReader reader = new ClassReader(binary);
      reader.accept(new ClassNamePrinter(), 0);
    } finally {
      binary.close();
    }
  }
}

如果您无法使用第三方库,你可以自己阅读类文件格式 。



Answer 3:

您应该能够使用javap拆卸字节码,如果只是在一段时间发生一次。

在运行时做:用一个字节码操作库,比如Apache的BCEL( http://jakarta.apache.org/bcel )来分析字节码。



Answer 4:

我想你可以使用ClassLoader.defineClass方法,ClassLoader的一个子类,获得Class对象为给定的字节码。 (未测试)



Answer 5:

只是为了完整性,在情况下,使用图书馆ASM5是可以接受的,下面的调用可以用来获得其字节表示的类名。

public String readClassName(final byte[] typeAsByte) {
    return new ClassReader(typeAsByte).getClassName().replace("/", ".");
}


文章来源: Resolve class name from bytecode