[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/strivegithub/bytecode-viewer/master/plugins/java/ClassParser.java [Back]  [Original]

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.api.Plugin;
import the.bytecode.club.bytecodeviewer.api.PluginConsole;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Class Parser
 *
 * @author Damir37
 */
public class ClassParser extends Plugin
{

    private PluginConsole pluginConsole;

    @Override
    public void execute(List list)
    {
        if(!BytecodeViewer.isActiveClassActive())
        {
            BytecodeViewer.showMessage("Open A Classfile First");
            return;
        }

        ClassNode c = BytecodeViewer.getCurrentlyOpenedClassNode();

        ClassFileParser classFileParser = new ClassFileParser(classNodeToByte(c));

        pluginConsole = new PluginConsole("ClassParser");
        pluginConsole.setVisible(true);

        print("Parsing class: " + c.name + ".class");
        print("MAGIC VALUE: " + classFileParser.parseMagicValue());
        print("Class version: " + classFileParser.parseVersionClass());
        print("Constant pool count: " + classFileParser.parseConstantPoolCount()
            + " If not all constants were parsed, most likely the constant is not used in the bytecode.");
        print("Then use the javap utility to view the constant pool of a class file.");
        print("Last modified class: " + classFileParser.parseClassModificationDate());
        print("Hash sum class md5: " + classFileParser.getHash("MD5"));
        print("Hash sum class sha1: " + classFileParser.getHash("SHA-1"));
        print("Hash sum class sha256: " + classFileParser.getHash("SHA-256"));
        print("Hash sum class sha512: " + classFileParser.getHash("SHA-512"));
        print("Constant pool ->");

        classFileParser.getConstantPool().parseConstantPool();

        if (classFileParser.getConstantPool().getCpList() != null && !classFileParser.getConstantPool().getCpList().isEmpty())
        {
            for (String s : classFileParser.getConstantPool().getCpList())
            {
                print(s);
            }
        }
    }

    private byte[] classNodeToByte(ClassNode classNode)
    {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        classNode.accept(cw);
        return cw.toByteArray();
    }

    public void print(String text)
    {
        pluginConsole.appendText(text);
        pluginConsole.repaint();
    }

    private static class ClassFileParser
    {
        private final ByteBuffer buffer;
        private final ConstantParser cpParser;

        public ClassFileParser(byte[] classBytes)
        {
            this.buffer = ByteBuffer.wrap(classBytes);
            cpParser = new ConstantParser(buffer, parseConstantPoolCount());
        }

        public String parseMagicValue()
        {
            buffer.position(0);
            int magicValue = buffer.getInt();
            return "0x" + Integer.toHexString(magicValue).toUpperCase();
        }

        public ClassVersion parseVersionClass()
        {
            buffer.position(4);
            int minor = buffer.getShort() & 0xFFFF;
            int major = buffer.getShort() & 0xFFFF;
            return ClassVersion.check(major, minor);
        }

        public Date parseClassModificationDate()
        {
            buffer.position(8);
            long modificationTime = buffer.getInt() & 0xFFFFFFFFL;
            return new Date(modificationTime * 1000L);
        }

        public int parseConstantPoolCount()
        {
            buffer.position(8);
            return buffer.getShort() & 0xFFFF;
        }

        public String getHash(String algorithm)
        {
            try
            {
                MessageDigest md = MessageDigest.getInstance(algorithm);
                md.update(buffer.array());
                byte[] digest = md.digest();
                return convertToHex(digest);
            }
            catch (NoSuchAlgorithmException e)
            {
                e.printStackTrace();
            }

            return "null";
        }

        private String convertToHex(byte[] bytes)
        {
            StringBuilder hexString = new StringBuilder();

            for (byte b : bytes)
            {
                hexString.append(String.format("%02X", b));
            }

            return hexString.toString();
        }

        public ConstantParser getConstantPool()
        {
            return cpParser;
        }
    }

    private enum ClassVersion
    {
        UNKNOWN(0, 0),
        JAVA_1_1(45, 3),
        JAVA_1_2(46, 0),
        JAVA_1_3(47, 0),
        JAVA_1_4(48, 0),
        JAVA_5(49, 0),
        JAVA_6(50, 0),
        JAVA_7(51, 0),
        JAVA_8(52, 0),
        JAVA_9(53, 0),
        JAVA_10(54, 0),
        AVA_11(55, 0),
        JAVA_12(56, 0),
        JAVA_13(57, 0),
        JAVA_14(58, 0),
        JAVA_15(59, 0),
        JAVA_16(60, 0),
        JAVA_17(61, 0),
        JAVA_18(62, 0),
        JAVA_19(63, 0),
        JAVA_20(64, 0),
        JAVA_21(65, 0),
        JAVA_22(66, 0),
        JAVA_23(67, 0),
        JAVA_24(68, 0),
        JAVA_25(69, 0),
        JAVA_26(70, 0),
        JAVA_27(71, 0),
        JAVA_28(72, 0),
        JAVA_29(73, 0),
        JAVA_30(74, 0);

        public final int major;
        public final int minor;

        ClassVersion(int major, int minor)
        {
            this.major = major;
            this.minor = minor;
        }

        public static ClassVersion check(int major, int minor)
        {
            for (ClassVersion v : ClassVersion.values())
            {
                if (v.major == major && v.minor == minor)
                    return v;
            }

            return UNKNOWN;
        }
    }

    private static class ConstantParser
    {
        private final ByteBuffer buffer;
        private final int constantPoolCount;
        private final List cpList = new ArrayList();

        public ConstantParser(ByteBuffer buffer, int constantPoolCount)
        {
            this.buffer = buffer;
            this.constantPoolCount = constantPoolCount;
        }

        public void parseConstantPool()
        {
            buffer.position(10);

            for (int i = 1; i < constantPoolCount; i++)
            {
                int tag = buffer.get() & 0xFF;
                switch (tag)
                {
                    case ConstantType.CONSTANT_Utf8:
                        int length = buffer.getShort() & 0xFFFF;
                        byte[] bytes = new byte[length];
                        buffer.get(bytes);
                        String string = new String(bytes);
                        cpList.add("[" + i + "] CONSTANT_Utf8: " + string);
                        break;

                    case ConstantType.CONSTANT_Integer:
                        int value = buffer.getInt();
                        cpList.add("[" + i + "] CONSTANT_Integer: " + value);
                        break;

                    case ConstantType.CONSTANT_Float:
                        float floatValue = buffer.getFloat();
                        cpList.add("[" + i + "] CONSTANT_Float: " + floatValue);
                        break;

                    case ConstantType.CONSTANT_Long:
                        long longValue = buffer.getLong();
                        cpList.add("[" + i + "] CONSTANT_Long: " + longValue);
                        i++;
                        break;

                    case ConstantType.CONSTANT_Double:
                        double doubleValue = buffer.getDouble();
                        cpList.add("[" + i + "] CONSTANT_Double: " + doubleValue);
                        i++;
                        break;

                    case ConstantType.CONSTANT_Class:
                        int nameIndex = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_Class: #" + nameIndex);
                        break;

                    case ConstantType.CONSTANT_String:
                        int stringIndex = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_String: #" + stringIndex);
                        break;

                    case ConstantType.CONSTANT_Fieldref:
                    case ConstantType.CONSTANT_Methodref:
                    case ConstantType.CONSTANT_InterfaceMethodref:
                        int classIndex = buffer.getShort() & 0xFFFF;
                        int nameAndTypeIndex = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_" + getRefTypeName(tag) + ": #" + classIndex + ".#" + nameAndTypeIndex);
                        break;

                    case ConstantType.CONSTANT_NameAndType:
                        int nameIndex1 = buffer.getShort() & 0xFFFF;
                        int descriptorIndex = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_NameAndType: #" + nameIndex1 + ":#" + descriptorIndex);
                        break;

                    case ConstantType.CONSTANT_MethodHandle:
                        int referenceKind = buffer.get() & 0xFF;
                        int referenceIndex = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_MethodHandle: " + referenceKind + ":#" + referenceIndex);
                        break;

                    case ConstantType.CONSTANT_MethodType:
                        int descriptorIndex1 = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_MethodType: #" + descriptorIndex1);
                        break;

                    case ConstantType.CONSTANT_InvokeDynamic:
                        int bootstrapMethodAttrIndex = buffer.getShort() & 0xFFFF;
                        int nameAndTypeIndex3 = buffer.getShort() & 0xFFFF;
                        cpList.add("[" + i + "] CONSTANT_InvokeDynamic: #" + bootstrapMethodAttrIndex + ":#" + nameAndTypeIndex3);
                        break;

                    default:
                        throw new IllegalArgumentException("Unknown constant pool tag " + tag);
                }
            }
        }

        private String getRefTypeName(int tag)
        {
            switch (tag)
            {
                case ConstantType.CONSTANT_Fieldref:
                    return "Fieldref";
                case ConstantType.CONSTANT_Methodref:
                    return "Methodref";
                case ConstantType.CONSTANT_InterfaceMethodref:
                    return "InterfaceMethodref";
                default:
                    return "Unknown";
            }
        }

        public List getCpList()
        {
            return cpList;
        }
    }

    private interface ConstantType
    {
        public static final byte CONSTANT_Utf8 = 1;
        public static final byte CONSTANT_Class = 7;
        public static final byte CONSTANT_Fieldref = 9;
        public static final byte CONSTANT_Methodref = 10;
        public static final byte CONSTANT_InterfaceMethodref = 11;
        public static final byte CONSTANT_String = 8;
        public static final byte CONSTANT_Integer = 3;
        public static final byte CONSTANT_Float = 4;
        public static final byte CONSTANT_Long = 5;
        public static final byte CONSTANT_Double = 6;
        public static final byte CONSTANT_NameAndType = 12;
        public static final byte CONSTANT_MethodHandle = 15;
        public static final byte CONSTANT_MethodType = 16;
        public static final byte CONSTANT_InvokeDynamic = 18;
    }
}

Web Proxy Viewer  |  New URL  |  Original Page