class Android::Dex

parsed dex object @see source.android.com/devices/tech/dalvik/dex-format.html @attr_reader strings [Array<String>] strings in dex file.

Constants

TYPE_DESCRIPTOR

@private

Attributes

classes[R]

@return [Array<Dex::ClassInfo>] array of class information

data[R]

@return [String] dex binary data

field_ids[R]
h[R]

@return [Dex::Header] dex header information

header[R]

@return [Dex::Header] dex header information

method_ids[R]
proto_ids[R]

Public Class Methods

new(data) click to toggle source

@param [String] data dex binary data

# File lib/android/dex.rb, line 22
def initialize(data)
  @data = data
  @data.force_encoding(Encoding::ASCII_8BIT)
  @classes = []
  parse()
end
sleb128(data, offset=0) click to toggle source

parse sleb128(signed integer) data @param [String] data target byte data @param [Integer] offset @return [Integer, Integer] parsed value and parsed byte length

# File lib/android/dex/utils.rb, line 32
def sleb128(data, offset=0)
  result  = 0
  shift = 0
  d = data[offset...data.size]
  (0..4).each do |i|
    byte  = d.getbyte(i)
    result  |=((byte & 0x7F) << shift)
    return (0 == (byte & 0x40) ? result : result - (1 << (shift+7))), i+1 if ((byte & 0x80) == 0)
    shift += 7
  end
end
uleb128(data, offset=0) click to toggle source

parse uleb128(unsigned integer) data @param [String] data target byte data @param [Integer] offset @return [Integer, Integer] parsed value and parsed byte length @see en.wikipedia.org/wiki/LEB128

# File lib/android/dex/utils.rb, line 9
def uleb128(data, offset=0)
  result = 0
  shift = 0
  d = data[offset...data.size]
  (0..4).each do |i|
    byte = d.getbyte(i)
    result |= ((byte & 0x7f) << shift)
    return result, i+1 if ((byte & 0x80) == 0)
    shift += 7
  end
end
uleb128p1(data, offset=0) click to toggle source

parse uleb128 + 1 data @param [String] data target byte data @param [Integer] offset @return [Integer, Integer] parsed value and parsed byte length

# File lib/android/dex/utils.rb, line 24
def uleb128p1(data, offset=0)
  ret, len = self.uleb128(data, offset)
  return (ret - 1), len
end

Public Instance Methods

inspect() click to toggle source
# File lib/android/dex.rb, line 33
def inspect
  "<Android::Dex @classes => #{@classes.size}, datasize => #{@data.size}>"
end
strings() click to toggle source
# File lib/android/dex.rb, line 29
def strings
  @strings ||= @string_data_items.map{|item| item.to_s }
end
type_resolve(typeid) click to toggle source
# File lib/android/dex.rb, line 52
def type_resolve(typeid)
  type = strings[@type_ids[typeid]]
  if type.start_with? '['
    type = type[1..type.size]
    return TYPE_DESCRIPTOR.fetch(type, type) + "[]" # TODO: recursive
  else
    return TYPE_DESCRIPTOR.fetch(type, type)
  end
end

Private Instance Methods

ids_list_array(cls, offset, size) click to toggle source
# File lib/android/dex.rb, line 85
def ids_list_array(cls, offset, size)
  ret_array = []
  size.times { |i| ret_array << cls.new(@data, offset + cls.size * i) }
  ret_array
end
parse() click to toggle source
# File lib/android/dex.rb, line 64
def parse
  @header = DexObject::Header.new(@data)
  @map_list = DexObject::MapList.new(@data, h[:map_off])

  # parse strings
  @string_ids = DexObject::StringIdItem.new(@data, h[:string_ids_off], h[:string_ids_size])
  @string_data_items = []
  @string_ids[:string_data_off].each { |off| @string_data_items << DexObject::StringDataItem.new(@data, off) }

  @type_ids = DexObject::TypeIdItem.new(@data, h[:type_ids_off], h[:type_ids_size])
  @proto_ids = ids_list_array(DexObject::ProtoIdItem, h[:proto_ids_off], h[:proto_ids_size])
  @field_ids = ids_list_array(DexObject::FieldIdItem, h[:field_ids_off], h[:field_ids_size])
  @method_ids = ids_list_array(DexObject::MethodIdItem, h[:method_ids_off], h[:method_ids_size])
  @class_defs = ids_list_array(DexObject::ClassDefItem, h[:class_defs_off], h[:class_defs_size])

  @classes = []
  @class_defs.each do |cls_def|
    @classes << ClassInfo.new(cls_def, self)
  end
end