`
wjm251
  • 浏览: 110083 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

解析class文件,贴完整代码,考虑可以做个反编译工具~

    博客分类:
  • java
阅读更多
写出来贴在这留个纪念,没看过class规范看着是比较抽象,,也没写注释,sorry

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ParseClassFile
{
    static class CLASS_ACC{
        public final static int ACC_PUBLIC = 0x0001;//class&interface
        public final static int ACC_FINAL = 0x0010;//class
        public final static int ACC_SUPER = 0x0020;//class&interface--->special
        public final static int ACC_INTERFACE = 0x0200;//all interface
        public final static int ACC_ABSTRACT = 0x0400;//all interface ,some class      
        public final static Object[][] ACC = new Object[][]{
            {0x0001,"public"},
            {0x0010,"final"},
            {0x0020,"invokespecial"},
            {0x0200,"interface"},
            {0x0400,"abstract"},
        };
    }
   
    static class FIELD_ACC{
        //头3个标志public,private protected在类中只能有一个
        //接口中必须设置为public static final
        //final 和volatile不能同时出现
        public final static int ACC_PUBLIC = 0x0001;
        public final static int ACC_PRIVATE = 0x0002;
        public final static int ACC_PROTECTED = 0x0004;
       
        public final static int ACC_STATIC = 0x0008;
        public final static int ACC_FINAL = 0x0010;   
        public final static int ACC_VOLATILE = 0x0040;
        public final static int ACC_TRANSIENT = 0x0080;
        public final static Object[][] ACC = new Object[][]{
            {0x0001,"public"},
            {0x0002,"private"},
            {0x0004,"protected"},
            {0x0008,"static"},           
            {0x0010,"final"},           
            {0x0040,"volatile"},
            {0x0080,"transient"}
        };
    }

static class METHOD_ACC
    {
        /**
         * 类(不含接口)中声明的方法只能有public private protected中的一个
         * 如果一个方法设置了abstract,则private static final synchronized,native及strict都不能有
         * 接口中方法必须使用public abstract不能有其他
         *
         * 构造方法<init>可以只使用public private和protected,<clinit>只会考虑ACC_STRICT标志
         */
        public final static int ACC_PUBLIC = 0x0001;
        public final static int ACC_PRIVATE = 0x0002;
        public final static int ACC_PROTECTED = 0x0004;
        public final static int ACC_STATIC = 0x0008;
        public final static int ACC_FINAL = 0x0010;
        public final static int ACC_SYNCHRONIZED = 0x0020;
        public final static int ACC_NATIVE = 0x0100;
        public final static int ACC_ABSTRACT = 0x0400;
        public final static int ACC_STRICT = 0x0800;       
        public final static Object[][] ACC = new Object[][]{
            {0x0001,"public"},
            {0x0002,"private"},
            {0x0004,"protected"},
            {0x0008,"static"},           
            {0x0010,"final"},           
            {0x0020,"synchronized"},
            {0x0100,"native"},
            {0x0400,"abstract"},
            {0x0800,"strict"}
        };
    }
    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException
    {
        File f = new File("bin\\a.class");
        FileInputStream in = new FileInputStream(f);

        printMagicNumber(in);
        printVersion(in);
        int count = printConstantPoolEntryNumber(in);
        printConstants(in, count);
        System.out.println("access flag:"+parseACC(readInt(in,2), CLASS_ACC.ACC));
        System.out.println("this class: class ref="+readInt(in,2));
        System.out.println("super class: class ref="+readInt(in,2));       
        printInterfaces(in);
        printFields(in);
        printMethods(in);
        parseAttrbute(in);
        System.out.println();
        System.out.println("remain bytes:" + in.available());
    }


    private static void printMethods(FileInputStream in)throws IOException
    {
        int methodCount = readInt(in,2);
        System.out.println("method count: "+methodCount);
        for(int i=0;i<methodCount;i++)
        {       
            String access = parseACC(readInt(in,2),METHOD_ACC.ACC);
            System.out.print("method["+i+"]"+access+"name ref="+readInt(in,2)+",descriptor ref="+readInt(in,2));
            parseAttrbute(in);
        }
    }


    private static void printFields(FileInputStream in) throws IOException
    {
       
        int fieldCount = readInt(in,2);
        System.out.println("field count: "+fieldCount);
        for(int i=0;i<fieldCount;i++)
        {
            String access = parseACC(readInt(in,2),FIELD_ACC.ACC);
            System.out.print("field["+i+"]"+access+"name ref="+readInt(in,2)+",descriptor ref="+readInt(in,2));
            parseAttrbute(in);
        }       
    }
public static String parseACC(int accessFlag,Object[][] accType) throws IOException
    {
        StringBuilder access = new StringBuilder("[");
        for(Object[] o : accType)
        {
            if((accessFlag&(Integer)o[0])!=0)
            {
                access.append(o[1]+",");
            }
        }
        access.append("]");
        return access.toString();
    }
    public static void parseAttrbute(FileInputStream in) throws IOException
    {
        int attrcount = readInt(in,2);
        System.out.print(",attr count="+attrcount);
        for(int j=0;j<attrcount;j++)
        {
            System.out.print(",attrname ref="+readInt(in,2));
            int attrLen = readInt(in,4);
            System.out.println(",attrlen="+attrLen);           
            //TODO parse attribute
            in.skip(attrLen);           
        }
    }

    private static void printInterfaces(FileInputStream in) throws IOException
    {
        int interfaceCount = readInt(in,2);
        System.out.println("interface count: "+interfaceCount);
        for(int i=0;i<interfaceCount;i++)
        {           
            System.out.println("interface["+i+"] ref="+readInt(in,2));
        }

    }


    private static void printVersion(FileInputStream in) throws IOException
    {
        System.out.println("minor_version:" + readInt(in, 2));
        System.out.println("major_version:" + readInt(in, 2));
    }

    private static void printMagicNumber(FileInputStream in) throws IOException
    {
        System.out.print("magic number:");
        for (int i = 1; i <= 4; i++)
        {
            System.out.print(Integer.toHexString(readInt(in, 1)));
        }
        System.out.println();
    }

    private static int printConstantPoolEntryNumber(FileInputStream in)
            throws IOException
    {
        int counstNum = readInt(in, 2) - 1;
        System.out.println("constant pool entrys number:" + counstNum);
        return counstNum;
    }

    private static void printConstants(FileInputStream in, int length)
            throws IOException
    {

        for (int i = 1; i <= length; i++)
        {
            int flagType = readInt(in, 1);
            System.out.print("counstPool " + i + ":tag=" + flagType + ",");
            switch (flagType)
            {
                case 1: // CONSTANT_Utf8
                {
                    int len = readInt(in, 2);
                    byte[] str = new byte[len];
                    in.read(str);
                    System.out.println("String:"+new String(str,"UTF-8"));
                    break;
                }            
               
                case 3://CONSTANT_Integer
                    System.out.println("int value="+readInt(in,4));
                    break;
                case 4://CONSTANT_Float
                  //TODO  
                    in.skip(1);
                    System.out.println();
                    break;     
                 case 5://CONSTANT_Long
                    System.out.println("long value="+Long.toString(readLong(in,8)));
                    i++;
                    break;
                case 6://CONSTANT_Double
                    //double型占两个常量池入口
                    //TODO
                      in.skip(8);
                      i++;
                      System.out.println();
                      break;
                case 7: // CONSTANT_Class
                {
                    int name_index_entry = readInt(in, 2);
                    System.out.println("ClassInfo,reference constPool "
                            + name_index_entry);
                    break;
                }
                case 8:// CONSTANT_String
                    System.out.println("String,ref"
                            + readInt(in, 2));
                    break;
                case 9:// CONSTANT_Fieldref
                {
                    System.out.println("field: classref="+readInt(in,2)+",method ref="+readInt(in,2));
                    break;
                }
                case 10:// CONSTANT_Methodref
                {
                    System.out.println("method from class: classref="+readInt(in,2)+",method ref="+readInt(in,2));
                    break;
                }                   
                case 11:// CONSTANT_InterfaceMethodref
                    System.out.println("method from interface: classref="+readInt(in,2)+",method ref="+readInt(in,2));
                    break;
                case 12:// CONSTANT_NameAndType
                {
                    System.out.println("fieldName ref="+readInt(in,2)+",fieldDescriptor ref="+readInt(in,2));
                    break;
                }
                default:
                    throw new RuntimeException();
            }
        }
    }

    public static byte[] int2Bytes(int val)
    {
        byte bs[] = new byte[4];
        bs[0] = (byte) (val >> 24);
        bs[1] = (byte) (val >> 16);
        bs[2] = (byte) (val >>8);
        bs[3] = (byte) val;
        return bs;
    }

    public static int readInt(InputStream in, int byteNum) throws IOException
    {
        byte[] x = new byte[byteNum];
        in.read(x);
        return bytes2Int(x);
    }   
    public static long readLong(InputStream in, int byteNum) throws IOException
   {
        byte[] x = new byte[byteNum];
        in.read(x);
        return bytes2Long(x);
    }
    private static int bytes2Int(byte bs[])
    {
        int var = 0;
        for (int i = 1; i <= bs.length; i++)
        {
            var += (bs[i - 1] & 255) << 8 * (bs.length - i);
        }
        return var;
    }
    private static long bytes2Long(byte bs[])
    {
        long var = 0;
        for (int i = 1; i <= bs.length; i++)
        {
            var += (bs[i - 1] & 255) << 8 * (bs.length - i);
        }
        return var;
    }

}
参考
《深入java虚拟机》

分享到:
评论

相关推荐

    class文件反编译工具

    在Java编程语言中,`.class`文件是Java字节码的...总的来说,`jd-gui`这样的class文件反编译工具为Java开发者提供了一个查看和理解已编译代码的窗口,提高了开发效率和学习能力,但在使用时需谨慎对待版权和隐私问题。

    java class反编译工具

    Java Class反编译工具是程序员在处理已编译的字节码文件时不可或缺的辅助工具。这类工具的主要功能是将`.class`文件转换回可读性强的`.java`源代码,帮助开发者理解或修改已有的Java程序,尤其在没有源代码的情况下...

    Java Class文件反编译工具 jd-gui

    为了查看和理解Class文件内部的源代码,我们就需要使用到反编译工具。本文将详细介绍Java Class文件反编译工具——jd-gui。 jd-gui是一个开源的Java反编译工具,由Jikes项目开发者创建。它允许开发者在图形用户界面...

    Java的class反编译工具

    标题中的"Java的class反编译工具"指的就是能够将.class文件转换回接近原始源代码形式的工具。这种工具帮助开发者了解已有的类库是如何工作的,或者在没有源代码的情况下修复bug。常见的Java Class反编译工具有JD-GUI...

    java.class 反编译工具

    通过反编译工具,开发者可以查看JAR内部的类文件,了解其功能和实现细节,而无需原始的源代码。 "无需安装,解压即用"的特点使得这个工具非常便捷。用户下载压缩包后,直接解压缩就可以开始使用,省去了复杂的安装...

    .class 文件反编译工具

    反编译工具通过解析.class文件的字节码,将其还原成接近原始Java源代码的形式,帮助开发者理解已编译的代码。 二、jd-gui:便捷的反编译工具 "jd-gui"是一款小巧且易于使用的Java反编译工具,它提供了一个图形化的...

    Class文件反编译工具

    在Java编程环境中,"Class文件反编译工具"是一个至关重要的辅助工具,它允许开发者查看并理解已编译的.class文件中的源代码级信息。由于Java的编译过程将源代码(.java文件)转化为字节码(.class文件),在某些情况...

    JD-GUI反编译class文件工具

    JD-GUI是一款强大的Java反编译工具,专用于将字节码(.class文件)转换回源代码(.java文件)。在Java开发中,有时我们可能需要查看或理解已编译的类文件内部实现,而原始的源代码不再可用。这时,JD-GUI就能发挥它...

    java class文件或jar文件反编译工具.rar

    "java class文件或jar文件反编译工具.rar"正是这样一个资源,包含了一个名为jd-gui.exe的反编译工具,可以帮助我们将这些二进制文件转换回可读的Java源代码。 jd-gui.exe是一个图形用户界面的Java反编译器,它由JDI...

    Xjad java class文件反编译工具

    这就是反编译工具如Xjad的重要性所在。Xjad是一款专门用于将Java class文件转换回源代码(.java文件)的工具,它使得开发者能够查看并理解已编译的Java代码,这对于学习、调试、分析或逆向工程非常有用。 反编译是...

    Java的class文件反编译工具

    2. **反编译原理**:反编译工具通过解析Class文件的字节码,将其转化为人类可读的源代码。这个过程涉及到对Java字节码的逆向工程,包括理解操作码、常量池引用、控制流结构等。 3. **JD-GUI特点**: - **直观界面*...

    代码反编译工具

    总之,代码反编译是软件开发中的一个重要辅助工具,jd-gui.exe作为一款便捷的反编译工具,为开发者提供了查看和理解.class文件源代码的能力。然而,正确使用和理解反编译的法律边界是每个开发者都应重视的。

    Java反编译工具,将class文件反编译成Java文件

    Java反编译是编程领域中一个重要的技术环节,它允许开发者查看和理解已经编译成字节码(.class文件)的Java程序的原始源代码。这种能力在多种情况下非常有用,例如,当我们需要分析开源软件的实现细节,或者当我们...

    class jar文件反编译工具

    需要注意的是,虽然反编译工具可以提供源码级别的信息,但它们并不能保证完全恢复原始的代码结构和变量名,因为这些信息在编译后并不保留。此外,使用反编译工具应尊重知识产权,仅用于合法的学习和研究目的,避免...

    jar文件反编译工具

    这些工具能够解析JAR文件中的.class文件,并将其转换为接近原始的Java源代码。虽然反编译的代码可能无法与原始源代码完全相同,但通常足以理解大部分逻辑。 JD-GUI 是一款图形用户界面的反编译工具,它允许用户直接...

    class反编译工具

    然而,字节码并不是人类可以直接阅读的代码,因此反编译工具就显得尤为必要。 JD-GUI,作为压缩包中的主要文件,是一个图形用户界面的Java反编译器。它能够将.class文件转换回可读的Java源代码,帮助开发者分析或...

    java反编译工具 对.class文件

    Java反编译工具是开发人员在处理Java字节码时不可或缺的辅助工具,它们能够将已编译的`.class`文件转换回接近原始的Java源代码形式。这在某些情况下非常有用,例如当源代码丢失或者需要查看第三方库的内部实现时。...

    Class文件反编译工具XJad

    2. **高效反编译**:XJad具备强大的反编译引擎,能够准确地将Java字节码转换为源代码,尽管不如现代的反编译工具如JD-GUI、Procyon等那么完善,但在处理早期版本的Java Class文件时,XJad的表现依然出色。...

Global site tag (gtag.js) - Google Analytics