diff --git a/README.md b/README.md index 759bbc7..f47bd6f 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed | AFE2 | | `patterns/afe2.hexpat` | Nintendo Switch Atmosphère CFW Fatal Error log | | AR | `application/x-archive` | `patterns/ar.hexpat` | Static library archive files | | NACP | | `patterns/nacp.hexpat` | Nintendo Switch NACP files | +| Java Class | `application/x-java-applet` | `patterns/java_class.hexpat` | Java Class files | ### Pattern Libraries diff --git a/patterns/java_class.hexpat b/patterns/java_class.hexpat new file mode 100644 index 0000000..1d78f3c --- /dev/null +++ b/patterns/java_class.hexpat @@ -0,0 +1,339 @@ +#pragma endian big +#pragma MIME application/x-java-applet + +// The Java documentations use the number of bytes instead of the number of bits for its type names +using u1 = u8; +using u2 = u16; +using u4 = u32; + +using f4 = float; +using f8 = double; + +enum cp_tag : u8 { + CONSTANT_Utf8 = 1, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_Class = 7, + CONSTANT_String = 8, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_NameAndType = 12, + CONSTANT_MethodHandle = 15, + CONSTANT_MethodType = 16, + CONSTANT_InvokeDynamic = 18 +}; + +enum major_version : u2 { + JDK_1_1 = 45, + JDK_1_2 = 46, + JDK_1_3 = 47, + JDK_1_4 = 48, + + Java_SE_5_0 = 49, + Java_SE_6_0 = 50, + Java_SE_7 = 51, + Java_SE_8 = 52, + Java_SE_9 = 53, + Java_SE_10 = 54, + Java_SE_11 = 55, + Java_SE_12 = 56, + Java_SE_13 = 57, + Java_SE_14 = 58, + Java_SE_15 = 59, + Java_SE_16 = 60, + Java_SE_17 = 61, +}; + +// Tag == CONSTANT_Utf8 +struct CONSTANT_Utf8_info { + u2 length; + char bytes[length]; // u1 in documentation. Changed to char to improve readability +}; + +// Tag == CONSTANT_Integer +struct CONSTANT_Integer_info { + u4 bytes; +}; + +// Tag == CONSTANT_Float +struct CONSTANT_Float_info { + f4 bytes; // u4 in documentation. Changed to f4 to improve readablilty +}; + +// Tag == CONSTANT_Long +struct CONSTANT_Long_info { + u4 high_bytes; + u4 low_bytes; +}; + +// Tag == CONSTANT_Double +struct CONSTANT_Double_info { + u4 high_bytes; + u4 low_bytes; +}; + +// Tag == CONSTANT_Class +struct CONSTANT_Class_info { + u2 name_index; +}; + +// Tag == CONSTANT_String +struct CONSTANT_String_info { + u2 string_index; +}; + +// Tag == CONSTANT_Fieldref +struct CONSTANT_Fieldref_info { + u2 class_index; + u2 name_and_type_index; +}; + +// Tag == CONSTANT_Methodref +struct CONSTANT_Methodref_info { + u2 class_index; + u2 name_and_type_index; +}; + +// Tag == CONSTANT_InterfaceMethodref +struct CONSTANT_InterfaceMethodref_info { + u2 class_index; + u2 name_and_type_index; +}; + +// Tag == CONSTANT_NameAndType +struct CONSTANT_NameAndType_info { + u2 name_index; + u2 descriptor_index; +}; + +// Tag == CONSTANT_MethodHandle +struct CONSTANT_MethodHandle_info { + u1 reference_kind; + u2 reference_index; +}; + +// Tag == CONSTANT_MethodType +struct CONSTANT_MethodType_info { + u2 descriptor_index; +}; + +// Tag == CONSTANT_InvokeDynamic +struct CONSTANT_InvokeDynamic_info { + u2 bootstrap_method_attr_index; + u2 name_and_type_index; +}; + +struct cp_info { + cp_tag tag; + + if (tag == cp_tag::CONSTANT_Utf8) + CONSTANT_Utf8_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Integer) + CONSTANT_Integer_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Float) + CONSTANT_Float_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Long) + CONSTANT_Long_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Double) + CONSTANT_Double_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Class) + CONSTANT_Class_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_String) + CONSTANT_String_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Fieldref) + CONSTANT_Fieldref_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_Methodref) + CONSTANT_Methodref_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_InterfaceMethodref) + CONSTANT_InterfaceMethodref_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_NameAndType) + CONSTANT_NameAndType_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_MethodHandle) + CONSTANT_MethodHandle_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_MethodType) + CONSTANT_MethodType_info info [[inline]]; + else if (tag == cp_tag::CONSTANT_InvokeDynamic) + CONSTANT_InvokeDynamic_info info [[inline]]; +}; + +bitfield access_flags_method { + ACC_PUBLIC : 1; // 0x0001 + ACC_PRIVATE : 1; // 0x0002 + ACC_PROTECTED : 1; // 0x0004 + ACC_STATIC : 1; // 0x0008 + ACC_FINAL : 1; // 0x0010 + ACC_SYNCHRONIZED: 1; // 0x0020 + ACC_BRIDGE : 1; // 0x0040 + ACC_VARARGS : 1; // 0x0080 + ACC_NATIVE : 1; // 0x0100 + padding : 1; // 0x0200 + ACC_ABSTRACT : 1; // 0x0400 + ACC_STRICT : 1; // 0x0800 + ACC_SYNTHETIC : 1; // 0x1000 + padding : 1; // 0x2000 + padding : 1; // 0x4000 + padding : 1; // 0x8000 +}; + +bitfield access_flags_field { + ACC_PUBLIC : 1; // 0x0001 + ACC_PRIVATE : 1; // 0x0002 + ACC_PROTECTED : 1; // 0x0004 + ACC_STATIC : 1; // 0x0008 + ACC_FINAL : 1; // 0x0010 + padding : 1; // 0x0020 + ACC_VOLATILE : 1; // 0x0040 + ACC_TRANSIENT : 1; // 0x0080 + padding : 1; // 0x0100 + padding : 1; // 0x0200 + padding : 1; // 0x0400 + padding : 1; // 0x0800 + ACC_SYNTHETIC : 1; // 0x1000 + padding : 1; // 0x2000 + ACC_ENUM : 1; // 0x4000 + padding : 1; // 0x8000 +}; + +bitfield access_flags_class { + ACC_PUBLIC : 1; // 0x0001 + padding : 1; // 0x0002 + padding : 1; // 0x0004 + padding : 1; // 0x0008 + ACC_FINAL : 1; // 0x0010 + ACC_SUPER : 1; // 0x0020 + padding : 1; // 0x0040 + padding : 1; // 0x0080 + padding : 1; // 0x0100 + ACC_INTERFACE : 1; // 0x0200 + ACC_ABSTRACT : 1; // 0x0400 + padding : 1; // 0x0800 + ACC_SYNTHETIC : 1; // 0x1000 + ACC_ANNOTATION : 1; // 0x2000 + ACC_ENUM : 1; // 0x4000 + padding : 1; // 0x8000 +}; + +struct attribute_info { + u2 attribute_name_info; + + u4 attribute_length; + + u1 info[attribute_length]; +}; + +struct field_info { + access_flags_field access_flags; + u2 name_index; + u2 descriptor_index; + + u2 attribute_count; + attribute_info attributes[attribute_count]; +}; + +struct method_info { + access_flags_method access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; +}; + +struct ClassFile { + u4 magic; + + u2 minor_version; + major_version major_version; + + u2 constant_pool_count; + cp_info constant_pool[constant_pool_count - 1]; + + access_flags_class access_flags; + u2 this_class; + u2 super_class; + + u2 interfaces_count; + u2 interfaces[interfaces_count]; + + u2 fields_count; + field_info fields[fields_count]; + + u2 methods_count; + method_info methods[methods_count]; + + u2 attribute_count; + attribute_info attributes[attribute_count]; +}; + +ClassFile class_file @ 0x00; + +fn main() { + + std::assert(class_file.magic == 0xCAFEBABE, "File is not a valid Java Class file! Invalid header magic"); + + + std::print("Fields:"); + for (le u16 i = 0, i < class_file.fields_count, i = i + 1) { + str method_string = " "; + + if (class_file.fields[i].access_flags.ACC_PUBLIC) + method_string = method_string + "public "; + if (class_file.fields[i].access_flags.ACC_PRIVATE) + method_string = method_string + "private "; + if (class_file.fields[i].access_flags.ACC_PROTECTED) + method_string = method_string + "protected "; + if (class_file.fields[i].access_flags.ACC_STATIC) + method_string = method_string + "static "; + if (class_file.fields[i].access_flags.ACC_FINAL) + method_string = method_string + "final "; + if (class_file.fields[i].access_flags.ACC_VOLATILE) + method_string = method_string + "volatile "; + if (class_file.fields[i].access_flags.ACC_NATIVE) + method_string = method_string + "native "; + if (class_file.fields[i].access_flags.ACC_TRANSIENT) + method_string = method_string + "transient "; + if (class_file.fields[i].access_flags.ACC_ENUM) + method_string = method_string + "enum "; + + method_string = method_string + class_file.constant_pool[class_file.fields[i].name_index - 1].info.bytes; + method_string = method_string + " [ " + class_file.constant_pool[class_file.fields[i].descriptor_index - 1].info.bytes + " ]"; + + std::print("{}", method_string); + } + + std::print("Methods:"); + for (le u16 i = 0, i < class_file.methods_count, i = i + 1) { + str method_string = " "; + + if (class_file.methods[i].access_flags.ACC_PUBLIC) + method_string = method_string + "public "; + if (class_file.methods[i].access_flags.ACC_PRIVATE) + method_string = method_string + "private "; + if (class_file.methods[i].access_flags.ACC_PROTECTED) + method_string = method_string + "protected "; + if (class_file.methods[i].access_flags.ACC_STATIC) + method_string = method_string + "static "; + if (class_file.methods[i].access_flags.ACC_FINAL) + method_string = method_string + "final "; + if (class_file.methods[i].access_flags.ACC_SYNCHRONIZED) + method_string = method_string + "synchronized "; + if (class_file.methods[i].access_flags.ACC_NATIVE) + method_string = method_string + "native "; + if (class_file.methods[i].access_flags.ACC_ABSTRACT) + method_string = method_string + "abstract "; + if (class_file.methods[i].access_flags.ACC_STRICT) + method_string = method_string + "strictfp "; + + method_string = method_string + class_file.constant_pool[class_file.methods[i].name_index - 1].info.bytes; + method_string = method_string + " [ " + class_file.constant_pool[class_file.methods[i].descriptor_index - 1].info.bytes + " ]"; + + std::print("{}", method_string); + } + + std::print("Class Attributes:"); + for (le u16 i = 0, i < class_file.attribute_count, i = i + 1) { + std::print(" {}", class_file.constant_pool[class_file.attributes[i].attribute_name_info - 1].info.bytes); + } +}; \ No newline at end of file