class Java::Dissassembler
Constants
- CONSTANT_CLASS
- CONSTANT_DOUBLE
- CONSTANT_FIELDREF
- CONSTANT_FLOAT
- CONSTANT_INTEGER
- CONSTANT_INTERFACEMETHODREF
- CONSTANT_INVOKEDYNAMIC
- CONSTANT_LONG
- CONSTANT_METHODHANDLE
- CONSTANT_METHODREF
- CONSTANT_METHODTYPE
- CONSTANT_NAMEANDTYPE
- CONSTANT_STRING
- CONSTANT_UTF8
- MAGIC
Public Class Methods
dissassemble(bytes)
click to toggle source
# File lib/java_dissassembler.rb, line 28 def dissassemble(bytes) if bytes.is_a?(Array) do_dissassemble(bytes) elsif bytes.is_a?(String) do_dissassemble(bytes.each_byte.to_a) else raise "Expected `bytes' to be Array of bytes or String of bytes" end end
dissassemble_file(path)
click to toggle source
# File lib/java_dissassembler.rb, line 38 def dissassemble_file(path) File.open(path) do |file| dissassemble(file.read) end end
Private Class Methods
constant_pool_info_size(bytes)
click to toggle source
# File lib/java_dissassembler.rb, line 142 def constant_pool_info_size(bytes) constant_pool_tag = bytes[0] case constant_pool_tag when CONSTANT_UTF8 tag_content_size = bytes[1..2].u2 val = bytes[3..tag_content_size + 2].modified_utf8_to_s return 3 + tag_content_size, val when CONSTANT_INTEGER val = bytes[1..4].u4 return 5, val when CONSTANT_FLOAT val = to_float(bytes[1..4].u4) return 5, val when CONSTANT_LONG high_bytes = bytes[1..4].u4 low_bytes = bytes[5..8].u4 return 9, (high_bytes << 32) + low_bytes, constant_pool_tag when CONSTANT_DOUBLE high_bytes = bytes[1..4].u4 low_bytes = bytes[5..8].u4 return 9, to_double((high_bytes << 32) + low_bytes), constant_pool_tag when CONSTANT_STRING, CONSTANT_CLASS val = bytes[1..2].u2 return 3, val when CONSTANT_FIELDREF, CONSTANT_METHODREF, CONSTANT_INTERFACEMETHODREF klass_index = bytes[1..2].u2 name_and_type_index = bytes[3..4].u2 return 5, [klass_index, name_and_type_index] when CONSTANT_NAMEANDTYPE name_index = bytes[1..2].u2 descriptor_index = bytes[3..4].u2 return 5, [name_index, descriptor_index] when CONSTANT_METHODHANDLE reference_kind = bytes[1] reference_index = bytes[2..3].u2 return 4, [reference_kind, reference_index] when CONSTANT_METHODTYPE return 3, bytes[1..2].u2 when CONSTANT_INVOKEDYNAMIC bootstrap_method_attr_index = bytes[1..2].u2 name_and_type_index = bytes[3..4].u2 return 5, [bootstrap_method_attr_index, name_and_type_index] else raise "Unknown Constant Pool Tag: 0x#{constant_pool_tag.to_s(16)}" end end
do_dissassemble(bytes)
click to toggle source
# File lib/java_dissassembler.rb, line 45 def do_dissassemble(bytes) raise "Missing magic number 0xCAFEBABE. Not a .class file" unless bytes[0..3] == MAGIC minor = bytes[4..5].u2 major = bytes[6..7].u2 offset = 8 # Constant Pool constant_pool = {} constant_pool_size = bytes[offset..offset + 1].u2 - 1 offset += 2 i = 0 while i < constant_pool_size consumed, val, tag = constant_pool_info_size(bytes[offset..-1]) i += 1 if !tag.nil? && ((tag == 5) || (tag == 6)) # Floats and Doubles take up two constant pool entries :/ constant_pool[i + 1] = val unless val.nil? offset += consumed i += 1 end # Class Info: 3 x u2 (access_flags, this_klass, super_klass) access_flags = bytes[offset..offset + 1].u2 this_klass = constant_pool[constant_pool[bytes[offset + 2..offset + 3].u2]] super_klass = constant_pool[constant_pool[bytes[offset + 4..offset + 5].u2]] offset += 6 # Interfaces interfaces = Array.new interfaces_count = bytes[offset..offset + 1].u2 offset += 2 interfaces_count.times do interface_index = bytes[offset..offset + 1].u2 interfaces << constant_pool[interface_index] offset += 2 end # Fields fields = Array.new fields_count = bytes[offset..offset + 1].u2 offset += 2 fields_count.times do flags = bytes[offset..offset + 1].u2 name = bytes[offset + 2..offset + 3].u2 sig = bytes[offset + 4..offset + 5].u2 offset += 6 # Skip the field header consumed, annotations = parse_attributes(bytes[offset..-1], constant_pool) fields << Java::Field.new(flags, constant_pool[name], constant_pool[sig], annotations.compact) offset += consumed end # Parse methods methods = Array.new methods_count = bytes[offset..offset + 1].u2 offset += 2 methods_count.times do flags = bytes[offset..offset + 1].u2 name = bytes[offset + 2..offset + 3].u2 sig = bytes[offset + 4..offset + 5].u2 offset += 6 consumed, annotations = parse_attributes(bytes[offset..-1], constant_pool) methods << Java::Method.new(flags, constant_pool[name], constant_pool[sig], annotations.compact) offset += consumed end # Parse class attributes _, annotations = parse_attributes(bytes[offset..-1], constant_pool) Java::Class.new(major, minor, access_flags, this_klass, super_klass, interfaces, fields, methods, annotations) end
parse_annotation(bytes, constant_pool)
click to toggle source
# File lib/java_dissassembler.rb, line 188 def parse_annotation(bytes, constant_pool) annotations = {} num_annotations = bytes[0..1].u2 offset = 2 num_annotations.times do |_annotation| annotation_name_index = bytes[offset..offset + 1].u2 num_value_pairs = bytes[offset + 2..offset + 3].u2 offset += 4 key_values = annotations[ constant_pool[annotation_name_index] ] = [] num_value_pairs.times do |_value_pairs| name = bytes[offset..offset + 1].u2 # TODO: Handle 4.7.16.1. The element_value structure value = bytes[offset + 3..offset + 4].u2 key_values << constant_pool[name] key_values << constant_pool[value] end end return nil if annotations.empty? annotations end
parse_attributes(bytes, constant_pool)
click to toggle source
# File lib/java_dissassembler.rb, line 209 def parse_attributes(bytes, constant_pool) annotations = [] attr_count = bytes[0..1].u2 offset = 2 # Consume attr_count attr_count.times do |_attr| attr_name_index = bytes[offset..offset + 1].u2 attr_size = bytes[offset + 2..offset + 5].u4 offset += 6 if (constant_pool[attr_name_index] == "RuntimeInvisibleAnnotations") && (attr_size > 0) annotations << parse_annotation(bytes[offset..offset + attr_size], constant_pool) end offset += attr_size end [offset, annotations] end
to_double(fixnum)
click to toggle source
# File lib/java_dissassembler.rb, line 116 def to_double(fixnum) case fixnum when 0x7ff0000000000000 then Float::INFINITY when 0xfff0000000000000 then -Float::INFINITY #TODO: NaN else s = (fixnum >> 63) == 0 ? 1 : -1 e = (fixnum >> 52) & 0x7ff m = e == 0 ? (fixnum & 0xfffffffffffff) << 1 : (fixnum & 0xfffffffffffff) | 0x10000000000000 (s * m * 2**(e - 1075)).to_f end end
to_float(fixnum)
click to toggle source
# File lib/java_dissassembler.rb, line 129 def to_float(fixnum) case fixnum when 0x7f800000 then Float::INFINITY when 0xff800000 then Float::INFINITY #TODO: NaN else s = ((fixnum >> 31) == 0) ? 1 : -1 e = ((fixnum >> 23) & 0xff) m = (e == 0) ? (fixnum & 0x7fffff) << 1 : (fixnum & 0x7fffff) | 0x800000; (s * m * 2**(e - 150)).to_f end end