mirror of https://github.com/x64dbg/btparser
254 lines
8.0 KiB
Plaintext
254 lines
8.0 KiB
Plaintext
//-------------------------------------------------------------------------
|
|
//--- 010 Editor v2.1 Binary Template
|
|
//
|
|
// File: CLASSTemplate.bt
|
|
// Author: Kevin O. Grover <kevin@kevingrover.net>
|
|
// Purpose: A template for parsing Java Class (JVM) Files
|
|
// Version: 1.1 2014-08-13
|
|
// History:
|
|
// 2007-02-26 kog Original Version
|
|
// 2014-08-13 kog Updated for Java 7/8 Version number (and future)
|
|
//
|
|
// This template was written to the "The Java Virtual Machine
|
|
// Specification", Second Edition, by Tim Lindholm, Frank Yellin.
|
|
// It was later updated to include the provisio in that spec (and future
|
|
// specs).
|
|
//
|
|
// The details used to write this Template came mainly from Chapter 4:
|
|
// "The <code>class</code> File Format".
|
|
//
|
|
// You can get the document from the Oracle Java Pages or Wikipedia:
|
|
// http://docs.oracle.com/javase/specs/
|
|
// http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf
|
|
// http://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf
|
|
// http://en.wikipedia.org/wiki/Class_file
|
|
//-------------------------------------------------------------------------
|
|
|
|
BigEndian();
|
|
|
|
// Types used in the JVM Spec.
|
|
// (To make this code as close to the text in the spec as possible.)
|
|
typedef uint32 u4;
|
|
typedef uint16 u2;
|
|
typedef ubyte u1;
|
|
|
|
typedef enum <u2> eACCESS_FLAGS {
|
|
ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package.
|
|
ACC_PRIVATE = 0x0002, // Declared private; usable only within the defining class.
|
|
ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses.
|
|
ACC_STATIC = 0x0008, // Declared static.
|
|
ACC_FINAL = 0x0010, // Declared final; no subclasses allowed.
|
|
ACC_SUPER = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction.
|
|
ACC_VOLATILE = 0x0040, // Declared volatile; cannot be cached.
|
|
ACC_TRANSIENT = 0x0080, // Declared transient; not written or read by a persistent object manager.
|
|
ACC_NATIVE = 0x0100, // Declared native; implemented in a language other than Java.
|
|
ACC_INTERFACE = 0x0200, // Is an interface, not a class.
|
|
ACC_ABSTRACT = 0x0400, // Declared abstract; may not be instantiated.
|
|
ACC_STRICT = 0x0800 // Declared strictfp; floating-point mode is FP-strict
|
|
} AF <read=read_AF>;
|
|
|
|
string read_AF (local AF &af) {
|
|
local string s = "";
|
|
local int commaNeeded = 0;
|
|
local AF i = 1;
|
|
|
|
SPrintf (s, "%d: ", af);
|
|
|
|
// Iterate over all possible values the flags
|
|
// if the given bit is set, add it's text representation to the
|
|
// return string.
|
|
// NOTE: There's probably a better way to do this. (More portable?)
|
|
while (i < ACC_STRICT) {
|
|
if (af && i) {
|
|
if (commaNeeded) {
|
|
s += ", ";
|
|
}
|
|
s += EnumToString(i);
|
|
commaNeeded = 1;
|
|
}
|
|
i = i << 1;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
// Constants for cp_info.tag ...
|
|
typedef enum <u1> eCP_CONST {
|
|
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,
|
|
} CP_CONST;
|
|
|
|
// Constant Pool Table Structure
|
|
// NOTE: These are NOT constant sized items. Although referenced
|
|
// like an array in the main structure, you can not use position
|
|
// to directly infer a byte offset because you do not know the
|
|
// sizes of the items preceeding it.
|
|
typedef struct {
|
|
CP_CONST tag;
|
|
switch(tag)
|
|
{
|
|
case CONSTANT_Class:
|
|
u2 name_index;
|
|
break;
|
|
case CONSTANT_Methodref:
|
|
case CONSTANT_Fieldref:
|
|
case CONSTANT_InterfaceMethodref:
|
|
u2 class_index;
|
|
u2 name_and_type_index;
|
|
break;
|
|
case CONSTANT_Utf8:
|
|
u2 length;
|
|
char bytes[length];
|
|
break;
|
|
case CONSTANT_Integer:
|
|
case CONSTANT_Float:
|
|
u4 bytes;
|
|
break;
|
|
case CONSTANT_Long:
|
|
case CONSTANT_Double:
|
|
u4 high_bytes;
|
|
u4 low_bytes;
|
|
break;
|
|
case CONSTANT_String:
|
|
u2 string_index;
|
|
break;
|
|
case CONSTANT_NameAndType:
|
|
u2 name_index;
|
|
u2 descriptor_index;
|
|
break;
|
|
default:
|
|
local string s;
|
|
SPrintf(s, "Unknown 'constant_pool' tag: %d", tag);
|
|
Warning(s);
|
|
return -3;
|
|
}
|
|
} cp_info <read=read_cp_info, optimize=false>;
|
|
|
|
/**
|
|
* Reader for 'cp_info'
|
|
* @param cp_info Constant Pool info structure
|
|
*/
|
|
string read_cp_info (local cp_info &i)
|
|
{
|
|
local string s = "";
|
|
s = EnumToString(i.tag);
|
|
if (i.tag == CONSTANT_Utf8) {
|
|
s += ": " + i.bytes;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
typedef struct {
|
|
u2 attribute_name_index;
|
|
u4 attribute_length;
|
|
u1 info[attribute_length];
|
|
} attribute_info <optimize=false>;
|
|
|
|
typedef struct {
|
|
AF access_flags;
|
|
u2 name_index;
|
|
u2 descriptor_index;
|
|
u2 attributes_count;
|
|
attribute_info attributes[attributes_count];
|
|
} field_info <optimize=false>;
|
|
|
|
typedef struct {
|
|
AF access_flags;
|
|
u2 name_index;
|
|
u2 descriptor_index;
|
|
u2 attributes_count;
|
|
attribute_info attributes[attributes_count];
|
|
} method_info <optimize=false>;
|
|
|
|
// MAIN Structure
|
|
|
|
typedef struct {
|
|
u4 magic <format=hex>;
|
|
if (magic != 0xCAFEBABE) { // Check that 'magic' is correct
|
|
Warning("Incorrect Magic Number. This is not a JVM Class. Template Terminated.");
|
|
return -1;
|
|
}
|
|
u2 minor_version;
|
|
u2 major_version;
|
|
u2 constant_pool_count;
|
|
cp_info constant_pool[constant_pool_count-1];
|
|
AF access_flags;
|
|
u2 this_class; // Reference into constant_pool table
|
|
if (this_class < 1 || this_class > constant_pool_count-1) {
|
|
local string s;
|
|
SPrintf(s,"Bad 'this_class' reference (%d). It should be in the range [1..%d]", this_class, constant_pool_count-1);
|
|
Warning(s);
|
|
return -2;
|
|
}
|
|
u2 super_class; // Reference into constant_pool table
|
|
if (super_class < 1 || super_class > constant_pool_count-1) {
|
|
local string s;
|
|
SPrintf(s,"Bad 'super_class' reference (%d). It should be in the range [1..%d]", super_class, constant_pool_count-1);
|
|
Warning(s);
|
|
return -2;
|
|
}
|
|
u2 interfaces_count;
|
|
u2 interfaces[interfaces_count];
|
|
u2 fields_count;
|
|
field_info fields[fields_count];
|
|
u2 methods_count;
|
|
method_info methods[methods_count];
|
|
u2 attributes_count;
|
|
attribute_info attributes[attributes_count];
|
|
} JVMClass <read=read_JVMClass, optimize=false>;
|
|
|
|
/**
|
|
* Reader for 'JVMClass'
|
|
* Returns the JVM Version: major.minor and the Java version (if it can
|
|
* calculate it from the JVM Version.
|
|
* @param j JVMClass The JVM Class Structure
|
|
* @return string The version information
|
|
*/
|
|
string read_JVMClass (local JVMClass &j)
|
|
{
|
|
// JVM Version (as stored in the class file)
|
|
local string s;
|
|
SPrintf (s, "JVM class v%d.%d", j.major_version, j.minor_version);
|
|
|
|
// Java Runtime Version. From the JVM Spec for class files
|
|
local int major = 1;
|
|
local int minor = 0;
|
|
|
|
if (j.major_version == 45) {
|
|
if (j.minor_version >= 3) minor = 1;
|
|
} else {
|
|
if (j.major_version >= 46) {
|
|
minor = j.major_version - 44;
|
|
} else {
|
|
// Unknown: it's either newer or older than expected
|
|
major = 0;
|
|
minor = 0;
|
|
Warning("Unexpected JVM major version number.");
|
|
}
|
|
}
|
|
|
|
if (major || minor) {
|
|
local string jre_v;
|
|
SPrintf(jre_v, " (Java %d.%d)", major, minor);
|
|
s += jre_v;
|
|
} else {
|
|
s += " (Unknown Java Version)";
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
// *****************************************
|
|
// MAIN - Allocate data here...
|
|
// *****************************************
|
|
|
|
struct JVMClass jc;
|