`
wjm251
  • 浏览: 108637 次
  • 性别: 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虚拟机》

分享到:
评论

相关推荐

    java反编译工具,直接查看class文件

    class文件变java源代码,可同时打开多个文件,关键字高亮显示

    JD-GUI,JDGUI,java反编译工具

    java反编译工具: JD-GUI JD-GUI 是一个用 C++ 开发的 Java 反编译工具... (它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。)

    android反编译工具集合以及攻略全新

    大家都知道,将apk文件解压后有两部分文件需要处理,一种是xml文件,另一种一个dex文件(.dex),我们可以从.dex文件中得到.class,利用后者再得到大家垂涎已久的java文件。 下面分别针对这三种格式的文件进行反编译...

    apk 反编译

    2.源代码反编译 工具:1) dex2jar-0.0.7-SNAPSHOT 2) jd-gui-0.3.3.windows 步骤:1) 将xxx.apk改名为xxx.zip,解压缩,进入解压缩文件夹会看到一个class.dex文件 2) 使用命令进入dex2jar-0.0.7-SNAPSHOT目录下,...

    java字节码分析工具

    对于反编译出java源码还未能做到,主要是由于条件语句本人无法想出通用的反编译算法,不过对于class文件结构已经做了完整的分析,哪位仁兄如果在此基础上实现了完整的反编译,希望告知一声。class测试文件最好用Jdk...

    JAVA上百实例源码以及开源项目

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    JAVA上百实例源码以及开源项目源代码

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    fernflower1.zip

    一款可以直接将一个文件夹内全部class直接...楼主已经亲测,成功反编译一个项目,但是对于代码量比较大的文件,有的反编译工具还是无法正常解析,不过已经满足需求,即使解析失败也有提示,配合luyten工具使用就行了。

    java反编译class源码-MARA_Framework:MARA是一个移动应用程序逆向工程和分析框架。它是一个工具包,汇集了常用的移动应用

    java反编译class源码MARA_框架 MARA是A M obile甲pplicationřEVERSE工程和A nalysis框架。 它是一个将常用的移动应用程序逆向工程和分析工具组合在一起的工具,以帮助测试移动应用程序针对 OWASP 移动安全威胁。 其...

    一个java正则表达式工具类源代码.zip(内含Regexp.java文件)

    以前写了一个java的正规表达式的java工具类,分享一下,有用到的欢迎下载使用。 如果你有常用的定义好的,且测试通过的正规表达式,欢迎跟贴,也让我享用一下 . 类中用到了 jakarta-oro-2.0.jar 包,请大家自己在 ...

    java开源包8

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包10

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    iOS应用逆向工程:分析与实战

    第二部分为工具篇,介绍一系列基于Mac和iOS平台的配套工具,并且重点讲解其中的class-dump、Theos、Reveal、IDA、GDB等5个工具的使用方法,前3个侧重于使用,后2个侧重于分析。第三部分为理论篇,主要讲述iOS逆向/...

    java开源包4

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包1

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包11

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包2

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包3

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

    java开源包6

    JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的...

Global site tag (gtag.js) - Google Analytics